• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/lib/
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/*
31  This is a *much* faster way of getting the list of groups for a user
32  without changing the current supplementary group list. The old
33  method used getgrent() which could take 20 minutes on a really big
34  network with hundeds of thousands of groups and users. The new method
35  takes a couple of seconds.
36
37  NOTE!! this function only works if it is called as root!
38  */
39
40static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups,
41				  int *grpcnt)
42{
43	gid_t *gids_saved;
44	int ret, ngrp_saved, num_gids;
45
46	if (non_root_mode()) {
47		*grpcnt = 0;
48		return 0;
49	}
50
51	/* work out how many groups we need to save */
52	ngrp_saved = getgroups(0, NULL);
53	if (ngrp_saved == -1) {
54		/* this shouldn't happen */
55		return -1;
56	}
57
58	gids_saved = SMB_MALLOC_ARRAY(gid_t, ngrp_saved+1);
59	if (!gids_saved) {
60		errno = ENOMEM;
61		return -1;
62	}
63
64	ngrp_saved = getgroups(ngrp_saved, gids_saved);
65	if (ngrp_saved == -1) {
66		SAFE_FREE(gids_saved);
67		/* very strange! */
68		return -1;
69	}
70
71	if (initgroups(user, gid) != 0) {
72		DEBUG(0, ("getgrouplist_internals: initgroups() failed!\n"));
73		SAFE_FREE(gids_saved);
74		return -1;
75	}
76
77	/* this must be done to cope with systems that put the current egid in the
78	   return from getgroups() */
79	save_re_gid();
80	set_effective_gid(gid);
81	setgid(gid);
82
83	num_gids = getgroups(0, NULL);
84	if (num_gids == -1) {
85		SAFE_FREE(gids_saved);
86		/* very strange! */
87		return -1;
88	}
89
90	if (num_gids + 1 > *grpcnt) {
91		*grpcnt = num_gids + 1;
92		ret = -1;
93	} else {
94		ret = getgroups(*grpcnt - 1, &groups[1]);
95		if (ret < 0) {
96			SAFE_FREE(gids_saved);
97			/* very strange! */
98			return -1;
99		}
100		groups[0] = gid;
101		*grpcnt = ret + 1;
102	}
103
104	restore_re_gid();
105
106	if (sys_setgroups(gid, ngrp_saved, gids_saved) != 0) {
107		/* yikes! */
108		DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
109		smb_panic("getgrouplist: failed to reset group list!");
110	}
111
112	free(gids_saved);
113	return ret;
114}
115#endif
116
117static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
118{
119	int retval;
120	bool winbind_env;
121
122	DEBUG(10,("sys_getgrouplist: user [%s]\n", user));
123
124	/* This is only ever called for Unix users, remote memberships are
125	 * always determined by the info3 coming back from auth3 or the
126	 * PAC. */
127	winbind_env = winbind_env_set();
128	(void)winbind_off();
129
130#ifdef HAVE_GETGROUPLIST
131	retval = getgrouplist(user, gid, groups, grpcnt);
132#else
133	become_root();
134	retval = getgrouplist_internals(user, gid, groups, grpcnt);
135	unbecome_root();
136#endif
137
138	/* allow winbindd lookups, but only if they were not already disabled */
139	if (!winbind_env) {
140		(void)winbind_on();
141	}
142
143	return retval;
144}
145
146bool getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user,
147			 gid_t primary_gid,
148			 gid_t **ret_groups, size_t *p_ngroups)
149{
150	size_t ngrp;
151	int max_grp;
152	gid_t *temp_groups;
153	gid_t *groups;
154	int i;
155
156	max_grp = MIN(128, groups_max());
157	temp_groups = SMB_MALLOC_ARRAY(gid_t, max_grp);
158	if (! temp_groups) {
159		return False;
160	}
161
162	if (sys_getgrouplist(user, primary_gid, temp_groups, &max_grp) == -1) {
163		temp_groups = SMB_REALLOC_ARRAY(temp_groups, gid_t, max_grp);
164		if (!temp_groups) {
165			return False;
166		}
167
168		if (sys_getgrouplist(user, primary_gid,
169				     temp_groups, &max_grp) == -1) {
170			DEBUG(0, ("get_user_groups: failed to get the unix "
171				  "group list\n"));
172			SAFE_FREE(temp_groups);
173			return False;
174		}
175	}
176
177	ngrp = 0;
178	groups = NULL;
179
180	/* Add in primary group first */
181	if (!add_gid_to_array_unique(mem_ctx, primary_gid, &groups, &ngrp)) {
182		SAFE_FREE(temp_groups);
183		return False;
184	}
185
186	for (i=0; i<max_grp; i++) {
187		if (!add_gid_to_array_unique(mem_ctx, temp_groups[i],
188					&groups, &ngrp)) {
189			SAFE_FREE(temp_groups);
190			return False;
191		}
192	}
193
194	*p_ngroups = ngrp;
195	*ret_groups = groups;
196	SAFE_FREE(temp_groups);
197	return True;
198}
199