LCOV - code coverage report
Current view: top level - source3/winbindd - idmap_nss.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 0 214 0.0 %
Date: 2024-04-21 15:09:00 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    idmap NSS backend
       5             : 
       6             :    Copyright (C) Simo Sorce 2006
       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             : 
      22             : #include "includes.h"
      23             : #include "system/passwd.h"
      24             : #include "winbindd.h"
      25             : #include "nsswitch/winbind_client.h"
      26             : #include "idmap.h"
      27             : #include "lib/winbind_util.h"
      28             : #include "libcli/security/dom_sid.h"
      29             : #include "lib/global_contexts.h"
      30             : #include "messages.h"
      31             : 
      32             : #undef DBGC_CLASS
      33             : #define DBGC_CLASS DBGC_IDMAP
      34             : 
      35             : struct idmap_nss_context {
      36             :         struct idmap_domain *dom;
      37             :         bool use_upn;
      38             : };
      39             : 
      40           0 : static int idmap_nss_context_destructor(struct idmap_nss_context *ctx)
      41             : {
      42           0 :         if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
      43           0 :                 ctx->dom->private_data = NULL;
      44             :         }
      45           0 :         return 0;
      46             : }
      47             : 
      48           0 : static NTSTATUS idmap_nss_context_create(TALLOC_CTX *mem_ctx,
      49             :                                          struct idmap_domain *dom,
      50             :                                          struct idmap_nss_context **pctx)
      51             : {
      52           0 :         struct idmap_nss_context *ctx = NULL;
      53             : 
      54           0 :         ctx = talloc_zero(mem_ctx, struct idmap_nss_context);
      55           0 :         if (ctx == NULL) {
      56           0 :                 return NT_STATUS_NO_MEMORY;
      57             :         }
      58           0 :         ctx->dom = dom;
      59             : 
      60           0 :         talloc_set_destructor(ctx, idmap_nss_context_destructor);
      61             : 
      62           0 :         ctx->use_upn = idmap_config_bool(dom->name, "use_upn", false);
      63             : 
      64           0 :         *pctx = ctx;
      65           0 :         return NT_STATUS_OK;
      66             : }
      67             : 
      68           0 : static NTSTATUS idmap_nss_get_context(struct idmap_domain *dom,
      69             :                                       struct idmap_nss_context **pctx)
      70             : {
      71           0 :         struct idmap_nss_context *ctx = NULL;
      72           0 :         NTSTATUS status;
      73             : 
      74           0 :         if (dom->private_data != NULL) {
      75           0 :                 *pctx = talloc_get_type_abort(dom->private_data,
      76             :                                               struct idmap_nss_context);
      77           0 :                 return NT_STATUS_OK;
      78             :         }
      79             : 
      80           0 :         status = idmap_nss_context_create(dom, dom, &ctx);
      81           0 :         if (!NT_STATUS_IS_OK(status)) {
      82           0 :                 DBG_WARNING("idmap_nss_context_create failed: %s\n",
      83             :                             nt_errstr(status));
      84           0 :                 return status;
      85             :         }
      86             : 
      87           0 :         dom->private_data = ctx;
      88           0 :         *pctx = ctx;
      89           0 :         return NT_STATUS_OK;
      90             : }
      91             : 
      92           0 : static bool idmap_nss_msg_filter(struct messaging_rec *rec, void *private_data)
      93             : {
      94           0 :         struct idmap_domain *dom = talloc_get_type_abort(private_data,
      95             :                        struct idmap_domain);
      96           0 :         struct idmap_nss_context *ctx = NULL;
      97           0 :         NTSTATUS status;
      98           0 :         bool ret;
      99             : 
     100           0 :         if (rec->msg_type == MSG_SMB_CONF_UPDATED) {
     101           0 :                 ret = lp_load_global(get_dyn_CONFIGFILE());
     102           0 :                 if (!ret) {
     103           0 :                         DBG_WARNING("Failed to reload configuration\n");
     104           0 :                         return false;
     105             :                 }
     106             : 
     107           0 :                 status = idmap_nss_get_context(dom, &ctx);
     108           0 :                 if (NT_STATUS_IS_ERR(status)) {
     109           0 :                         DBG_WARNING("Failed to get idmap nss context: %s\n",
     110             :                                         nt_errstr(status));
     111           0 :                         return false;
     112             :                 }
     113             : 
     114           0 :                 ctx->use_upn = idmap_config_bool(dom->name, "use_upn", false);
     115             :         }
     116             : 
     117           0 :         return false;
     118             : }
     119             : 
     120             : /*****************************
     121             :  Initialise idmap database.
     122             : *****************************/
     123             : 
     124           0 : static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
     125             : {
     126           0 :         struct idmap_nss_context *ctx = NULL;
     127           0 :         NTSTATUS status;
     128           0 :         struct messaging_context *msg_ctx = global_messaging_context();
     129           0 :         struct tevent_req *req = NULL;
     130             : 
     131           0 :         status = idmap_nss_context_create(dom, dom, &ctx);
     132           0 :         if (NT_STATUS_IS_ERR(status)) {
     133           0 :                 return status;
     134             :         }
     135             : 
     136           0 :         dom->private_data = ctx;
     137             : 
     138           0 :         req = messaging_filtered_read_send(
     139             :                         dom,
     140             :                         messaging_tevent_context(msg_ctx),
     141             :                         msg_ctx,
     142             :                         idmap_nss_msg_filter,
     143             :                         dom);
     144           0 :         if (req == NULL) {
     145           0 :                 DBG_WARNING("messaging_filtered_read_send failed\n");
     146           0 :                 return NT_STATUS_UNSUCCESSFUL;
     147             :         }
     148             : 
     149           0 :         return status;
     150             : }
     151             : 
     152           0 : static NTSTATUS idmap_nss_lookup_name(const char *namespace,
     153             :                                       const char *username,
     154             :                                       struct dom_sid *sid,
     155             :                                       enum lsa_SidType *type)
     156             : {
     157           0 :         bool ret;
     158             : 
     159             :         /*
     160             :          * By default calls to winbindd are disabled
     161             :          * the following call will not recurse so this is safe
     162             :          */
     163           0 :         (void)winbind_on();
     164           0 :         ret = winbind_lookup_name(namespace, username, sid, type);
     165           0 :         (void)winbind_off();
     166             : 
     167           0 :         if (!ret) {
     168           0 :                 DBG_NOTICE("Failed to lookup name [%s] in namespace [%s]\n",
     169             :                            username, namespace);
     170           0 :                 return NT_STATUS_NOT_FOUND;
     171             :         }
     172             : 
     173           0 :         return NT_STATUS_OK;
     174             : }
     175             : 
     176             : /**********************************
     177             :  lookup a set of unix ids.
     178             : **********************************/
     179             : 
     180           0 : static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
     181             : {
     182           0 :         struct idmap_nss_context *ctx = NULL;
     183           0 :         NTSTATUS status;
     184           0 :         int i;
     185             : 
     186           0 :         status = idmap_nss_get_context(dom, &ctx);
     187           0 :         if (NT_STATUS_IS_ERR(status)) {
     188           0 :                 DBG_WARNING("Failed to get idmap nss context: %s\n",
     189             :                             nt_errstr(status));
     190           0 :                 return status;
     191             :         }
     192             : 
     193             :         /* initialize the status to avoid surprise */
     194           0 :         for (i = 0; ids[i]; i++) {
     195           0 :                 ids[i]->status = ID_UNKNOWN;
     196             :         }
     197             : 
     198           0 :         for (i = 0; ids[i]; i++) {
     199           0 :                 struct passwd *pw;
     200           0 :                 struct group *gr;
     201           0 :                 const char *name;
     202           0 :                 struct dom_sid sid;
     203           0 :                 enum lsa_SidType type;
     204             : 
     205           0 :                 switch (ids[i]->xid.type) {
     206           0 :                 case ID_TYPE_UID:
     207           0 :                         errno = 0;
     208           0 :                         pw = getpwuid((uid_t)ids[i]->xid.id);
     209           0 :                         if (!pw) {
     210           0 :                                 DBG_DEBUG("getpwuid(%lu) failed: %s\n",
     211             :                                           (unsigned long)ids[i]->xid.id,
     212             :                                           errno != 0
     213             :                                           ? strerror(errno)
     214             :                                           : "not found");
     215           0 :                                 ids[i]->status = ID_UNMAPPED;
     216           0 :                                 continue;
     217             :                         }
     218           0 :                         name = pw->pw_name;
     219           0 :                         break;
     220           0 :                 case ID_TYPE_GID:
     221           0 :                         errno = 0;
     222           0 :                         gr = getgrgid((gid_t)ids[i]->xid.id);
     223           0 :                         if (!gr) {
     224           0 :                                 DBG_DEBUG("getgrgid(%lu) failed: %s\n",
     225             :                                           (unsigned long)ids[i]->xid.id,
     226             :                                           errno != 0
     227             :                                           ? strerror(errno)
     228             :                                           : "not found");
     229           0 :                                 ids[i]->status = ID_UNMAPPED;
     230           0 :                                 continue;
     231             :                         }
     232           0 :                         name = gr->gr_name;
     233           0 :                         break;
     234           0 :                 default: /* ?? */
     235           0 :                         DBG_WARNING("Unexpected xid type %d\n",
     236             :                                     ids[i]->xid.type);
     237           0 :                         ids[i]->status = ID_UNKNOWN;
     238           0 :                         continue;
     239             :                 }
     240             : 
     241             :                 /* Lookup name from PDC using lsa_lookup_names() */
     242           0 :                 if (ctx->use_upn) {
     243           0 :                         char *p = NULL;
     244           0 :                         const char *namespace = NULL;
     245           0 :                         const char *domname = NULL;
     246           0 :                         const char *domuser = NULL;
     247             : 
     248           0 :                         p = strstr(name, lp_winbind_separator());
     249           0 :                         if (p != NULL) {
     250           0 :                                 *p = '\0';
     251           0 :                                 domname = name;
     252           0 :                                 namespace = domname;
     253           0 :                                 domuser = p + 1;
     254             :                         } else {
     255           0 :                                 p = strchr(name, '@');
     256           0 :                                 if (p != NULL) {
     257           0 :                                         *p = '\0';
     258           0 :                                         namespace = p + 1;
     259           0 :                                         domname = "";
     260           0 :                                         domuser = name;
     261             :                                 } else {
     262           0 :                                         namespace = dom->name;
     263           0 :                                         domuser = name;
     264             :                                 }
     265             :                         }
     266             : 
     267           0 :                         DBG_DEBUG("Using namespace [%s] from UPN instead "
     268             :                                   "of [%s] to lookup the name [%s]\n",
     269             :                                   namespace, dom->name, domuser);
     270             : 
     271           0 :                         status = idmap_nss_lookup_name(namespace,
     272             :                                                        domuser,
     273             :                                                        &sid,
     274             :                                                        &type);
     275             :                 } else {
     276           0 :                         status = idmap_nss_lookup_name(dom->name,
     277             :                                                        name,
     278             :                                                        &sid,
     279             :                                                        &type);
     280             :                 }
     281             : 
     282           0 :                 if (NT_STATUS_IS_ERR(status)) {
     283             :                         /*
     284             :                          * TODO: how do we know if the name is really
     285             :                          * not mapped, or something just failed ?
     286             :                          */
     287           0 :                         ids[i]->status = ID_UNMAPPED;
     288           0 :                         continue;
     289             :                 }
     290             : 
     291           0 :                 switch (type) {
     292           0 :                 case SID_NAME_USER:
     293           0 :                         if (ids[i]->xid.type == ID_TYPE_UID) {
     294           0 :                                 sid_copy(ids[i]->sid, &sid);
     295           0 :                                 ids[i]->status = ID_MAPPED;
     296             :                         }
     297           0 :                         break;
     298             : 
     299           0 :                 case SID_NAME_DOM_GRP:
     300             :                 case SID_NAME_ALIAS:
     301             :                 case SID_NAME_WKN_GRP:
     302           0 :                         if (ids[i]->xid.type == ID_TYPE_GID) {
     303           0 :                                 sid_copy(ids[i]->sid, &sid);
     304           0 :                                 ids[i]->status = ID_MAPPED;
     305             :                         }
     306           0 :                         break;
     307             : 
     308           0 :                 default:
     309           0 :                         ids[i]->status = ID_UNKNOWN;
     310           0 :                         break;
     311             :                 }
     312             :         }
     313           0 :         return NT_STATUS_OK;
     314             : }
     315             : 
     316             : /**********************************
     317             :  lookup a set of sids.
     318             : **********************************/
     319             : 
     320           0 : static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
     321             : {
     322           0 :         struct idmap_nss_context *ctx = NULL;
     323           0 :         NTSTATUS status;
     324           0 :         int i;
     325             : 
     326           0 :         status = idmap_nss_get_context(dom, &ctx);
     327           0 :         if (NT_STATUS_IS_ERR(status)) {
     328           0 :                 DBG_WARNING("Failed to get idmap nss context: %s\n",
     329             :                             nt_errstr(status));
     330           0 :                 return status;
     331             :         }
     332             : 
     333             :         /* initialize the status to avoid surprise */
     334           0 :         for (i = 0; ids[i]; i++) {
     335           0 :                 ids[i]->status = ID_UNKNOWN;
     336             :         }
     337             : 
     338           0 :         for (i = 0; ids[i]; i++) {
     339           0 :                 struct group *gr;
     340           0 :                 enum lsa_SidType type;
     341           0 :                 const char *_domain = NULL;
     342           0 :                 const char *_name = NULL;
     343           0 :                 char *domain = NULL;
     344           0 :                 char *name = NULL;
     345           0 :                 char *fqdn = NULL;
     346           0 :                 char *sname = NULL;
     347           0 :                 bool ret;
     348             : 
     349             :                 /* by default calls to winbindd are disabled
     350             :                    the following call will not recurse so this is safe */
     351           0 :                 (void)winbind_on();
     352           0 :                 ret = winbind_lookup_sid(talloc_tos(),
     353           0 :                                          ids[i]->sid,
     354             :                                          &_domain,
     355             :                                          &_name,
     356             :                                          &type);
     357           0 :                 (void)winbind_off();
     358           0 :                 if (!ret) {
     359             :                         /* TODO: how do we know if the name is really not mapped,
     360             :                          * or something just failed ? */
     361           0 :                         ids[i]->status = ID_UNMAPPED;
     362           0 :                         continue;
     363             :                 }
     364             : 
     365           0 :                 domain = discard_const_p(char, _domain);
     366           0 :                 name = discard_const_p(char, _name);
     367             : 
     368           0 :                 if (!strequal(domain, dom->name)) {
     369           0 :                         struct dom_sid_buf buf;
     370           0 :                         DBG_ERR("DOMAIN[%s] ignoring SID[%s] belongs to %s [%s\\%s]\n",
     371             :                                 dom->name, dom_sid_str_buf(ids[i]->sid, &buf),
     372             :                                 sid_type_lookup(type), domain, name);
     373           0 :                         ids[i]->status = ID_UNMAPPED;
     374           0 :                         continue;
     375             :                 }
     376             : 
     377           0 :                 if (ctx->use_upn) {
     378           0 :                         fqdn = talloc_asprintf(talloc_tos(),
     379             :                                                "%s%s%s",
     380             :                                                domain,
     381             :                                                lp_winbind_separator(),
     382             :                                                name);
     383           0 :                         if (fqdn == NULL) {
     384           0 :                                 DBG_ERR("No memory\n");
     385           0 :                                 ids[i]->status = ID_UNMAPPED;
     386           0 :                                 continue;
     387             :                         }
     388           0 :                         DBG_DEBUG("Using UPN [%s] instead of plain name [%s]\n",
     389             :                                   fqdn, name);
     390           0 :                         sname = fqdn;
     391             :                 } else {
     392           0 :                         sname = name;
     393             :                 }
     394             : 
     395           0 :                 switch (type) {
     396           0 :                 case SID_NAME_USER: {
     397           0 :                         struct passwd *pw;
     398             : 
     399             :                         /* this will find also all lower case name and use username level */
     400           0 :                         pw = Get_Pwnam_alloc(talloc_tos(), sname);
     401           0 :                         if (pw) {
     402           0 :                                 ids[i]->xid.id = pw->pw_uid;
     403           0 :                                 ids[i]->xid.type = ID_TYPE_UID;
     404           0 :                                 ids[i]->status = ID_MAPPED;
     405             :                         }
     406           0 :                         TALLOC_FREE(pw);
     407           0 :                         break;
     408             :                 }
     409             : 
     410           0 :                 case SID_NAME_DOM_GRP:
     411             :                 case SID_NAME_ALIAS:
     412             :                 case SID_NAME_WKN_GRP:
     413             : 
     414           0 :                         gr = getgrnam(sname);
     415           0 :                         if (gr) {
     416           0 :                                 ids[i]->xid.id = gr->gr_gid;
     417           0 :                                 ids[i]->xid.type = ID_TYPE_GID;
     418           0 :                                 ids[i]->status = ID_MAPPED;
     419             :                         }
     420           0 :                         break;
     421             : 
     422           0 :                 default:
     423           0 :                         ids[i]->status = ID_UNKNOWN;
     424           0 :                         break;
     425             :                 }
     426           0 :                 TALLOC_FREE(domain);
     427           0 :                 TALLOC_FREE(name);
     428           0 :                 TALLOC_FREE(fqdn);
     429             :         }
     430           0 :         return NT_STATUS_OK;
     431             : }
     432             : 
     433             : /**********************************
     434             :  Close the idmap tdb instance
     435             : **********************************/
     436             : 
     437             : static const struct idmap_methods nss_methods = {
     438             :         .init = idmap_nss_int_init,
     439             :         .unixids_to_sids = idmap_nss_unixids_to_sids,
     440             :         .sids_to_unixids = idmap_nss_sids_to_unixids,
     441             : };
     442             : 
     443           0 : NTSTATUS idmap_nss_init(TALLOC_CTX *mem_ctx)
     444             : {
     445           0 :         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "nss", &nss_methods);
     446             : }

Generated by: LCOV version 1.14