source: branches/samba-3.5.x/source3/lib/system_smbd.c

Last change on this file was 599, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.9

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