Start to tidy-up check_user_ok().
[Samba/gebeck_regimport.git] / source3 / smbd / uid.c
blob2aa9fff34bb998b87049edb0db57bc51b8a654d7
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"
29 /* what user is current? */
30 extern struct current_user current_user;
32 /****************************************************************************
33 Become the guest user without changing the security context stack.
34 ****************************************************************************/
36 bool change_to_guest(void)
38 struct passwd *pass;
40 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
41 if (!pass) {
42 return false;
45 #ifdef AIX
46 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
47 setting IDs */
48 initgroups(pass->pw_name, pass->pw_gid);
49 #endif
51 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
53 current_user.conn = NULL;
54 current_user.vuid = UID_FIELD_INVALID;
56 TALLOC_FREE(pass);
58 return true;
61 /****************************************************************************
62 talloc free the conn->session_info if not used in the vuid cache.
63 ****************************************************************************/
65 static void free_conn_session_info_if_unused(connection_struct *conn)
67 unsigned int i;
69 for (i = 0; i < VUID_CACHE_SIZE; i++) {
70 struct vuid_cache_entry *ent;
71 ent = &conn->vuid_cache.array[i];
72 if (ent->vuid != UID_FIELD_INVALID &&
73 conn->session_info == ent->session_info) {
74 return;
77 /* Not used, safe to free. */
78 TALLOC_FREE(conn->session_info);
81 /*******************************************************************
82 Check if a username is OK.
84 This sets up conn->session_info with a copy related to this vuser that
85 later code can then mess with.
86 ********************************************************************/
88 static bool check_user_ok(connection_struct *conn,
89 uint64_t vuid,
90 const struct auth_session_info *session_info,
91 int snum)
93 unsigned int i;
94 bool readonly_share;
95 bool admin_user;
98 struct vuid_cache_entry *ent;
100 for (i=0; i<VUID_CACHE_SIZE; i++) {
101 ent = &conn->vuid_cache.array[i];
102 if (ent->vuid == vuid) {
103 free_conn_session_info_if_unused(conn);
104 conn->session_info = ent->session_info;
105 conn->read_only = ent->read_only;
106 return(True);
111 if (!user_ok_token(session_info->unix_info->unix_name,
112 session_info->info->domain_name,
113 session_info->security_token, snum))
114 return(False);
116 readonly_share = is_share_read_only_for_token(
117 session_info->unix_info->unix_name,
118 session_info->info->domain_name,
119 session_info->security_token,
120 conn);
122 if (!readonly_share &&
123 !share_access_check(session_info->security_token,
124 lp_servicename(talloc_tos(), snum),
125 FILE_WRITE_DATA,
126 NULL)) {
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,
135 lp_servicename(talloc_tos(), snum),
136 readonly_share ?
137 FILE_READ_DATA : FILE_WRITE_DATA,
138 NULL)) {
139 return False;
142 admin_user = token_contains_name_in_list(
143 session_info->unix_info->unix_name,
144 session_info->info->domain_name,
145 NULL, session_info->security_token, lp_admin_users(snum));
148 struct vuid_cache_entry *ent =
149 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
151 conn->vuid_cache.next_entry =
152 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
154 TALLOC_FREE(ent->session_info);
157 * If force_user was set, all session_info's are based on the same
158 * username-based faked one.
161 ent->session_info = copy_session_info(
162 conn, conn->force_user ? conn->session_info : session_info);
164 if (ent->session_info == NULL) {
165 ent->vuid = UID_FIELD_INVALID;
166 return false;
169 ent->vuid = vuid;
170 ent->read_only = readonly_share;
171 free_conn_session_info_if_unused(conn);
172 conn->session_info = ent->session_info;
175 conn->read_only = readonly_share;
176 if (admin_user) {
177 DEBUG(2,("check_user_ok: user %s is an admin user. "
178 "Setting uid as %d\n",
179 conn->session_info->unix_info->unix_name,
180 sec_initial_uid() ));
181 conn->session_info->unix_token->uid = sec_initial_uid();
184 return(True);
187 /****************************************************************************
188 Become the user of a connection number without changing the security context
189 stack, but modify the current_user entries.
190 ****************************************************************************/
192 static bool change_to_user_internal(connection_struct *conn,
193 const struct auth_session_info *session_info,
194 uint64_t vuid)
196 int snum;
197 gid_t gid;
198 uid_t uid;
199 char group_c;
200 int num_groups = 0;
201 gid_t *group_list = NULL;
202 bool ok;
204 snum = SNUM(conn);
206 ok = check_user_ok(conn, vuid, session_info, snum);
207 if (!ok) {
208 DEBUG(2,("SMB user %s (unix user %s) "
209 "not permitted access to share %s.\n",
210 session_info->unix_info->sanitized_username,
211 session_info->unix_info->unix_name,
212 lp_servicename(talloc_tos(), snum)));
213 return false;
216 uid = conn->session_info->unix_token->uid;
217 gid = conn->session_info->unix_token->gid;
218 num_groups = conn->session_info->unix_token->ngroups;
219 group_list = conn->session_info->unix_token->groups;
222 * See if we should force group for this service. If so this overrides
223 * any group set in the force user code.
225 if((group_c = *lp_force_group(talloc_tos(), snum))) {
227 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
229 if (group_c == '+') {
230 int i;
233 * Only force group if the user is a member of the
234 * service group. Check the group memberships for this
235 * user (we already have this) to see if we should force
236 * the group.
238 for (i = 0; i < num_groups; i++) {
239 if (group_list[i] == conn->force_group_gid) {
240 conn->session_info->unix_token->gid =
241 conn->force_group_gid;
242 gid = conn->force_group_gid;
243 gid_to_sid(&conn->session_info->security_token
244 ->sids[1], gid);
245 break;
248 } else {
249 conn->session_info->unix_token->gid = conn->force_group_gid;
250 gid = conn->force_group_gid;
251 gid_to_sid(&conn->session_info->security_token->sids[1],
252 gid);
256 /*Set current_user since we will immediately also call set_sec_ctx() */
257 current_user.ut.ngroups = num_groups;
258 current_user.ut.groups = group_list;
260 set_sec_ctx(uid,
261 gid,
262 current_user.ut.ngroups,
263 current_user.ut.groups,
264 conn->session_info->security_token);
266 current_user.conn = conn;
267 current_user.vuid = vuid;
269 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
270 (int)getuid(),
271 (int)geteuid(),
272 (int)getgid(),
273 (int)getegid()));
275 return true;
278 bool change_to_user(connection_struct *conn, uint64_t vuid)
280 const struct auth_session_info *session_info = NULL;
281 struct user_struct *vuser;
282 int snum = SNUM(conn);
284 if (!conn) {
285 DEBUG(2,("Connection not open\n"));
286 return(False);
289 vuser = get_valid_user_struct(conn->sconn, vuid);
291 if ((current_user.conn == conn) &&
292 (vuser != NULL) && (current_user.vuid == vuid) &&
293 (current_user.ut.uid == vuser->session_info->unix_token->uid)) {
294 DEBUG(4,("Skipping user change - already "
295 "user\n"));
296 return(True);
299 if (vuser == NULL) {
300 /* Invalid vuid sent */
301 DEBUG(2,("Invalid vuid %llu used on share %s.\n",
302 (unsigned long long)vuid, lp_servicename(talloc_tos(),
303 snum)));
304 return false;
307 session_info = vuser->session_info;
309 if (!conn->force_user && vuser == NULL) {
310 DEBUG(2,("Invalid vuid used %llu in accessing share %s.\n",
311 (unsigned long long)vuid,
312 lp_servicename(talloc_tos(), snum)));
313 return False;
316 return change_to_user_internal(conn, session_info, vuid);
319 static bool change_to_user_by_session(connection_struct *conn,
320 const struct auth_session_info *session_info)
322 SMB_ASSERT(conn != NULL);
323 SMB_ASSERT(session_info != NULL);
325 if ((current_user.conn == conn) &&
326 (current_user.ut.uid == session_info->unix_token->uid)) {
327 DEBUG(7, ("Skipping user change - already user\n"));
329 return true;
332 return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
335 /****************************************************************************
336 Go back to being root without changing the security context stack,
337 but modify the current_user entries.
338 ****************************************************************************/
340 bool smbd_change_to_root_user(void)
342 set_root_sec_ctx();
344 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
345 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
347 current_user.conn = NULL;
348 current_user.vuid = UID_FIELD_INVALID;
350 return(True);
353 /****************************************************************************
354 Become the user of an authenticated connected named pipe.
355 When this is called we are currently running as the connection
356 user. Doesn't modify current_user.
357 ****************************************************************************/
359 bool become_authenticated_pipe_user(struct auth_session_info *session_info)
361 if (!push_sec_ctx())
362 return False;
364 set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
365 session_info->unix_token->ngroups, session_info->unix_token->groups,
366 session_info->security_token);
368 return True;
371 /****************************************************************************
372 Unbecome the user of an authenticated connected named pipe.
373 When this is called we are running as the authenticated pipe
374 user and need to go back to being the connection user. Doesn't modify
375 current_user.
376 ****************************************************************************/
378 bool unbecome_authenticated_pipe_user(void)
380 return pop_sec_ctx();
383 /****************************************************************************
384 Utility functions used by become_xxx/unbecome_xxx.
385 ****************************************************************************/
387 static void push_conn_ctx(void)
389 struct conn_ctx *ctx_p;
391 /* Check we don't overflow our stack */
393 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
394 DEBUG(0, ("Connection context stack overflow!\n"));
395 smb_panic("Connection context stack overflow!\n");
398 /* Store previous user context */
399 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
401 ctx_p->conn = current_user.conn;
402 ctx_p->vuid = current_user.vuid;
404 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
405 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
407 conn_ctx_stack_ndx++;
410 static void pop_conn_ctx(void)
412 struct conn_ctx *ctx_p;
414 /* Check for stack underflow. */
416 if (conn_ctx_stack_ndx == 0) {
417 DEBUG(0, ("Connection context stack underflow!\n"));
418 smb_panic("Connection context stack underflow!\n");
421 conn_ctx_stack_ndx--;
422 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
424 current_user.conn = ctx_p->conn;
425 current_user.vuid = ctx_p->vuid;
427 ctx_p->conn = NULL;
428 ctx_p->vuid = UID_FIELD_INVALID;
431 /****************************************************************************
432 Temporarily become a root user. Must match with unbecome_root(). Saves and
433 restores the connection context.
434 ****************************************************************************/
436 void smbd_become_root(void)
439 * no good way to handle push_sec_ctx() failing without changing
440 * the prototype of become_root()
442 if (!push_sec_ctx()) {
443 smb_panic("become_root: push_sec_ctx failed");
445 push_conn_ctx();
446 set_root_sec_ctx();
449 /* Unbecome the root user */
451 void smbd_unbecome_root(void)
453 pop_sec_ctx();
454 pop_conn_ctx();
457 /****************************************************************************
458 Push the current security context then force a change via change_to_user().
459 Saves and restores the connection context.
460 ****************************************************************************/
462 bool become_user(connection_struct *conn, uint64_t vuid)
464 if (!push_sec_ctx())
465 return False;
467 push_conn_ctx();
469 if (!change_to_user(conn, vuid)) {
470 pop_sec_ctx();
471 pop_conn_ctx();
472 return False;
475 return True;
478 bool become_user_by_session(connection_struct *conn,
479 const struct auth_session_info *session_info)
481 if (!push_sec_ctx())
482 return false;
484 push_conn_ctx();
486 if (!change_to_user_by_session(conn, session_info)) {
487 pop_sec_ctx();
488 pop_conn_ctx();
489 return false;
492 return true;
495 bool unbecome_user(void)
497 pop_sec_ctx();
498 pop_conn_ctx();
499 return True;
502 /****************************************************************************
503 Return the current user we are running effectively as on this connection.
504 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
505 doesn't alter this value.
506 ****************************************************************************/
508 uid_t get_current_uid(connection_struct *conn)
510 return current_user.ut.uid;
513 /****************************************************************************
514 Return the current group we are running effectively as on this connection.
515 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
516 doesn't alter this value.
517 ****************************************************************************/
519 gid_t get_current_gid(connection_struct *conn)
521 return current_user.ut.gid;
524 /****************************************************************************
525 Return the UNIX token we are running effectively as on this connection.
526 I'd like to make this return &conn->session_info->unix_token-> but become_root()
527 doesn't alter this value.
528 ****************************************************************************/
530 const struct security_unix_token *get_current_utok(connection_struct *conn)
532 return &current_user.ut;
535 /****************************************************************************
536 Return the Windows token we are running effectively as on this connection.
537 If this is currently a NULL token as we're inside become_root() - a temporary
538 UNIX security override, then we search up the stack for the previous active
539 token.
540 ****************************************************************************/
542 const struct security_token *get_current_nttok(connection_struct *conn)
544 if (current_user.nt_user_token) {
545 return current_user.nt_user_token;
547 return sec_ctx_active_token();
550 uint64_t get_current_vuid(connection_struct *conn)
552 return current_user.vuid;