LCOV - code coverage report
Current view: top level - responder/sudo - sudosrv_query.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 197 0.0 %
Date: 2015-10-19 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             : 
       5             :     Copyright (C) 2011 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <string.h>
      22             : #include <stdint.h>
      23             : #include <errno.h>
      24             : #include <talloc.h>
      25             : #include <tevent.h>
      26             : 
      27             : #include "util/util.h"
      28             : #include "responder/sudo/sudosrv_private.h"
      29             : 
      30           0 : static int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
      31             :                                           const char *str,
      32             :                                           size_t str_len,
      33             :                                           uint8_t **_response_body,
      34             :                                           size_t *_response_len)
      35             : {
      36           0 :     size_t response_len = *_response_len;
      37           0 :     uint8_t *response_body = *_response_body;
      38             : 
      39           0 :     response_body = talloc_realloc(mem_ctx, response_body, uint8_t,
      40             :                                    response_len + (str_len * sizeof(char)));
      41           0 :     if (response_body == NULL) {
      42           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc() failed\n");
      43           0 :         return ENOMEM;
      44             :     }
      45           0 :     memcpy(response_body + response_len, str, str_len);
      46           0 :     response_len += str_len;
      47             : 
      48           0 :     *_response_body = response_body;
      49           0 :     *_response_len = response_len;
      50             : 
      51           0 :     return EOK;
      52             : }
      53             : 
      54           0 : static int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
      55             :                                           uint32_t number,
      56             :                                           uint8_t **_response_body,
      57             :                                           size_t *_response_len)
      58             : {
      59           0 :     size_t response_len = *_response_len;
      60           0 :     uint8_t *response_body = *_response_body;
      61             : 
      62           0 :     response_body = talloc_realloc(mem_ctx, response_body, uint8_t,
      63             :                                    response_len + sizeof(uint32_t));
      64           0 :     if (response_body == NULL) {
      65           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc() failed\n");
      66           0 :         return ENOMEM;
      67             :     }
      68           0 :     SAFEALIGN_SET_UINT32(response_body + response_len, number, &response_len);
      69             : 
      70           0 :     *_response_body = response_body;
      71           0 :     *_response_len = response_len;
      72             : 
      73           0 :     return EOK;
      74             : }
      75             : 
      76           0 : static int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
      77             :                                         const char *name,
      78             :                                         unsigned int values_num,
      79             :                                         struct ldb_val *values,
      80             :                                         uint8_t **_response_body,
      81             :                                         size_t *_response_len)
      82             : {
      83           0 :     uint8_t *response_body = *_response_body;
      84           0 :     size_t response_len = *_response_len;
      85           0 :     TALLOC_CTX *tmp_ctx = NULL;
      86           0 :     int i = 0;
      87           0 :     int ret = EOK;
      88             : 
      89           0 :     tmp_ctx = talloc_new(NULL);
      90           0 :     if (tmp_ctx == NULL) {
      91           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
      92           0 :         return ENOMEM;
      93             :     }
      94             : 
      95             :     /* attr name */
      96           0 :     ret = sudosrv_response_append_string(tmp_ctx, name, strlen(name) + 1,
      97             :                                          &response_body, &response_len);
      98           0 :     if (ret != EOK) {
      99           0 :         goto done;
     100             :     }
     101             : 
     102             :     /* values count */
     103           0 :     ret = sudosrv_response_append_uint32(tmp_ctx, values_num,
     104             :                                          &response_body, &response_len);
     105           0 :     if (ret != EOK) {
     106           0 :         goto done;
     107             :     }
     108             : 
     109             :     /* values */
     110           0 :     for (i = 0; i < values_num; i++) {
     111           0 :         if (strlen((char*)(values[i].data)) != values[i].length) {
     112           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "value is not a string\n");
     113           0 :             ret = EINVAL;
     114           0 :             goto done;
     115             :         }
     116             : 
     117           0 :         ret = sudosrv_response_append_string(tmp_ctx,
     118           0 :                                              (const char*)values[i].data,
     119           0 :                                              values[i].length + 1,
     120             :                                              &response_body, &response_len);
     121           0 :         if (ret != EOK) {
     122           0 :             goto done;
     123             :         }
     124             :     }
     125             : 
     126           0 :     *_response_body = talloc_steal(mem_ctx, response_body);
     127           0 :     *_response_len = response_len;
     128             : 
     129           0 :     ret = EOK;
     130             : 
     131             : done:
     132           0 :     talloc_free(tmp_ctx);
     133           0 :     return ret;
     134             : }
     135             : 
     136           0 : static int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
     137             :                                         int attrs_num,
     138             :                                         struct ldb_message_element *attrs,
     139             :                                         uint8_t **_response_body,
     140             :                                         size_t *_response_len)
     141             : {
     142           0 :     uint8_t *response_body = *_response_body;
     143           0 :     size_t response_len = *_response_len;
     144           0 :     TALLOC_CTX *tmp_ctx = NULL;
     145           0 :     int i = 0;
     146           0 :     int ret = EOK;
     147             : 
     148           0 :     tmp_ctx = talloc_new(NULL);
     149           0 :     if (tmp_ctx == NULL) {
     150           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     151           0 :         return ENOMEM;
     152             :     }
     153             : 
     154             :     /* attrs count */
     155           0 :     ret = sudosrv_response_append_uint32(tmp_ctx, attrs_num,
     156             :                                          &response_body, &response_len);
     157           0 :     if (ret != EOK) {
     158           0 :         goto done;
     159             :     }
     160             : 
     161             :     /* attrs */
     162           0 :     for (i = 0; i < attrs_num; i++) {
     163           0 :         ret = sudosrv_response_append_attr(tmp_ctx, attrs[i].name,
     164           0 :                                            attrs[i].num_values, attrs[i].values,
     165             :                                            &response_body, &response_len);
     166           0 :         if (ret != EOK) {
     167           0 :             goto done;
     168             :         }
     169             :     }
     170             : 
     171           0 :     *_response_body = talloc_steal(mem_ctx, response_body);
     172           0 :     *_response_len = response_len;
     173             : 
     174           0 :     ret = EOK;
     175             : 
     176             : done:
     177           0 :     talloc_free(tmp_ctx);
     178           0 :     return ret;
     179             : }
     180             : 
     181             : /*
     182             :  * Response format:
     183             :  * <error_code(uint32_t)><domain(char*)>\0<num_entries(uint32_t)><rule1><rule2>...
     184             :  * <ruleN> = <num_attrs(uint32_t)><attr1><attr2>...
     185             :  * <attrN>  = <name(char*)>\0<num_values(uint32_t)><value1(char*)>\0<value2(char*)>\0...
     186             :  *
     187             :  * if <error_code> is not SSS_SUDO_ERROR_OK, the rest of the data is skipped.
     188             :  */
     189           0 : errno_t sudosrv_build_response(TALLOC_CTX *mem_ctx,
     190             :                                uint32_t error,
     191             :                                uint32_t rules_num,
     192             :                                struct sysdb_attrs **rules,
     193             :                                uint8_t **_response_body,
     194             :                                size_t *_response_len)
     195             : {
     196           0 :     uint8_t *response_body = NULL;
     197           0 :     size_t response_len = 0;
     198           0 :     TALLOC_CTX *tmp_ctx = NULL;
     199           0 :     uint32_t i = 0;
     200           0 :     errno_t ret = EOK;
     201             : 
     202           0 :     tmp_ctx = talloc_new(NULL);
     203           0 :     if (tmp_ctx == NULL) {
     204           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     205           0 :         return ENOMEM;
     206             :     }
     207             : 
     208             :     /* error code */
     209           0 :     ret = sudosrv_response_append_uint32(tmp_ctx, error,
     210             :                                          &response_body, &response_len);
     211           0 :     if (ret != EOK) {
     212           0 :         goto fail;
     213             :     }
     214             : 
     215           0 :     if (error != SSS_SUDO_ERROR_OK) {
     216           0 :         goto done;
     217             :     }
     218             : 
     219             :     /* domain name - deprecated
     220             :      * TODO: when possible change the protocol */
     221           0 :     ret = sudosrv_response_append_string(tmp_ctx, "\0", 1,
     222             :                                          &response_body, &response_len);
     223           0 :     if (ret != EOK) {
     224           0 :         goto fail;
     225             :     }
     226             : 
     227             :     /* rules count */
     228           0 :     ret = sudosrv_response_append_uint32(tmp_ctx, rules_num,
     229             :                                          &response_body, &response_len);
     230           0 :     if (ret != EOK) {
     231           0 :         goto fail;
     232             :     }
     233             : 
     234             :     /* rules */
     235           0 :     for (i = 0; i < rules_num; i++) {
     236           0 :         ret = sudosrv_response_append_rule(tmp_ctx, rules[i]->num, rules[i]->a,
     237             :                                            &response_body, &response_len);
     238           0 :         if (ret != EOK) {
     239           0 :             goto fail;
     240             :         }
     241             :     }
     242             : 
     243             : done:
     244           0 :     *_response_body = talloc_steal(mem_ctx, response_body);
     245           0 :     *_response_len = response_len;
     246             : 
     247           0 :     ret = EOK;
     248             : 
     249             : fail:
     250           0 :     talloc_free(tmp_ctx);
     251           0 :     return ret;
     252             : }
     253             : 
     254             : struct sudosrv_parse_query_state {
     255             :     struct resp_ctx *rctx;
     256             :     uid_t uid;
     257             :     char *rawname;
     258             : };
     259             : 
     260             : static void sudosrv_parse_query_done(struct tevent_req *subreq);
     261             : 
     262           0 : struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx,
     263             :                                             struct resp_ctx *rctx,
     264             :                                             uint8_t *query_body,
     265             :                                             size_t query_len)
     266             : {
     267           0 :     struct tevent_req *req = NULL;
     268           0 :     struct tevent_req *subreq = NULL;
     269           0 :     struct sudosrv_parse_query_state *state = NULL;
     270           0 :     size_t offset = 0;
     271           0 :     size_t rawname_len = 0;
     272           0 :     char *rawname = NULL;
     273           0 :     char *domainname = NULL;
     274             :     errno_t ret;
     275             : 
     276             :     /* create request */
     277           0 :     req = tevent_req_create(mem_ctx, &state,
     278             :                             struct sudosrv_parse_query_state);
     279           0 :     if (req == NULL) {
     280           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "tevent_req_create() failed\n");
     281           0 :         return NULL;
     282             :     }
     283             : 
     284           0 :     state->rctx = rctx;
     285             : 
     286             :     /* uid */
     287             : 
     288           0 :     if (query_len < sizeof(uid_t)) {
     289           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Query is too small\n");
     290           0 :         ret = EINVAL;
     291           0 :         goto done;
     292             :     }
     293           0 :     safealign_memcpy(&state->uid, query_body, sizeof(uid_t), &offset);
     294             : 
     295             :     /* username[@domain] */
     296             : 
     297           0 :     rawname = (char*)(query_body + offset);
     298           0 :     rawname_len = query_len - offset; /* strlen + zero */
     299             : 
     300           0 :     if (rawname[rawname_len - 1] != '\0') {
     301           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Username is not zero terminated\n");
     302           0 :         ret = EINVAL;
     303           0 :         goto done;
     304             :     }
     305             : 
     306           0 :     if (rawname_len < 2) { /* at least one character and zero */
     307           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Query does not contain username\n");
     308           0 :         ret = EINVAL;
     309           0 :         goto done;
     310             :     }
     311             : 
     312           0 :     if (!sss_utf8_check((uint8_t*)rawname, rawname_len - 1)) {
     313           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Supplied data is not valid UTF-8 string\n");
     314           0 :         ret = EINVAL;
     315           0 :         goto done;
     316             :     }
     317             : 
     318             :     /* parse username */
     319             : 
     320           0 :     state->rawname = rawname;
     321           0 :     ret = sss_parse_name_for_domains(state, rctx->domains,
     322           0 :                                      rctx->default_domain, state->rawname,
     323             :                                      &domainname, NULL);
     324           0 :     if (ret == EAGAIN) {
     325           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Domain [%s] not found, "
     326             :               "sending subdomain request\n", domainname);
     327             : 
     328           0 :         subreq = sss_dp_get_domains_send(state, rctx, true, domainname);
     329           0 :         if (subreq == NULL) {
     330           0 :             ret = ENOMEM;
     331             :         } else {
     332           0 :             tevent_req_set_callback(subreq, sudosrv_parse_query_done, req);
     333           0 :             ret = EAGAIN;
     334             :         }
     335           0 :         goto done;
     336           0 :     } else if (ret != EOK) {
     337           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid name received [%s]\n", rawname);
     338           0 :         goto done;
     339             :     }
     340             : 
     341           0 :     ret = EOK;
     342             : 
     343             : done:
     344           0 :     if (ret != EAGAIN) {
     345           0 :         if (ret == EOK) {
     346           0 :             tevent_req_done(req);
     347             :         } else {
     348           0 :             tevent_req_error(req, ret);
     349             :         }
     350           0 :         tevent_req_post(req, rctx->ev);
     351             :     }
     352             : 
     353           0 :     return req;
     354             : }
     355             : 
     356           0 : static void sudosrv_parse_query_done(struct tevent_req *subreq)
     357             : {
     358           0 :     struct tevent_req *req = NULL;
     359             :     errno_t ret;
     360             : 
     361           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     362             : 
     363           0 :     ret = sss_dp_get_domains_recv(subreq);
     364           0 :     talloc_free(subreq);
     365           0 :     if (ret != EOK) {
     366           0 :         tevent_req_error(req, ret);
     367           0 :         return;
     368             :     }
     369             : 
     370           0 :     tevent_req_done(req);
     371             : }
     372             : 
     373           0 : errno_t sudosrv_parse_query_recv(TALLOC_CTX *mem_ctx,
     374             :                                  struct tevent_req *req,
     375             :                                  uid_t *_uid,
     376             :                                  char **_username,
     377             :                                  struct sss_domain_info **_domain)
     378             : {
     379           0 :     struct sudosrv_parse_query_state *state = NULL;
     380           0 :     struct sss_domain_info *domain = NULL;
     381           0 :     char *username = NULL;
     382           0 :     char *domainname = NULL;
     383             :     errno_t ret;
     384             : 
     385           0 :     state = tevent_req_data(req, struct sudosrv_parse_query_state);
     386             : 
     387           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     388             : 
     389           0 :     if (state->rawname == NULL) {
     390           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "No query specified?!\n");
     391           0 :         return EINVAL;
     392             :     }
     393             : 
     394             :     /* Try to parse username@domain again because if the first call
     395             :      * returned EAGAIN, then username is unset. If we get EAGAIN again,
     396             :      * we will not search for it again.
     397             :      */
     398           0 :     ret = sss_parse_name_for_domains(state, state->rctx->domains,
     399           0 :                                      state->rctx->default_domain,
     400           0 :                                      state->rawname,
     401             :                                      &domainname, &username);
     402           0 :     if (ret != EOK) {
     403           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Unable to parse domain [%d]: %s\n",
     404             :                                   ret, strerror(ret));
     405           0 :         return ret;
     406             :     }
     407             : 
     408           0 :     if (username == NULL) {
     409           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "No username specified!\n");
     410           0 :         return EINVAL;
     411             :     }
     412             : 
     413           0 :     if (domainname != NULL) {
     414             :         /* mem_ctx because it duplicates only subdomains not domains
     415             :          * so I cannot easily steal it */
     416           0 :         domain = responder_get_domain(state->rctx, domainname);
     417           0 :         if (domain == NULL) {
     418           0 :             DEBUG(SSSDBG_OP_FAILURE, "Corresponding domain [%s] has not been "
     419             :                                       "found\n", domainname);
     420           0 :             return ENOENT;
     421             :         }
     422             :     }
     423             : 
     424           0 :     *_uid = state->uid;
     425           0 :     *_username = talloc_steal(mem_ctx, username);
     426           0 :     *_domain = domain; /* do not steal on mem_ctx */
     427             : 
     428           0 :     return EOK;
     429             : }

Generated by: LCOV version 1.10