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

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    PAC Responder - utility finctions
       5             : 
       6             :    Copyright (C) Sumit Bose <sbose@redhat.com> 2012
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : #include <sys/types.h>
      22             : #include <stdbool.h>
      23             : #include <util/data_blob.h>
      24             : #include <gen_ndr/security.h>
      25             : 
      26             : #include "util/util.h"
      27             : #include "responder/pac/pacsrv.h"
      28             : 
      29           0 : errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx,
      30             :                           struct pac_ctx *pac_ctx,
      31             :                           struct PAC_LOGON_INFO *logon_info,
      32             :                           char **_user_sid_str,
      33             :                           char **_primary_group_sid_str,
      34             :                           hash_table_t **_sid_table)
      35             : {
      36             :     int ret;
      37             :     size_t s;
      38             :     struct netr_SamInfo3 *info3;
      39             :     struct sss_domain_info *user_dom;
      40             :     struct sss_domain_info *group_dom;
      41           0 :     char *sid_str = NULL;
      42           0 :     char *msid_str = NULL;
      43           0 :     char *user_dom_sid_str = NULL;
      44             :     size_t user_dom_sid_str_len;
      45             :     enum idmap_error_code err;
      46           0 :     hash_table_t *sid_table = NULL;
      47             :     hash_key_t key;
      48             :     hash_value_t value;
      49             :     char *rid_start;
      50           0 :     struct ldb_result *msg = NULL;
      51           0 :     char *user_sid_str = NULL;
      52           0 :     char *primary_group_sid_str = NULL;
      53             : 
      54           0 :     if (pac_ctx == NULL || logon_info == NULL || _sid_table == NULL) {
      55           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n");
      56           0 :         return EINVAL;
      57             :     }
      58             : 
      59           0 :     info3 = &logon_info->info3;
      60             : 
      61           0 :     ret = sss_hash_create(mem_ctx,
      62           0 :                           info3->sidcount + info3->base.groups.count + 2,
      63             :                           &sid_table);
      64           0 :     if (ret != EOK) {
      65           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
      66           0 :         goto done;
      67             :     }
      68             : 
      69           0 :     key.type = HASH_KEY_STRING;
      70           0 :     value.type = HASH_VALUE_ULONG;
      71             : 
      72           0 :     err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, info3->base.domain_sid,
      73             :                                    &user_dom_sid_str);
      74           0 :     if (err != IDMAP_SUCCESS) {
      75           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
      76           0 :         ret = EFAULT;
      77           0 :         goto done;
      78             :     }
      79             : 
      80           0 :     ret = responder_get_domain_by_id(pac_ctx->rctx, user_dom_sid_str,
      81             :                                      &user_dom);
      82           0 :     if (ret != EOK) {
      83           0 :         DEBUG(SSSDBG_OP_FAILURE, "responder_get_domain_by_id failed.\n");
      84           0 :         ret = EINVAL;
      85           0 :         goto done;
      86             :     }
      87             : 
      88           0 :     user_dom_sid_str_len = strlen(user_dom_sid_str);
      89           0 :     sid_str = talloc_zero_size(mem_ctx, user_dom_sid_str_len + 12);
      90           0 :     if (sid_str == NULL) {
      91           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
      92           0 :         ret = ENOMEM;
      93           0 :         goto done;
      94             :     }
      95           0 :     rid_start = sid_str + user_dom_sid_str_len;
      96             : 
      97           0 :     memcpy(sid_str, user_dom_sid_str, user_dom_sid_str_len);
      98             : 
      99           0 :     memset(rid_start, '\0', 12);
     100           0 :     ret = snprintf(rid_start, 12, "-%lu",
     101           0 :                                   (unsigned long) info3->base.rid);
     102           0 :     if (ret < 0 || ret > 12) {
     103           0 :         DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
     104           0 :         ret = EIO;
     105           0 :         goto done;
     106             :     }
     107             : 
     108           0 :     user_sid_str = talloc_strdup(mem_ctx, sid_str);
     109           0 :     if (user_sid_str == NULL) {
     110           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     111           0 :         ret = ENOMEM;
     112           0 :         goto done;
     113             :     }
     114             : 
     115           0 :     key.str = sid_str;
     116           0 :     value.ul = 0;
     117             : 
     118           0 :     ret = sysdb_search_object_by_sid(mem_ctx, user_dom, sid_str, NULL, &msg);
     119           0 :     if (ret == EOK && msg->count == 1) {
     120           0 :         value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_UIDNUM, 0);
     121             :     }
     122           0 :     talloc_zfree(msg);
     123             : 
     124           0 :     ret = hash_enter(sid_table, &key, &value);
     125           0 :     if (ret != HASH_SUCCESS) {
     126           0 :         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
     127             :                                   ret, hash_error_string(ret));
     128           0 :         ret = EIO;
     129           0 :         goto done;
     130             :     }
     131             : 
     132             : 
     133           0 :     memset(rid_start, '\0', 12);
     134           0 :     ret = snprintf(rid_start, 12, "-%lu",
     135           0 :                                   (unsigned long) info3->base.primary_gid);
     136           0 :     if (ret < 0 || ret > 12) {
     137           0 :         DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
     138           0 :         ret = EIO;
     139           0 :         goto done;
     140             :     }
     141             : 
     142           0 :     primary_group_sid_str = talloc_strdup(mem_ctx, sid_str);
     143           0 :     if (primary_group_sid_str == NULL) {
     144           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     145           0 :         ret = ENOMEM;
     146           0 :         goto done;
     147             :     }
     148             : 
     149           0 :     key.str = sid_str;
     150           0 :     value.ul = 0;
     151             : 
     152           0 :     ret = sysdb_search_object_by_sid(mem_ctx, user_dom, sid_str, NULL, &msg);
     153           0 :     if (ret == EOK && msg->count == 1) {
     154           0 :         value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_GIDNUM, 0);
     155             :     }
     156           0 :     talloc_zfree(msg);
     157             : 
     158           0 :     ret = hash_enter(sid_table, &key, &value);
     159           0 :     if (ret != HASH_SUCCESS) {
     160           0 :         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
     161             :                                   ret, hash_error_string(ret));
     162           0 :         ret = EIO;
     163           0 :         goto done;
     164             :     }
     165             : 
     166             : 
     167           0 :     for (s = 0; s < info3->base.groups.count; s++) {
     168           0 :         memset(rid_start, '\0', 12);
     169           0 :         ret = snprintf(rid_start, 12, "-%lu",
     170           0 :                                 (unsigned long) info3->base.groups.rids[s].rid);
     171           0 :         if (ret < 0 || ret > 12) {
     172           0 :             DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
     173           0 :             ret = EIO;
     174           0 :             goto done;
     175             :         }
     176             : 
     177           0 :         key.str = sid_str;
     178           0 :         value.ul = 0;
     179             : 
     180           0 :         ret = sysdb_search_object_by_sid(mem_ctx, user_dom, sid_str,
     181             :                                          NULL, &msg);
     182           0 :         if (ret == EOK && msg->count == 1) {
     183           0 :             value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0],
     184             :                                                    SYSDB_GIDNUM, 0);
     185             :         }
     186           0 :         talloc_zfree(msg);
     187             : 
     188           0 :         ret = hash_enter(sid_table, &key, &value);
     189           0 :         if (ret != HASH_SUCCESS) {
     190           0 :             DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
     191             :                                       ret, hash_error_string(ret));
     192           0 :             ret = EIO;
     193           0 :             goto done;
     194             :         }
     195             : 
     196             :     }
     197             : 
     198           0 :     for(s = 0; s < info3->sidcount; s++) {
     199           0 :         err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, info3->sids[s].sid,
     200             :                                        &msid_str);
     201           0 :         if (err != IDMAP_SUCCESS) {
     202           0 :             DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
     203           0 :             ret = EFAULT;
     204           0 :             goto done;
     205             :         }
     206             : 
     207           0 :         key.str = msid_str;
     208           0 :         value.ul = 0;
     209             : 
     210           0 :         ret = responder_get_domain_by_id(pac_ctx->rctx, msid_str, &group_dom);
     211           0 :         if (ret == EOK) {
     212           0 :             ret = sysdb_search_object_by_sid(mem_ctx, group_dom, msid_str,
     213             :                                              NULL, &msg);
     214           0 :             if (ret == EOK && msg->count == 1 ) {
     215           0 :                 value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0],
     216             :                                                        SYSDB_GIDNUM, 0);
     217             :             }
     218           0 :             talloc_zfree(msg);
     219             :         }
     220             : 
     221           0 :         ret = hash_enter(sid_table, &key, &value);
     222           0 :         sss_idmap_free_sid(pac_ctx->idmap_ctx, msid_str);
     223           0 :         if (ret != HASH_SUCCESS) {
     224           0 :             DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
     225             :                                       ret, hash_error_string(ret));
     226           0 :             ret = EIO;
     227           0 :             goto done;
     228             :         }
     229             :     }
     230             : 
     231           0 :     ret = EOK;
     232             : 
     233             : done:
     234           0 :     talloc_free(sid_str);
     235           0 :     sss_idmap_free_sid(pac_ctx->idmap_ctx, user_dom_sid_str);
     236             : 
     237           0 :     if (ret == EOK) {
     238           0 :         *_sid_table = sid_table;
     239           0 :         *_user_sid_str = user_sid_str;
     240           0 :         *_primary_group_sid_str = primary_group_sid_str;
     241             :     } else {
     242           0 :         hash_destroy(sid_table);
     243           0 :         talloc_free(user_sid_str);
     244           0 :         talloc_free(primary_group_sid_str);
     245             :     }
     246             : 
     247           0 :     return ret;
     248             : }
     249             : 
     250             : /**
     251             :  * Extract the PAC logon data from an NDR blob.
     252             :  */
     253           0 : errno_t get_data_from_pac(TALLOC_CTX *mem_ctx,
     254             :                           uint8_t *pac_blob, size_t pac_len,
     255             :                           struct PAC_LOGON_INFO **_logon_info)
     256             : {
     257             :     DATA_BLOB blob;
     258             :     struct ndr_pull *ndr_pull;
     259             :     struct PAC_DATA *pac_data;
     260             :     enum ndr_err_code ndr_err;
     261             :     size_t c;
     262             :     int ret;
     263             : 
     264           0 :     blob.data = pac_blob;
     265           0 :     blob.length = pac_len;
     266             : 
     267           0 :     ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
     268           0 :     if (ndr_pull == NULL) {
     269           0 :         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob failed.\n");
     270           0 :         return ENOMEM;
     271             :     }
     272           0 :     ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; /* FIXME: is this really needed ? */
     273             : 
     274           0 :     pac_data = talloc_zero(mem_ctx, struct PAC_DATA);
     275           0 :     if (pac_data == NULL) {
     276           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
     277           0 :         return ENOMEM;
     278             :     }
     279             : 
     280           0 :     ndr_err = ndr_pull_PAC_DATA(ndr_pull, NDR_SCALARS|NDR_BUFFERS, pac_data);
     281           0 :     if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     282           0 :         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_PAC_DATA failed [%d]\n", ndr_err);
     283           0 :         return EBADMSG;
     284             :     }
     285             : 
     286           0 :     for(c = 0; c < pac_data->num_buffers; c++) {
     287           0 :         if (pac_data->buffers[c].type == PAC_TYPE_LOGON_INFO) {
     288           0 :             *_logon_info = pac_data->buffers[c].info->logon_info.info;
     289             : 
     290           0 :             return EOK;
     291             :         }
     292             :     }
     293             : 
     294           0 :     ret = EINVAL;
     295             : 
     296           0 :     talloc_free(pac_data);
     297           0 :     return ret;
     298             : }
     299             : 
     300             : /**
     301             :  * Fill up the passwd struct with data from the PAC logon info
     302             :  */
     303           0 : errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx,
     304             :                          struct sss_domain_info *dom,
     305             :                          char *user_sid_str,
     306             :                          char *primary_group_sid_str,
     307             :                          hash_table_t *sid_table,
     308             :                          struct PAC_LOGON_INFO *logon_info,
     309             :                          struct passwd **_pwd,
     310             :                          struct sysdb_attrs **_attrs)
     311             : {
     312           0 :     struct passwd *pwd = NULL;
     313           0 :     struct sysdb_attrs *attrs = NULL;
     314             :     struct netr_SamBaseInfo *base_info;
     315             :     int ret;
     316             :     char *lname;
     317             :     char *uc_realm;
     318             :     char *upn;
     319             :     hash_key_t key;
     320             :     hash_value_t value;
     321             :     struct sss_nss_homedir_ctx homedir_ctx;
     322             : 
     323           0 :     pwd = talloc_zero(mem_ctx, struct passwd);
     324           0 :     if (pwd == NULL) {
     325           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
     326           0 :         return ENOMEM;
     327             :     }
     328             : 
     329           0 :     base_info = &logon_info->info3.base;
     330             : 
     331           0 :     if (base_info->account_name.size == 0) {
     332           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing account name in PAC.\n");
     333           0 :         ret = EINVAL;
     334           0 :         goto done;
     335             :     }
     336           0 :     if (base_info->rid == 0) {
     337           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing user RID in PAC.\n");
     338           0 :         ret = EINVAL;
     339           0 :         goto done;
     340             :     }
     341             : 
     342             :     /* To be compatible with winbind based lookups we have to use lower
     343             :      * case names only, effectively making the domain case-insenvitive. */
     344           0 :     lname = sss_tc_utf8_str_tolower(pwd, base_info->account_name.string);
     345           0 :     if (lname == NULL) {
     346           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_tc_utf8_str_tolower failed.\n");
     347           0 :         ret = ENOMEM;
     348           0 :         goto done;
     349             :     }
     350             : 
     351             :     /* Subdomain use fully qualified names */
     352           0 :     pwd->pw_name = sss_get_domain_name(pwd, lname, dom);
     353           0 :     if (!pwd->pw_name) {
     354           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_sprintf failed.\n");
     355           0 :         ret = ENOMEM;
     356           0 :         goto done;
     357             :     }
     358             : 
     359           0 :     key.type = HASH_KEY_STRING;
     360           0 :     key.str = user_sid_str;
     361           0 :     ret = hash_lookup(sid_table, &key, &value);
     362           0 :     if (ret != HASH_SUCCESS) {
     363           0 :         DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed.\n");
     364           0 :         ret = EIO;
     365           0 :         goto done;
     366             :     }
     367           0 :     if (value.type != HASH_VALUE_ULONG) {
     368           0 :         DEBUG(SSSDBG_OP_FAILURE, "Wrong value type.\n");
     369           0 :         ret = EIO;
     370           0 :         goto done;
     371             :     }
     372           0 :     pwd->pw_uid = value.ul;
     373             : 
     374           0 :     if (IS_SUBDOMAIN(dom) || dom->mpg) {
     375           0 :         pwd->pw_gid = 0; /* We use MPGs for sub-domains */
     376             :     } else {
     377           0 :         key.type = HASH_KEY_STRING;
     378           0 :         key.str = primary_group_sid_str;
     379           0 :         ret = hash_lookup(sid_table, &key, &value);
     380           0 :         if (ret != HASH_SUCCESS) {
     381           0 :             DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed.\n");
     382           0 :             ret = EIO;
     383           0 :             goto done;
     384             :         }
     385           0 :         if (value.type != HASH_VALUE_ULONG) {
     386           0 :             DEBUG(SSSDBG_OP_FAILURE, "Wrong value type.\n");
     387           0 :             ret = EIO;
     388           0 :             goto done;
     389             :         }
     390           0 :         pwd->pw_gid = value.ul;
     391             :     }
     392             : 
     393           0 :     if (base_info->full_name.size != 0) {
     394           0 :         pwd->pw_gecos = talloc_strdup(pwd, base_info->full_name.string);
     395           0 :         if (pwd->pw_gecos == NULL) {
     396           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     397           0 :             ret = ENOMEM;
     398           0 :             goto done;
     399             :         }
     400             :     } else {
     401           0 :         DEBUG(SSSDBG_OP_FAILURE,
     402             :               "Missing full name in PAC, gecos field will by empty.\n");
     403             :     }
     404             : 
     405             :     /* Check if there is a special homedir template for sub-domains. If not a
     406             :      * fallback will be added by the NSS responder. */
     407           0 :     if (IS_SUBDOMAIN(dom) && dom->subdomain_homedir) {
     408           0 :         ZERO_STRUCT(homedir_ctx);
     409             : 
     410           0 :         homedir_ctx.username = lname;
     411           0 :         homedir_ctx.uid = pwd->pw_uid;
     412           0 :         homedir_ctx.domain = dom->name;
     413           0 :         homedir_ctx.flatname = dom->flat_name;
     414           0 :         homedir_ctx.config_homedir_substr = dom->homedir_substr;
     415             : 
     416           0 :         pwd->pw_dir = expand_homedir_template(pwd, dom->subdomain_homedir,
     417             :                                               &homedir_ctx);
     418           0 :         if (pwd->pw_dir == NULL) {
     419           0 :             ret = ENOMEM;
     420           0 :             goto done;
     421             :         }
     422             :     }
     423             : 
     424           0 :     pwd->pw_shell = NULL; /* Using default */
     425             : 
     426           0 :     attrs = sysdb_new_attrs(mem_ctx);
     427           0 :     if (attrs == NULL) {
     428           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
     429           0 :         ret = ENOMEM;
     430           0 :         goto done;
     431             :     }
     432             : 
     433           0 :     uc_realm = get_uppercase_realm(mem_ctx, dom->name);
     434           0 :     if (uc_realm == NULL) {
     435           0 :         DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n");
     436           0 :         ret = ENOMEM;
     437           0 :         goto done;
     438             :     }
     439             : 
     440           0 :     upn = talloc_asprintf(mem_ctx, "%s@%s", lname, uc_realm);
     441           0 :     talloc_free(uc_realm);
     442           0 :     if (upn == NULL) {
     443           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
     444           0 :         ret = ENOMEM;
     445           0 :         goto done;
     446             :     }
     447             : 
     448           0 :     ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, upn);
     449           0 :     talloc_free(upn);
     450           0 :     if (ret != EOK) {
     451           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
     452           0 :         goto done;
     453             :     }
     454             : 
     455           0 :     ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name);
     456           0 :     if (ret != EOK) {
     457           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n");
     458           0 :         goto done;
     459             :     }
     460             : 
     461           0 :     ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, user_sid_str);
     462           0 :     if (ret != EOK) {
     463           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
     464           0 :         goto done;
     465             :     }
     466             : 
     467           0 :     *_pwd = pwd;
     468           0 :     *_attrs = attrs;
     469             : 
     470           0 :     ret = EOK;
     471             : 
     472             : done:
     473           0 :     if (ret != EOK) {
     474           0 :         talloc_free(pwd);
     475             :     }
     476             : 
     477           0 :     return ret;
     478             : }

Generated by: LCOV version 1.10