libsmbconf: Convert smbconf_set_parameter() to sbcErr.
[Samba.git] / source3 / smbd / uid.c
blobb554b36054b9573e71db8a66fe76cd7afb9ce821
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/passwd.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
27 #include "auth.h"
28 #include "ntdomain.h"
30 /* what user is current? */
31 extern struct current_user current_user;
33 /****************************************************************************
34 Become the guest user without changing the security context stack.
35 ****************************************************************************/
37 bool change_to_guest(void)
39 struct passwd *pass;
41 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
42 if (!pass) {
43 return false;
46 #ifdef AIX
47 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
48 setting IDs */
49 initgroups(pass->pw_name, pass->pw_gid);
50 #endif
52 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
54 current_user.conn = NULL;
55 current_user.vuid = UID_FIELD_INVALID;
57 TALLOC_FREE(pass);
59 return true;
62 /****************************************************************************
63 talloc free the conn->session_info if not used in the vuid cache.
64 ****************************************************************************/
66 static void free_conn_session_info_if_unused(connection_struct *conn)
68 unsigned int i;
70 for (i = 0; i < VUID_CACHE_SIZE; i++) {
71 struct vuid_cache_entry *ent;
72 ent = &conn->vuid_cache.array[i];
73 if (ent->vuid != UID_FIELD_INVALID &&
74 conn->session_info == ent->session_info) {
75 return;
78 /* Not used, safe to free. */
79 TALLOC_FREE(conn->session_info);
82 /*******************************************************************
83 Check if a username is OK.
85 This sets up conn->session_info with a copy related to this vuser that
86 later code can then mess with.
87 ********************************************************************/
89 static bool check_user_ok(connection_struct *conn,
90 uint16_t vuid,
91 const struct auth_serversupplied_info *session_info,
92 int snum)
94 bool valid_vuid = (vuid != UID_FIELD_INVALID);
95 unsigned int i;
96 bool readonly_share;
97 bool admin_user;
99 if (valid_vuid) {
100 struct vuid_cache_entry *ent;
102 for (i=0; i<VUID_CACHE_SIZE; i++) {
103 ent = &conn->vuid_cache.array[i];
104 if (ent->vuid == vuid) {
105 free_conn_session_info_if_unused(conn);
106 conn->session_info = ent->session_info;
107 conn->read_only = ent->read_only;
108 return(True);
113 if (!user_ok_token(session_info->unix_name,
114 session_info->info3->base.domain.string,
115 session_info->security_token, snum))
116 return(False);
118 readonly_share = is_share_read_only_for_token(
119 session_info->unix_name,
120 session_info->info3->base.domain.string,
121 session_info->security_token,
122 conn);
124 if (!readonly_share &&
125 !share_access_check(session_info->security_token, lp_servicename(snum),
126 FILE_WRITE_DATA)) {
127 /* smb.conf allows r/w, but the security descriptor denies
128 * write. Fall back to looking at readonly. */
129 readonly_share = True;
130 DEBUG(5,("falling back to read-only access-evaluation due to "
131 "security descriptor\n"));
134 if (!share_access_check(session_info->security_token, lp_servicename(snum),
135 readonly_share ?
136 FILE_READ_DATA : FILE_WRITE_DATA)) {
137 return False;
140 admin_user = token_contains_name_in_list(
141 session_info->unix_name,
142 session_info->info3->base.domain.string,
143 NULL, session_info->security_token, lp_admin_users(snum));
145 if (valid_vuid) {
146 struct vuid_cache_entry *ent =
147 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
149 conn->vuid_cache.next_entry =
150 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
152 TALLOC_FREE(ent->session_info);
155 * If force_user was set, all session_info's are based on the same
156 * username-based faked one.
159 ent->session_info = copy_serverinfo(
160 conn, conn->force_user ? conn->session_info : session_info);
162 if (ent->session_info == NULL) {
163 ent->vuid = UID_FIELD_INVALID;
164 return false;
167 ent->vuid = vuid;
168 ent->read_only = readonly_share;
169 free_conn_session_info_if_unused(conn);
170 conn->session_info = ent->session_info;
173 conn->read_only = readonly_share;
174 if (admin_user) {
175 DEBUG(2,("check_user_ok: user %s is an admin user. "
176 "Setting uid as %d\n",
177 conn->session_info->unix_name,
178 sec_initial_uid() ));
179 conn->session_info->utok.uid = sec_initial_uid();
182 return(True);
185 /****************************************************************************
186 Clear a vuid out of the connection's vuid cache
187 This is only called on SMBulogoff.
188 ****************************************************************************/
190 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
192 int i;
194 for (i=0; i<VUID_CACHE_SIZE; i++) {
195 struct vuid_cache_entry *ent;
197 ent = &conn->vuid_cache.array[i];
199 if (ent->vuid == vuid) {
200 ent->vuid = UID_FIELD_INVALID;
202 * We need to keep conn->session_info around
203 * if it's equal to ent->session_info as a SMBulogoff
204 * is often followed by a SMBtdis (with an invalid
205 * vuid). The debug code (or regular code in
206 * vfs_full_audit) wants to refer to the
207 * conn->session_info pointer to print debug
208 * statements. Theoretically this is a bug,
209 * as once the vuid is gone the session_info
210 * on the conn struct isn't valid any more,
211 * but there's enough code that assumes
212 * conn->session_info is never null that
213 * it's easier to hold onto the old pointer
214 * until we get a new sessionsetupX.
215 * As everything is hung off the
216 * conn pointer as a talloc context we're not
217 * leaking memory here. See bug #6315. JRA.
219 if (conn->session_info == ent->session_info) {
220 ent->session_info = NULL;
221 } else {
222 TALLOC_FREE(ent->session_info);
224 ent->read_only = False;
229 /****************************************************************************
230 Become the user of a connection number without changing the security context
231 stack, but modify the current_user entries.
232 ****************************************************************************/
234 static bool change_to_user_internal(connection_struct *conn,
235 const struct auth_serversupplied_info *session_info,
236 uint16_t vuid)
238 int snum;
239 gid_t gid;
240 uid_t uid;
241 char group_c;
242 int num_groups = 0;
243 gid_t *group_list = NULL;
244 bool ok;
246 snum = SNUM(conn);
248 ok = check_user_ok(conn, vuid, session_info, snum);
249 if (!ok) {
250 DEBUG(2,("SMB user %s (unix user %s) "
251 "not permitted access to share %s.\n",
252 session_info->sanitized_username,
253 session_info->unix_name,
254 lp_servicename(snum)));
255 return false;
258 uid = conn->session_info->utok.uid;
259 gid = conn->session_info->utok.gid;
260 num_groups = conn->session_info->utok.ngroups;
261 group_list = conn->session_info->utok.groups;
264 * See if we should force group for this service. If so this overrides
265 * any group set in the force user code.
267 if((group_c = *lp_force_group(snum))) {
269 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
271 if (group_c == '+') {
272 int i;
275 * Only force group if the user is a member of the
276 * service group. Check the group memberships for this
277 * user (we already have this) to see if we should force
278 * the group.
280 for (i = 0; i < num_groups; i++) {
281 if (group_list[i] == conn->force_group_gid) {
282 conn->session_info->utok.gid =
283 conn->force_group_gid;
284 gid = conn->force_group_gid;
285 gid_to_sid(&conn->session_info->security_token
286 ->sids[1], gid);
287 break;
290 } else {
291 conn->session_info->utok.gid = conn->force_group_gid;
292 gid = conn->force_group_gid;
293 gid_to_sid(&conn->session_info->security_token->sids[1],
294 gid);
298 /*Set current_user since we will immediately also call set_sec_ctx() */
299 current_user.ut.ngroups = num_groups;
300 current_user.ut.groups = group_list;
302 set_sec_ctx(uid,
303 gid,
304 current_user.ut.ngroups,
305 current_user.ut.groups,
306 conn->session_info->security_token);
308 current_user.conn = conn;
309 current_user.vuid = vuid;
311 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
312 (int)getuid(),
313 (int)geteuid(),
314 (int)getgid(),
315 (int)getegid()));
317 return true;
320 bool change_to_user(connection_struct *conn, uint16_t vuid)
322 const struct auth_serversupplied_info *session_info = NULL;
323 user_struct *vuser;
324 int snum = SNUM(conn);
326 if (!conn) {
327 DEBUG(2,("Connection not open\n"));
328 return(False);
331 vuser = get_valid_user_struct(conn->sconn, vuid);
334 * We need a separate check in security=share mode due to vuid
335 * always being UID_FIELD_INVALID. If we don't do this then
336 * in share mode security we are *always* changing uid's between
337 * SMB's - this hurts performance - Badly.
340 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
341 (current_user.ut.uid == conn->session_info->utok.uid)) {
342 DEBUG(4,("Skipping user change - already "
343 "user\n"));
344 return(True);
345 } else if ((current_user.conn == conn) &&
346 (vuser != NULL) && (current_user.vuid == vuid) &&
347 (current_user.ut.uid == vuser->session_info->utok.uid)) {
348 DEBUG(4,("Skipping user change - already "
349 "user\n"));
350 return(True);
353 session_info = vuser ? vuser->session_info : conn->session_info;
355 if (session_info == NULL) {
356 /* Invalid vuid sent - even with security = share. */
357 DEBUG(2,("Invalid vuid %d used on "
358 "share %s.\n", vuid, lp_servicename(snum) ));
359 return false;
362 /* security = share sets force_user. */
363 if (!conn->force_user && vuser == NULL) {
364 DEBUG(2,("Invalid vuid used %d in accessing "
365 "share %s.\n", vuid, lp_servicename(snum) ));
366 return False;
369 return change_to_user_internal(conn, session_info, vuid);
372 bool change_to_user_by_session(connection_struct *conn,
373 const struct auth_serversupplied_info *session_info)
375 SMB_ASSERT(conn != NULL);
376 SMB_ASSERT(session_info != NULL);
378 if ((current_user.conn == conn) &&
379 (current_user.ut.uid == session_info->utok.uid)) {
380 DEBUG(7, ("Skipping user change - already user\n"));
382 return true;
385 return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
388 /****************************************************************************
389 Go back to being root without changing the security context stack,
390 but modify the current_user entries.
391 ****************************************************************************/
393 bool change_to_root_user(void)
395 set_root_sec_ctx();
397 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
398 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
400 current_user.conn = NULL;
401 current_user.vuid = UID_FIELD_INVALID;
403 return(True);
406 /****************************************************************************
407 Become the user of an authenticated connected named pipe.
408 When this is called we are currently running as the connection
409 user. Doesn't modify current_user.
410 ****************************************************************************/
412 bool become_authenticated_pipe_user(struct pipes_struct *p)
414 if (!push_sec_ctx())
415 return False;
417 set_sec_ctx(p->session_info->utok.uid, p->session_info->utok.gid,
418 p->session_info->utok.ngroups, p->session_info->utok.groups,
419 p->session_info->security_token);
421 return True;
424 /****************************************************************************
425 Unbecome the user of an authenticated connected named pipe.
426 When this is called we are running as the authenticated pipe
427 user and need to go back to being the connection user. Doesn't modify
428 current_user.
429 ****************************************************************************/
431 bool unbecome_authenticated_pipe_user(void)
433 return pop_sec_ctx();
436 /****************************************************************************
437 Utility functions used by become_xxx/unbecome_xxx.
438 ****************************************************************************/
440 static void push_conn_ctx(void)
442 struct conn_ctx *ctx_p;
444 /* Check we don't overflow our stack */
446 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
447 DEBUG(0, ("Connection context stack overflow!\n"));
448 smb_panic("Connection context stack overflow!\n");
451 /* Store previous user context */
452 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
454 ctx_p->conn = current_user.conn;
455 ctx_p->vuid = current_user.vuid;
457 DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
458 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
460 conn_ctx_stack_ndx++;
463 static void pop_conn_ctx(void)
465 struct conn_ctx *ctx_p;
467 /* Check for stack underflow. */
469 if (conn_ctx_stack_ndx == 0) {
470 DEBUG(0, ("Connection context stack underflow!\n"));
471 smb_panic("Connection context stack underflow!\n");
474 conn_ctx_stack_ndx--;
475 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
477 current_user.conn = ctx_p->conn;
478 current_user.vuid = ctx_p->vuid;
480 ctx_p->conn = NULL;
481 ctx_p->vuid = UID_FIELD_INVALID;
484 /****************************************************************************
485 Temporarily become a root user. Must match with unbecome_root(). Saves and
486 restores the connection context.
487 ****************************************************************************/
489 void become_root(void)
492 * no good way to handle push_sec_ctx() failing without changing
493 * the prototype of become_root()
495 if (!push_sec_ctx()) {
496 smb_panic("become_root: push_sec_ctx failed");
498 push_conn_ctx();
499 set_root_sec_ctx();
502 /* Unbecome the root user */
504 void unbecome_root(void)
506 pop_sec_ctx();
507 pop_conn_ctx();
510 /****************************************************************************
511 Push the current security context then force a change via change_to_user().
512 Saves and restores the connection context.
513 ****************************************************************************/
515 bool become_user(connection_struct *conn, uint16 vuid)
517 if (!push_sec_ctx())
518 return False;
520 push_conn_ctx();
522 if (!change_to_user(conn, vuid)) {
523 pop_sec_ctx();
524 pop_conn_ctx();
525 return False;
528 return True;
531 bool become_user_by_session(connection_struct *conn,
532 const struct auth_serversupplied_info *session_info)
534 if (!push_sec_ctx())
535 return false;
537 push_conn_ctx();
539 if (!change_to_user_by_session(conn, session_info)) {
540 pop_sec_ctx();
541 pop_conn_ctx();
542 return false;
545 return true;
548 bool unbecome_user(void)
550 pop_sec_ctx();
551 pop_conn_ctx();
552 return True;
555 /****************************************************************************
556 Return the current user we are running effectively as on this connection.
557 I'd like to make this return conn->session_info->utok.uid, but become_root()
558 doesn't alter this value.
559 ****************************************************************************/
561 uid_t get_current_uid(connection_struct *conn)
563 return current_user.ut.uid;
566 /****************************************************************************
567 Return the current group we are running effectively as on this connection.
568 I'd like to make this return conn->session_info->utok.gid, but become_root()
569 doesn't alter this value.
570 ****************************************************************************/
572 gid_t get_current_gid(connection_struct *conn)
574 return current_user.ut.gid;
577 /****************************************************************************
578 Return the UNIX token we are running effectively as on this connection.
579 I'd like to make this return &conn->session_info->utok, but become_root()
580 doesn't alter this value.
581 ****************************************************************************/
583 const struct security_unix_token *get_current_utok(connection_struct *conn)
585 return &current_user.ut;
588 const struct security_token *get_current_nttok(connection_struct *conn)
590 return current_user.nt_user_token;
593 uint16_t get_current_vuid(connection_struct *conn)
595 return current_user.vuid;