LCOV - code coverage report
Current view: top level - source3/lib - system_smbd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 29 41 70.7 %
Date: 2024-02-28 12:06:22 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    system call wrapper interface.
       4             :    Copyright (C) Andrew Tridgell 2002
       5             :    Copyright (C) Andrew Barteltt 2002
       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             : /*
      22             :    This file may assume linkage with smbd - for things like become_root()
      23             :    etc.
      24             : */
      25             : 
      26             : #include "includes.h"
      27             : #include "system/passwd.h"
      28             : #include "nsswitch/winbind_client.h"
      29             : #include "../lib/util/setid.h"
      30             : 
      31             : #ifndef HAVE_GETGROUPLIST
      32             : 
      33             : #ifdef HAVE_GETGRSET
      34             : static int getgrouplist_getgrset(const char *user, gid_t gid, gid_t *groups,
      35             :                                  int *grpcnt)
      36             : {
      37             :         char *grplist;
      38             :         char *grp;
      39             :         gid_t temp_gid;
      40             :         int num_gids = 1;
      41             :         int ret = 0;
      42             :         long l;
      43             : 
      44             :         grplist = getgrset(user);
      45             : 
      46             :         DEBUG(10, ("getgrset returned %s\n", grplist));
      47             : 
      48             :         if (grplist == NULL) {
      49             :                 return -1;
      50             :         }
      51             : 
      52             :         if (*grpcnt > 0) {
      53             :                 groups[0] = gid;
      54             :         }
      55             : 
      56             :         while ((grp = strsep(&grplist, ",")) != NULL) {
      57             :                 l = strtol(grp, NULL, 10);
      58             :                 temp_gid = (gid_t) l;
      59             :                 if (temp_gid == gid) {
      60             :                         continue;
      61             :                 }
      62             : 
      63             :                 if (num_gids + 1 > *grpcnt) {
      64             :                         num_gids++;
      65             :                         continue;
      66             :                 }
      67             :                 groups[num_gids++] = temp_gid;
      68             :         }
      69             :         free(grplist);
      70             : 
      71             :         if (num_gids > *grpcnt) {
      72             :                 ret = -1;
      73             :         }
      74             :         *grpcnt = num_gids;
      75             : 
      76             :         DEBUG(10, ("Found %d groups for user %s\n", *grpcnt, user));
      77             : 
      78             :         return ret;
      79             : }
      80             : 
      81             : #else /* HAVE_GETGRSET */
      82             : 
      83             : /*
      84             :   This is a *much* faster way of getting the list of groups for a user
      85             :   without changing the current supplementary group list. The old
      86             :   method used getgrent() which could take 20 minutes on a really big
      87             :   network with hundeds of thousands of groups and users. The new method
      88             :   takes a couple of seconds.
      89             : 
      90             :   NOTE!! this function only works if it is called as root!
      91             :   */
      92             : 
      93             : static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups,
      94             :                                   int *grpcnt)
      95             : {
      96             :         gid_t *gids_saved;
      97             :         int ret, ngrp_saved, num_gids;
      98             : 
      99             :         if (non_root_mode()) {
     100             :                 *grpcnt = 0;
     101             :                 return 0;
     102             :         }
     103             : 
     104             :         /* work out how many groups we need to save */
     105             :         ngrp_saved = getgroups(0, NULL);
     106             :         if (ngrp_saved == -1) {
     107             :                 /* this shouldn't happen */
     108             :                 return -1;
     109             :         }
     110             : 
     111             :         gids_saved = SMB_MALLOC_ARRAY(gid_t, ngrp_saved+1);
     112             :         if (!gids_saved) {
     113             :                 errno = ENOMEM;
     114             :                 return -1;
     115             :         }
     116             : 
     117             :         ngrp_saved = getgroups(ngrp_saved, gids_saved);
     118             :         if (ngrp_saved == -1) {
     119             :                 SAFE_FREE(gids_saved);
     120             :                 /* very strange! */
     121             :                 return -1;
     122             :         }
     123             : 
     124             :         if (initgroups(user, gid) == -1) {
     125             :                 DEBUG(0, ("getgrouplist_internals: initgroups() failed!\n"));
     126             :                 SAFE_FREE(gids_saved);
     127             :                 return -1;
     128             :         }
     129             : 
     130             :         /* this must be done to cope with systems that put the current egid in the
     131             :            return from getgroups() */
     132             :         save_re_gid();
     133             :         set_effective_gid(gid);
     134             :         samba_setgid(gid);
     135             : 
     136             :         num_gids = getgroups(0, NULL);
     137             :         if (num_gids == -1) {
     138             :                 SAFE_FREE(gids_saved);
     139             :                 /* very strange! */
     140             :                 return -1;
     141             :         }
     142             : 
     143             :         if (num_gids + 1 > *grpcnt) {
     144             :                 *grpcnt = num_gids + 1;
     145             :                 ret = -1;
     146             :         } else {
     147             :                 ret = getgroups(*grpcnt - 1, &groups[1]);
     148             :                 if (ret < 0) {
     149             :                         SAFE_FREE(gids_saved);
     150             :                         /* very strange! */
     151             :                         return -1;
     152             :                 }
     153             :                 groups[0] = gid;
     154             :                 *grpcnt = ret + 1;
     155             :         }
     156             : 
     157             :         restore_re_gid();
     158             : 
     159             :         if (sys_setgroups(gid, ngrp_saved, gids_saved) != 0) {
     160             :                 /* yikes! */
     161             :                 DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
     162             :                 smb_panic("getgrouplist: failed to reset group list!");
     163             :         }
     164             : 
     165             :         free(gids_saved);
     166             :         return ret;
     167             : }
     168             : #endif /* HAVE_GETGRSET */
     169             : #endif /* HAVE_GETGROUPLIST */
     170             : 
     171       55019 : static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
     172             : {
     173           3 :         int retval;
     174           3 :         bool winbind_env;
     175             : 
     176       55019 :         DEBUG(10,("sys_getgrouplist: user [%s]\n", user));
     177             : 
     178             :         /* This is only ever called for Unix users, remote memberships are
     179             :          * always determined by the info3 coming back from auth3 or the
     180             :          * PAC. */
     181       55019 :         winbind_env = winbind_env_set();
     182       55019 :         (void)winbind_off();
     183             : 
     184             : #ifdef HAVE_GETGROUPLIST
     185       55019 :         retval = getgrouplist(user, gid, groups, grpcnt);
     186             : #else
     187             : #ifdef HAVE_GETGRSET
     188             :         retval = getgrouplist_getgrset(user, gid, groups, grpcnt);
     189             : #else
     190             :         become_root();
     191             :         retval = getgrouplist_internals(user, gid, groups, grpcnt);
     192             :         unbecome_root();
     193             : #endif /* HAVE_GETGRSET */
     194             : #endif /* HAVE_GETGROUPLIST */
     195             : 
     196             :         /* allow winbindd lookups, but only if they were not already disabled */
     197       55019 :         if (!winbind_env) {
     198       51847 :                 (void)winbind_on();
     199             :         }
     200             : 
     201       55019 :         return retval;
     202             : }
     203             : 
     204       55019 : bool getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user,
     205             :                          gid_t primary_gid,
     206             :                          gid_t **ret_groups, uint32_t *p_ngroups)
     207       55019 : {
     208       55019 :         int max_grp = MIN(128, getgroups_max());
     209       55019 :         gid_t stack_groups[max_grp];
     210           3 :         uint32_t ngrp;
     211       55019 :         gid_t *temp_groups = stack_groups;
     212       55019 :         gid_t *to_free = NULL;
     213           3 :         gid_t *groups;
     214           3 :         int i;
     215             : 
     216       55019 :         if (sys_getgrouplist(user, primary_gid, temp_groups, &max_grp) == -1) {
     217           0 :                 to_free = talloc_array(mem_ctx, gid_t, max_grp);
     218           0 :                 if (!to_free) {
     219           0 :                         return False;
     220             :                 }
     221           0 :                 temp_groups = to_free;
     222             : 
     223           0 :                 if (sys_getgrouplist(user, primary_gid,
     224             :                                      temp_groups, &max_grp) == -1) {
     225           0 :                         DEBUG(0, ("get_user_groups: failed to get the unix "
     226             :                                   "group list\n"));
     227           0 :                         TALLOC_FREE(to_free);
     228           0 :                         return False;
     229             :                 }
     230             :         }
     231             : 
     232       55019 :         ngrp = 0;
     233       55019 :         groups = NULL;
     234             : 
     235             :         /* Add in primary group first */
     236       55019 :         if (!add_gid_to_array_unique(mem_ctx, primary_gid, &groups, &ngrp)) {
     237           0 :                 TALLOC_FREE(to_free);
     238           0 :                 return False;
     239             :         }
     240             : 
     241      159902 :         for (i=0; i<max_grp; i++) {
     242      104883 :                 if (!add_gid_to_array_unique(mem_ctx, temp_groups[i],
     243             :                                         &groups, &ngrp)) {
     244           0 :                         TALLOC_FREE(to_free);
     245           0 :                         return False;
     246             :                 }
     247             :         }
     248             : 
     249       55019 :         *p_ngroups = ngrp;
     250       55019 :         *ret_groups = groups;
     251       55019 :         TALLOC_FREE(to_free);
     252       55016 :         return True;
     253             : }

Generated by: LCOV version 1.14