rpc_server/srv_samr.c:
[bbaumbach/samba-autobuild/.git] / source / smbd / uid.c
1 #define OLD_NTDOMAIN 1
2
3 /* 
4    Unix SMB/Netbios implementation.
5    Version 1.9.
6    uid/user handling
7    Copyright (C) Andrew Tridgell 1992-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 extern int DEBUGLEVEL;
27
28 /* what user is current? */
29 extern struct current_user current_user;
30
31 /****************************************************************************
32  Become the guest user.
33 ****************************************************************************/
34
35 BOOL become_guest(void)
36 {
37         static struct passwd *pass=NULL;
38         
39         if (!pass)
40                 pass = Get_Pwnam(lp_guestaccount(-1),True);
41         if (!pass)
42                 return(False);
43         
44 #ifdef AIX
45         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
46            setting IDs */
47         initgroups(pass->pw_name, (gid_t)pass->pw_gid);
48 #endif
49         
50         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
51         
52         current_user.conn = NULL;
53         current_user.vuid = UID_FIELD_INVALID;
54         
55         return True;
56 }
57
58 /*******************************************************************
59  Check if a username is OK.
60 ********************************************************************/
61
62 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
63 {
64         int i;
65         for (i=0;i<conn->uid_cache.entries;i++)
66                 if (conn->uid_cache.list[i] == vuser->uid)
67                         return(True);
68
69         if (!user_ok(vuser->user.unix_name,snum))
70                 return(False);
71
72         i = conn->uid_cache.entries % UID_CACHE_SIZE;
73         conn->uid_cache.list[i] = vuser->uid;
74
75         if (conn->uid_cache.entries < UID_CACHE_SIZE)
76                 conn->uid_cache.entries++;
77
78         return(True);
79 }
80
81 /****************************************************************************
82  Become the user of a connection number.
83 ****************************************************************************/
84
85 BOOL become_user(connection_struct *conn, uint16 vuid)
86 {
87         user_struct *vuser = get_valid_user_struct(vuid);
88         int snum;
89         gid_t gid;
90         uid_t uid;
91         char group_c;
92         BOOL must_free_token = False;
93         NT_USER_TOKEN *token = NULL;
94
95         if (!conn) {
96                 DEBUG(2,("Connection not open\n"));
97                 return(False);
98         }
99
100         /*
101          * We need a separate check in security=share mode due to vuid
102          * always being UID_FIELD_INVALID. If we don't do this then
103          * in share mode security we are *always* changing uid's between
104          * SMB's - this hurts performance - Badly.
105          */
106
107         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
108            (current_user.uid == conn->uid)) {
109                 DEBUG(4,("Skipping become_user - already user\n"));
110                 return(True);
111         } else if ((current_user.conn == conn) && 
112                    (vuser != 0) && (current_user.vuid == vuid) && 
113                    (current_user.uid == vuser->uid)) {
114                 DEBUG(4,("Skipping become_user - already user\n"));
115                 return(True);
116         }
117
118         snum = SNUM(conn);
119
120         if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
121                 return False;
122
123         if (conn->force_user || 
124                 conn->admin_user ||
125             lp_security() == SEC_SHARE ||
126             !(vuser) || (vuser->guest)) {
127                 uid = conn->uid;
128                 gid = conn->gid;
129                 current_user.groups = conn->groups;
130                 current_user.ngroups = conn->ngroups;
131                 token = conn->nt_user_token;
132         } else {
133                 if (!vuser) {
134                         DEBUG(2,("Invalid vuid used %d\n",vuid));
135                         return(False);
136                 }
137                 uid = vuser->uid;
138                 gid = vuser->gid;
139                 current_user.ngroups = vuser->n_groups;
140                 current_user.groups  = vuser->groups;
141                 token = vuser->nt_user_token;
142         }
143
144         /*
145          * See if we should force group for this service.
146          * If so this overrides any group set in the force
147          * user code.
148          */
149
150         if((group_c = *lp_force_group(snum))) {
151                 BOOL is_guest = False;
152
153                 if(group_c == '+') {
154
155                         /*
156                          * Only force group if the user is a member of
157                          * the service group. Check the group memberships for
158                          * this user (we already have this) to
159                          * see if we should force the group.
160                          */
161
162                         int i;
163                         for (i = 0; i < current_user.ngroups; i++) {
164                                 if (current_user.groups[i] == conn->gid) {
165                                         gid = conn->gid;
166                                         break;
167                                 }
168                         }
169                 } else {
170                         gid = conn->gid;
171                 }
172
173                 /*
174                  * We've changed the group list in the token - we must
175                  * re-create it.
176                  */
177
178                 if (vuser && vuser->guest)
179                         is_guest = True;
180
181                 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
182                 must_free_token = True;
183         }
184         
185         set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
186
187         /*
188          * Free the new token (as set_sec_ctx copies it).
189          */
190
191         if (must_free_token)
192                 delete_nt_token(&token);
193
194         current_user.conn = conn;
195         current_user.vuid = vuid;
196
197         DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
198                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
199   
200         return(True);
201 }
202
203 /****************************************************************************
204  Unbecome the user of a connection number.
205 ****************************************************************************/
206
207 BOOL unbecome_user(void )
208 {
209         set_root_sec_ctx();
210
211         DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
212                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
213
214         current_user.conn = NULL;
215         current_user.vuid = UID_FIELD_INVALID;
216
217         return(True);
218 }
219
220 /****************************************************************************
221  Become the user of an authenticated connected named pipe.
222  When this is called we are currently running as the connection
223  user.
224 ****************************************************************************/
225
226 BOOL become_authenticated_pipe_user(pipes_struct *p)
227 {
228         BOOL res = push_sec_ctx();
229
230         if (!res) {
231                 return False;
232         }
233
234         set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, 
235                     p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
236
237         return True;
238 }
239
240 /****************************************************************************
241  Unbecome the user of an authenticated connected named pipe.
242  When this is called we are running as the authenticated pipe
243  user and need to go back to being the connection user.
244 ****************************************************************************/
245
246 BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
247 {
248         return pop_sec_ctx();
249 }
250
251 /* Temporarily become a root user.  Must match with unbecome_root(). */
252
253 void become_root(void)
254 {
255         push_sec_ctx();
256         set_root_sec_ctx();
257 }
258
259 /* Unbecome the root user */
260
261 void unbecome_root(void)
262 {
263         pop_sec_ctx();
264 }
265
266 /*****************************************************************
267  *THE CANONICAL* convert name to SID function.
268  Tries winbind first - then uses local lookup.
269 *****************************************************************/  
270
271 BOOL lookup_name(char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
272 {
273         extern pstring global_myname;
274         fstring sid;
275         char *sep = lp_winbind_separator();
276
277         if (!winbind_lookup_name(name, psid, name_type)) {
278                 BOOL ret;
279
280                 DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
281
282                 /* If we are looking up a domain user, make sure it is
283                    for the local machine only */
284
285                 if (strchr(name, sep[0]) || strchr(name, '\\')) {
286                         fstring domain, username;
287
288                         split_domain_name(name, domain, username);
289
290                         if (strcasecmp(global_myname, domain) != 0) {
291                                 DEBUG(5, ("domain %s is not local\n", domain));
292                                 return False;
293                         }
294
295                         ret = local_lookup_name(domain, username, psid, 
296                                                 name_type);
297                 } else {
298
299                         ret = local_lookup_name(global_myname, name, psid, 
300                                                 name_type);
301                 }
302
303                 if (ret) {
304                         DEBUG(10,
305                               ("lookup_name: (local) %s -> SID %s (type %u)\n",
306                                name, sid_to_string(sid,psid),
307                                (unsigned int)*name_type ));
308                 } else {
309                         DEBUG(10,("lookup name: (local) %s failed.\n", name));
310                 }
311
312                 return ret;
313         }
314
315                 DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
316                           name, sid_to_string(sid, psid), 
317                           (unsigned int)*name_type));
318         return True;
319 }
320
321 /*****************************************************************
322  *THE CANONICAL* convert SID to name function.
323  Tries winbind first - then uses local lookup.
324 *****************************************************************/  
325
326 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
327 {
328         if (!name_type)
329                 return False;
330
331         /* Check if this is our own sid.  This should perhaps be done by
332            winbind?  For the moment handle it here. */
333
334         if (sid->num_auths == 5) {
335                 DOM_SID tmp_sid;
336                 uint32 rid;
337
338                 sid_copy(&tmp_sid, sid);
339                 sid_split_rid(&tmp_sid, &rid);
340
341                 if (sid_equal(&global_sam_sid, &tmp_sid)) {
342
343                         return map_domain_sid_to_name(&tmp_sid, dom_name) &&
344                                 local_lookup_rid(rid, name, name_type);
345                 }
346         }
347
348         if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
349                 fstring sid_str;
350                 DOM_SID tmp_sid;
351                 uint32 rid;
352
353                 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
354
355                 sid_copy(&tmp_sid, sid);
356                 sid_split_rid(&tmp_sid, &rid);
357                 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
358                                 lookup_known_rid(&tmp_sid, rid, name, name_type);
359         }
360         return True;
361 }
362
363 /*****************************************************************
364  *THE CANONICAL* convert uid_t to SID function.
365  Tries winbind first - then uses local lookup.
366  Returns SID pointer.
367 *****************************************************************/  
368
369 DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
370 {
371         fstring sid;
372
373         if (!winbind_uid_to_sid(psid, uid)) {
374                 DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid ));
375
376                 return local_uid_to_sid(psid, uid);
377         }
378
379         DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
380                 (unsigned int)uid, sid_to_string(sid, psid) ));
381
382         return psid;
383 }
384
385 /*****************************************************************
386  *THE CANONICAL* convert gid_t to SID function.
387  Tries winbind first - then uses local lookup.
388  Returns SID pointer.
389 *****************************************************************/  
390
391 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
392 {
393         fstring sid;
394
395         if (!winbind_gid_to_sid(psid, gid)) {
396                 DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid ));
397
398                 return local_gid_to_sid(psid, gid);
399         }
400
401         DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
402                 (unsigned int)gid, sid_to_string(sid,psid) ));
403
404         return psid;
405 }
406
407 /*****************************************************************
408  *THE CANONICAL* convert SID to uid function.
409  Tries winbind first - then uses local lookup.
410  Returns True if this name is a user sid and the conversion
411  was done correctly, False if not.
412 *****************************************************************/  
413
414 BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
415 {
416         fstring dom_name, name, sid_str;
417         enum SID_NAME_USE name_type;
418
419         *sidtype = SID_NAME_UNKNOWN;
420
421         /*
422          * First we must look up the name and decide if this is a user sid.
423          */
424
425         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
426                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
427                                 sid_to_string(sid_str, psid) ));
428
429                 return local_sid_to_uid(puid, psid, sidtype);
430         }
431
432         /*
433          * Ensure this is a user sid.
434          */
435
436         if (name_type != SID_NAME_USER) {
437                 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
438                                 (unsigned int)name_type ));
439                 return False;
440         }
441
442         *sidtype = SID_NAME_USER;
443
444         /*
445          * Get the uid for this SID.
446          */
447
448         if (!winbind_sid_to_uid(puid, psid)) {
449                 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
450                                 sid_to_string(sid_str, psid) ));
451                 return False;
452         }
453
454         DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
455                 sid_to_string(sid_str, psid),
456                 (unsigned int)*puid ));
457
458         return True;
459 }
460
461 /*****************************************************************
462  *THE CANONICAL* convert SID to gid function.
463  Tries winbind first - then uses local lookup.
464  Returns True if this name is a user sid and the conversion
465  was done correctly, False if not.
466 *****************************************************************/  
467
468 BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
469 {
470         fstring dom_name, name, sid_str;
471         enum SID_NAME_USE name_type;
472
473         *sidtype = SID_NAME_UNKNOWN;
474
475         /*
476          * First we must look up the name and decide if this is a group sid.
477          */
478
479         if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
480                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
481                                 sid_to_string(sid_str, psid) ));
482
483                 return local_sid_to_gid(pgid, psid, sidtype);
484         }
485
486         /*
487          * Ensure this is a group sid.
488          */
489
490         if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
491                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
492                                 (unsigned int)name_type ));
493
494                 return local_sid_to_gid(pgid, psid, sidtype);
495         }
496
497         *sidtype = name_type;
498
499         /*
500          * Get the gid for this SID.
501          */
502
503         if (!winbind_sid_to_gid(pgid, psid)) {
504                 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
505                                 sid_to_string(sid_str, psid) ));
506                 return False;
507         }
508
509         DEBUG(10,("gid_to_uid: winbindd %s -> %u\n",
510                 sid_to_string(sid_str, psid),
511                 (unsigned int)*pgid ));
512
513         return True;
514 }
515
516 #undef OLD_NTDOMAIN