increase log level for this failed setsockopt call. EINVAL is a normal error on Solar...
[jra/samba/.git] / source / lib / system_smbd.c
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
40 static 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
117 static 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
146 bool 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(32, 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 }