Large commit which restructures the local password storage API.
[Samba.git] / source / smbd / uid.c
blobd82edcbfae097a220173ed208ea7016c64c618fd
1 #define OLD_NTDOMAIN 1
3 /*
4 Unix SMB/Netbios implementation.
5 Version 1.9.
6 uid/user handling
7 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
24 #include "includes.h"
26 extern int DEBUGLEVEL;
28 /* what user is current? */
29 extern struct current_user current_user;
31 /****************************************************************************
32 Become the guest user.
33 ****************************************************************************/
35 BOOL become_guest(void)
37 static struct passwd *pass=NULL;
39 if (!pass)
40 pass = Get_Pwnam(lp_guestaccount(-1),True);
41 if (!pass)
42 return(False);
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
50 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
52 current_user.conn = NULL;
53 current_user.vuid = UID_FIELD_INVALID;
55 return True;
58 /*******************************************************************
59 Check if a username is OK.
60 ********************************************************************/
62 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
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);
69 if (!user_ok(vuser->user.unix_name,snum))
70 return(False);
72 i = conn->uid_cache.entries % UID_CACHE_SIZE;
73 conn->uid_cache.list[i] = vuser->uid;
75 if (conn->uid_cache.entries < UID_CACHE_SIZE)
76 conn->uid_cache.entries++;
78 return(True);
81 /****************************************************************************
82 Become the user of a connection number.
83 ****************************************************************************/
85 BOOL become_user(connection_struct *conn, uint16 vuid)
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;
95 if (!conn) {
96 DEBUG(2,("Connection not open\n"));
97 return(False);
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.
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);
118 snum = SNUM(conn);
120 if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
121 return False;
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);
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;
145 * See if we should force group for this service.
146 * If so this overrides any group set in the force
147 * user code.
150 if((group_c = *lp_force_group(snum))) {
151 if(group_c == '+') {
154 * Only force group if the user is a member of
155 * the service group. Check the group memberships for
156 * this user (we already have this) to
157 * see if we should force the group.
160 int i;
161 for (i = 0; i < current_user.ngroups; i++) {
162 if (current_user.groups[i] == conn->gid) {
163 gid = conn->gid;
164 break;
167 } else {
168 gid = conn->gid;
172 * We've changed the group list in the token - we must
173 * re-create it.
176 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups);
177 must_free_token = True;
180 set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
183 * Free the new token (as set_sec_ctx copies it).
186 if (must_free_token)
187 delete_nt_token(&token);
189 current_user.conn = conn;
190 current_user.vuid = vuid;
192 DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
193 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
195 return(True);
198 /****************************************************************************
199 Unbecome the user of a connection number.
200 ****************************************************************************/
202 BOOL unbecome_user(void )
204 set_root_sec_ctx();
206 DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
207 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
209 current_user.conn = NULL;
210 current_user.vuid = UID_FIELD_INVALID;
212 return(True);
215 /****************************************************************************
216 Become the user of an authenticated connected named pipe.
217 When this is called we are currently running as the connection
218 user.
219 ****************************************************************************/
221 BOOL become_authenticated_pipe_user(pipes_struct *p)
223 BOOL res = push_sec_ctx();
225 if (!res) {
226 return False;
229 set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid,
230 p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
232 return True;
235 /****************************************************************************
236 Unbecome the user of an authenticated connected named pipe.
237 When this is called we are running as the authenticated pipe
238 user and need to go back to being the connection user.
239 ****************************************************************************/
241 BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
243 return pop_sec_ctx();
247 /* Temporarily become a root user. Must match with unbecome_root(). */
248 void become_root(void)
250 push_sec_ctx();
251 set_root_sec_ctx();
254 /* Unbecome the root user */
256 void unbecome_root(void)
258 pop_sec_ctx();
261 /*****************************************************************
262 *THE CANONICAL* convert name to SID function.
263 Tries winbind first - then uses local lookup.
264 *****************************************************************/
266 BOOL lookup_name(char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
268 extern pstring global_myname;
269 fstring sid;
271 if (!winbind_lookup_name(name, psid, name_type)) {
272 BOOL ret;
274 DEBUG(10,("lookup_name: winbind lookup for %s failed - trying local\n", name ));
276 ret = local_lookup_name(global_myname, name, psid, name_type);
277 if (ret)
278 DEBUG(10,("lookup_name : (local) %s -> SID %s (type %u)\n",
279 name, sid_to_string(sid,psid),
280 (unsigned int)*name_type ));
281 else
282 DEBUG(10,("lookup name : (local) %s failed.\n",
283 name ));
284 return ret;
287 DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
288 name, sid_to_string(sid,psid), (unsigned int)*name_type ));
289 return True;
292 /*****************************************************************
293 *THE CANONICAL* convert SID to name function.
294 Tries winbind first - then uses local lookup.
295 *****************************************************************/
297 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
299 if (!name_type)
300 return False;
302 /* Check if this is our own sid. This should perhaps be done by
303 winbind? For the moment handle it here. */
305 if (sid->num_auths == 5) {
306 DOM_SID tmp_sid;
307 uint32 rid;
309 sid_copy(&tmp_sid, sid);
310 sid_split_rid(&tmp_sid, &rid);
312 if (sid_equal(&global_sam_sid, &tmp_sid)) {
314 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
315 local_lookup_rid(rid, name, name_type);
319 if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
320 fstring sid_str;
321 DOM_SID tmp_sid;
322 uint32 rid;
324 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
326 sid_copy(&tmp_sid, sid);
327 sid_split_rid(&tmp_sid, &rid);
328 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
329 lookup_known_rid(&tmp_sid, rid, name, name_type);
331 return True;
334 /*****************************************************************
335 *THE CANONICAL* convert uid_t to SID function.
336 Tries winbind first - then uses local lookup.
337 Returns SID pointer.
338 *****************************************************************/
340 DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
342 fstring sid;
344 if (!winbind_uid_to_sid(psid, uid)) {
345 DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid ));
347 return local_uid_to_sid(psid, uid);
350 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
351 (unsigned int)uid, sid_to_string(sid, psid) ));
353 return psid;
356 /*****************************************************************
357 *THE CANONICAL* convert gid_t to SID function.
358 Tries winbind first - then uses local lookup.
359 Returns SID pointer.
360 *****************************************************************/
362 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
364 fstring sid;
366 if (!winbind_gid_to_sid(psid, gid)) {
367 DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid ));
369 return local_gid_to_sid(psid, gid);
372 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
373 (unsigned int)gid, sid_to_string(sid,psid) ));
375 return psid;
378 /*****************************************************************
379 *THE CANONICAL* convert SID to uid function.
380 Tries winbind first - then uses local lookup.
381 Returns True if this name is a user sid and the conversion
382 was done correctly, False if not.
383 *****************************************************************/
385 BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
387 fstring dom_name, name, sid_str;
388 enum SID_NAME_USE name_type;
390 *sidtype = SID_NAME_UNKNOWN;
393 * First we must look up the name and decide if this is a user sid.
396 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
397 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
398 sid_to_string(sid_str, psid) ));
400 return local_sid_to_uid(puid, psid, sidtype);
404 * Ensure this is a user sid.
407 if (name_type != SID_NAME_USER) {
408 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
409 (unsigned int)name_type ));
410 return False;
413 *sidtype = SID_NAME_USER;
416 * Get the uid for this SID.
419 if (!winbind_sid_to_uid(puid, psid)) {
420 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
421 sid_to_string(sid_str, psid) ));
422 return False;
425 DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
426 sid_to_string(sid_str, psid),
427 (unsigned int)*puid ));
429 return True;
432 /*****************************************************************
433 *THE CANONICAL* convert SID to gid function.
434 Tries winbind first - then uses local lookup.
435 Returns True if this name is a user sid and the conversion
436 was done correctly, False if not.
437 *****************************************************************/
439 BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
441 fstring dom_name, name, sid_str;
442 enum SID_NAME_USE name_type;
444 *sidtype = SID_NAME_UNKNOWN;
447 * First we must look up the name and decide if this is a group sid.
450 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
451 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
452 sid_to_string(sid_str, psid) ));
454 return local_sid_to_gid(pgid, psid, sidtype);
458 * Ensure this is a group sid.
461 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
462 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a know group (%u)\n",
463 (unsigned int)name_type ));
465 return local_sid_to_gid(pgid, psid, sidtype);
468 *sidtype = name_type;
471 * Get the gid for this SID.
474 if (!winbind_sid_to_gid(pgid, psid)) {
475 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
476 sid_to_string(sid_str, psid) ));
477 return False;
480 DEBUG(10,("gid_to_uid: winbindd %s -> %u\n",
481 sid_to_string(sid_str, psid),
482 (unsigned int)*pgid ));
484 return True;
487 #undef OLD_NTDOMAIN