1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
5
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.
10
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.
15
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/>.
18 */
19
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 "../auth/auth_util.h"
29
30 /* what user is current? */
31 extern struct current_user current_user;
32
33 /****************************************************************************
34 Become the guest user without changing the security context stack.
35 ****************************************************************************/
36
change_to_guest(void)37 bool change_to_guest(void)
38 {
39 struct passwd *pass;
40
41 pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
42 if (!pass) {
43 return false;
44 }
45
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
51
52 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
53
54 current_user.conn = NULL;
55 current_user.vuid = UID_FIELD_INVALID;
56
57 TALLOC_FREE(pass);
58
59 return true;
60 }
61
62 /****************************************************************************
63 talloc free the conn->session_info if not used in the vuid cache.
64 ****************************************************************************/
65
free_conn_session_info_if_unused(connection_struct * conn)66 static void free_conn_session_info_if_unused(connection_struct *conn)
67 {
68 unsigned int i;
69
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;
76 }
77 }
78 /* Not used, safe to free. */
79 TALLOC_FREE(conn->session_info);
80 }
81
82 /****************************************************************************
83 Setup the share access mask for a connection.
84 ****************************************************************************/
85
create_share_access_mask(int snum,bool readonly_share,const struct security_token * token)86 static uint32_t create_share_access_mask(int snum,
87 bool readonly_share,
88 const struct security_token *token)
89 {
90 uint32_t share_access = 0;
91
92 share_access_check(token,
93 lp_const_servicename(snum),
94 MAXIMUM_ALLOWED_ACCESS,
95 &share_access);
96
97 if (readonly_share) {
98 share_access &=
99 ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
100 SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
101 SEC_DIR_DELETE_CHILD );
102 }
103
104 if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
105 share_access |= SEC_FLAG_SYSTEM_SECURITY;
106 }
107 if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
108 share_access |= SEC_RIGHTS_PRIV_RESTORE;
109 }
110 if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
111 share_access |= SEC_RIGHTS_PRIV_BACKUP;
112 }
113 if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
114 share_access |= SEC_STD_WRITE_OWNER;
115 }
116
117 return share_access;
118 }
119
120 /*******************************************************************
121 Calculate access mask and if this user can access this share.
122 ********************************************************************/
123
check_user_share_access(connection_struct * conn,const struct auth_session_info * session_info,uint32_t * p_share_access,bool * p_readonly_share)124 NTSTATUS check_user_share_access(connection_struct *conn,
125 const struct auth_session_info *session_info,
126 uint32_t *p_share_access,
127 bool *p_readonly_share)
128 {
129 int snum = SNUM(conn);
130 uint32_t share_access = 0;
131 bool readonly_share = false;
132
133 if (!user_ok_token(session_info->unix_info->unix_name,
134 session_info->info->domain_name,
135 session_info->security_token, snum)) {
136 return NT_STATUS_ACCESS_DENIED;
137 }
138
139 readonly_share = is_share_read_only_for_token(
140 session_info->unix_info->unix_name,
141 session_info->info->domain_name,
142 session_info->security_token,
143 conn);
144
145 share_access = create_share_access_mask(snum,
146 readonly_share,
147 session_info->security_token);
148
149 if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
150 /* No access, read or write. */
151 DBG_NOTICE("user %s connection to %s denied due to share "
152 "security descriptor.\n",
153 session_info->unix_info->unix_name,
154 lp_const_servicename(snum));
155 return NT_STATUS_ACCESS_DENIED;
156 }
157
158 if (!readonly_share &&
159 !(share_access & FILE_WRITE_DATA)) {
160 /* smb.conf allows r/w, but the security descriptor denies
161 * write. Fall back to looking at readonly. */
162 readonly_share = true;
163 DBG_INFO("falling back to read-only access-evaluation due to "
164 "security descriptor\n");
165 }
166
167 *p_share_access = share_access;
168 *p_readonly_share = readonly_share;
169
170 return NT_STATUS_OK;
171 }
172
173 /*******************************************************************
174 Check if a username is OK.
175
176 This sets up conn->session_info with a copy related to this vuser that
177 later code can then mess with.
178 ********************************************************************/
179
check_user_ok(connection_struct * conn,uint64_t vuid,const struct auth_session_info * session_info,int snum)180 static bool check_user_ok(connection_struct *conn,
181 uint64_t vuid,
182 const struct auth_session_info *session_info,
183 int snum)
184 {
185 unsigned int i;
186 bool readonly_share = false;
187 bool admin_user = false;
188 struct vuid_cache_entry *ent = NULL;
189 uint32_t share_access = 0;
190 NTSTATUS status;
191
192 for (i=0; i<VUID_CACHE_SIZE; i++) {
193 ent = &conn->vuid_cache->array[i];
194 if (ent->vuid == vuid) {
195 if (vuid == UID_FIELD_INVALID) {
196 /*
197 * Slow path, we don't care
198 * about the array traversal.
199 */
200 continue;
201 }
202 free_conn_session_info_if_unused(conn);
203 conn->session_info = ent->session_info;
204 conn->read_only = ent->read_only;
205 conn->share_access = ent->share_access;
206 conn->vuid = ent->vuid;
207 return(True);
208 }
209 }
210
211 status = check_user_share_access(conn,
212 session_info,
213 &share_access,
214 &readonly_share);
215 if (!NT_STATUS_IS_OK(status)) {
216 return false;
217 }
218
219 admin_user = token_contains_name_in_list(
220 session_info->unix_info->unix_name,
221 session_info->info->domain_name,
222 NULL, session_info->security_token, lp_admin_users(snum));
223
224 ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
225
226 conn->vuid_cache->next_entry =
227 (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
228
229 TALLOC_FREE(ent->session_info);
230
231 /*
232 * If force_user was set, all session_info's are based on the same
233 * username-based faked one.
234 */
235
236 ent->session_info = copy_session_info(
237 conn, conn->force_user ? conn->session_info : session_info);
238
239 if (ent->session_info == NULL) {
240 ent->vuid = UID_FIELD_INVALID;
241 return false;
242 }
243
244 if (admin_user) {
245 DEBUG(2,("check_user_ok: user %s is an admin user. "
246 "Setting uid as %d\n",
247 ent->session_info->unix_info->unix_name,
248 sec_initial_uid() ));
249 ent->session_info->unix_token->uid = sec_initial_uid();
250 }
251
252 /*
253 * It's actually OK to call check_user_ok() with
254 * vuid == UID_FIELD_INVALID as called from become_user_by_session().
255 * All this will do is throw away one entry in the cache.
256 */
257
258 ent->vuid = vuid;
259 ent->read_only = readonly_share;
260 ent->share_access = share_access;
261 free_conn_session_info_if_unused(conn);
262 conn->session_info = ent->session_info;
263 conn->vuid = ent->vuid;
264 if (vuid == UID_FIELD_INVALID) {
265 /*
266 * Not strictly needed, just make it really
267 * clear this entry is actually an unused one.
268 */
269 ent->read_only = false;
270 ent->share_access = 0;
271 ent->session_info = NULL;
272 }
273
274 conn->read_only = readonly_share;
275 conn->share_access = share_access;
276
277 return(True);
278 }
279
print_impersonation_info(connection_struct * conn)280 static void print_impersonation_info(connection_struct *conn)
281 {
282 struct smb_filename *cwdfname = NULL;
283
284 if (!CHECK_DEBUGLVL(DBGLVL_INFO)) {
285 return;
286 }
287
288 cwdfname = vfs_GetWd(talloc_tos(), conn);
289 if (cwdfname == NULL) {
290 return;
291 }
292
293 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
294 (int)getuid(),
295 (int)geteuid(),
296 (int)getgid(),
297 (int)getegid(),
298 cwdfname->base_name);
299 TALLOC_FREE(cwdfname);
300 }
301
302 /****************************************************************************
303 Become the user of a connection number without changing the security context
304 stack, but modify the current_user entries.
305 ****************************************************************************/
306
change_to_user_impersonate(connection_struct * conn,const struct auth_session_info * session_info,uint64_t vuid)307 static bool change_to_user_impersonate(connection_struct *conn,
308 const struct auth_session_info *session_info,
309 uint64_t vuid)
310 {
311 const struct loadparm_substitution *lp_sub =
312 loadparm_s3_global_substitution();
313 int snum;
314 gid_t gid;
315 uid_t uid;
316 const char *force_group_name;
317 char group_c;
318 int num_groups = 0;
319 gid_t *group_list = NULL;
320 bool ok;
321
322 if ((current_user.conn == conn) &&
323 (current_user.vuid == vuid) &&
324 (current_user.ut.uid == session_info->unix_token->uid))
325 {
326 DBG_INFO("Skipping user change - already user\n");
327 return true;
328 }
329
330 set_current_user_info(session_info->unix_info->sanitized_username,
331 session_info->unix_info->unix_name,
332 session_info->info->domain_name);
333
334 snum = SNUM(conn);
335
336 ok = check_user_ok(conn, vuid, session_info, snum);
337 if (!ok) {
338 DBG_WARNING("SMB user %s (unix user %s) "
339 "not permitted access to share %s.\n",
340 session_info->unix_info->sanitized_username,
341 session_info->unix_info->unix_name,
342 lp_const_servicename(snum));
343 return false;
344 }
345
346 uid = conn->session_info->unix_token->uid;
347 gid = conn->session_info->unix_token->gid;
348 num_groups = conn->session_info->unix_token->ngroups;
349 group_list = conn->session_info->unix_token->groups;
350
351 /*
352 * See if we should force group for this service. If so this overrides
353 * any group set in the force user code.
354 */
355 force_group_name = lp_force_group(talloc_tos(), lp_sub, snum);
356 group_c = *force_group_name;
357
358 if ((group_c != '\0') && (conn->force_group_gid == (gid_t)-1)) {
359 /*
360 * This can happen if "force group" is added to a
361 * share definition whilst an existing connection
362 * to that share exists. In that case, don't change
363 * the existing credentials for force group, only
364 * do so for new connections.
365 *
366 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
367 */
368 DBG_INFO("Not forcing group %s on existing connection to "
369 "share %s for SMB user %s (unix user %s)\n",
370 force_group_name,
371 lp_const_servicename(snum),
372 session_info->unix_info->sanitized_username,
373 session_info->unix_info->unix_name);
374 }
375
376 if((group_c != '\0') && (conn->force_group_gid != (gid_t)-1)) {
377 /*
378 * Only force group for connections where
379 * conn->force_group_gid has already been set
380 * to the correct value (i.e. the connection
381 * happened after the 'force group' definition
382 * was added to the share definition. Connections
383 * that were made before force group was added
384 * should stay with their existing credentials.
385 *
386 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
387 */
388
389 if (group_c == '+') {
390 int i;
391
392 /*
393 * Only force group if the user is a member of the
394 * service group. Check the group memberships for this
395 * user (we already have this) to see if we should force
396 * the group.
397 */
398 for (i = 0; i < num_groups; i++) {
399 if (group_list[i] == conn->force_group_gid) {
400 conn->session_info->unix_token->gid =
401 conn->force_group_gid;
402 gid = conn->force_group_gid;
403 gid_to_sid(&conn->session_info->security_token
404 ->sids[1], gid);
405 break;
406 }
407 }
408 } else {
409 conn->session_info->unix_token->gid = conn->force_group_gid;
410 gid = conn->force_group_gid;
411 gid_to_sid(&conn->session_info->security_token->sids[1],
412 gid);
413 }
414 }
415
416 /*Set current_user since we will immediately also call set_sec_ctx() */
417 current_user.ut.ngroups = num_groups;
418 current_user.ut.groups = group_list;
419
420 set_sec_ctx(uid,
421 gid,
422 current_user.ut.ngroups,
423 current_user.ut.groups,
424 conn->session_info->security_token);
425
426 current_user.conn = conn;
427 current_user.vuid = vuid;
428 return true;
429 }
430
431 /**
432 * Impersonate user and change directory to service
433 *
434 * change_to_user_and_service() is used to impersonate the user associated with
435 * the given vuid and to change the working directory of the process to the
436 * service base directory.
437 **/
change_to_user_and_service(connection_struct * conn,uint64_t vuid)438 bool change_to_user_and_service(connection_struct *conn, uint64_t vuid)
439 {
440 int snum = SNUM(conn);
441 struct auth_session_info *si = NULL;
442 NTSTATUS status;
443 bool ok;
444
445 if (conn == NULL) {
446 DBG_WARNING("Connection not open\n");
447 return false;
448 }
449
450 status = smbXsrv_session_info_lookup(conn->sconn->client,
451 vuid,
452 &si);
453 if (!NT_STATUS_IS_OK(status)) {
454 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
455 (unsigned long long)vuid,
456 lp_const_servicename(snum));
457 return false;
458 }
459
460 ok = change_to_user_impersonate(conn, si, vuid);
461 if (!ok) {
462 return false;
463 }
464
465 if (conn->tcon_done) {
466 ok = chdir_current_service(conn);
467 if (!ok) {
468 return false;
469 }
470 }
471
472 print_impersonation_info(conn);
473 return true;
474 }
475
476 /**
477 * Impersonate user and change directory to service
478 *
479 * change_to_user_and_service_by_fsp() is used to impersonate the user
480 * associated with the given vuid and to change the working directory of the
481 * process to the service base directory.
482 **/
change_to_user_and_service_by_fsp(struct files_struct * fsp)483 bool change_to_user_and_service_by_fsp(struct files_struct *fsp)
484 {
485 return change_to_user_and_service(fsp->conn, fsp->vuid);
486 }
487
488 /****************************************************************************
489 Go back to being root without changing the security context stack,
490 but modify the current_user entries.
491 ****************************************************************************/
492
smbd_change_to_root_user(void)493 bool smbd_change_to_root_user(void)
494 {
495 set_root_sec_ctx();
496
497 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
498 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
499
500 current_user.conn = NULL;
501 current_user.vuid = UID_FIELD_INVALID;
502
503 return(True);
504 }
505
506 /****************************************************************************
507 Become the user of an authenticated connected named pipe.
508 When this is called we are currently running as the connection
509 user. Doesn't modify current_user.
510 ****************************************************************************/
511
smbd_become_authenticated_pipe_user(struct auth_session_info * session_info)512 bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
513 {
514 if (!push_sec_ctx())
515 return False;
516
517 set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
518 session_info->unix_token->ngroups, session_info->unix_token->groups,
519 session_info->security_token);
520
521 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
522 (int)getuid(),
523 (int)geteuid(),
524 (int)getgid(),
525 (int)getegid()));
526
527 return True;
528 }
529
530 /****************************************************************************
531 Unbecome the user of an authenticated connected named pipe.
532 When this is called we are running as the authenticated pipe
533 user and need to go back to being the connection user. Doesn't modify
534 current_user.
535 ****************************************************************************/
536
smbd_unbecome_authenticated_pipe_user(void)537 bool smbd_unbecome_authenticated_pipe_user(void)
538 {
539 return pop_sec_ctx();
540 }
541
542 /****************************************************************************
543 Utility functions used by become_xxx/unbecome_xxx.
544 ****************************************************************************/
545
push_conn_ctx(void)546 static void push_conn_ctx(void)
547 {
548 struct conn_ctx *ctx_p;
549 extern userdom_struct current_user_info;
550
551 /* Check we don't overflow our stack */
552
553 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
554 DEBUG(0, ("Connection context stack overflow!\n"));
555 smb_panic("Connection context stack overflow!\n");
556 }
557
558 /* Store previous user context */
559 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
560
561 ctx_p->conn = current_user.conn;
562 ctx_p->vuid = current_user.vuid;
563 ctx_p->user_info = current_user_info;
564
565 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
566 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
567
568 conn_ctx_stack_ndx++;
569 }
570
pop_conn_ctx(void)571 static void pop_conn_ctx(void)
572 {
573 struct conn_ctx *ctx_p;
574
575 /* Check for stack underflow. */
576
577 if (conn_ctx_stack_ndx == 0) {
578 DEBUG(0, ("Connection context stack underflow!\n"));
579 smb_panic("Connection context stack underflow!\n");
580 }
581
582 conn_ctx_stack_ndx--;
583 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
584
585 set_current_user_info(ctx_p->user_info.smb_name,
586 ctx_p->user_info.unix_name,
587 ctx_p->user_info.domain);
588
589 current_user.conn = ctx_p->conn;
590 current_user.vuid = ctx_p->vuid;
591
592 *ctx_p = (struct conn_ctx) {
593 .vuid = UID_FIELD_INVALID,
594 };
595 }
596
597 /****************************************************************************
598 Temporarily become a root user. Must match with unbecome_root(). Saves and
599 restores the connection context.
600 ****************************************************************************/
601
smbd_become_root(void)602 void smbd_become_root(void)
603 {
604 /*
605 * no good way to handle push_sec_ctx() failing without changing
606 * the prototype of become_root()
607 */
608 if (!push_sec_ctx()) {
609 smb_panic("become_root: push_sec_ctx failed");
610 }
611 push_conn_ctx();
612 set_root_sec_ctx();
613 }
614
615 /* Unbecome the root user */
616
smbd_unbecome_root(void)617 void smbd_unbecome_root(void)
618 {
619 pop_sec_ctx();
620 pop_conn_ctx();
621 }
622
623 /****************************************************************************
624 Push the current security context then force a change via change_to_user().
625 Saves and restores the connection context.
626 ****************************************************************************/
627
become_user_without_service(connection_struct * conn,uint64_t vuid)628 bool become_user_without_service(connection_struct *conn, uint64_t vuid)
629 {
630 struct auth_session_info *session_info = NULL;
631 int snum = SNUM(conn);
632 NTSTATUS status;
633 bool ok;
634
635 if (conn == NULL) {
636 DBG_WARNING("Connection not open\n");
637 return false;
638 }
639
640 status = smbXsrv_session_info_lookup(conn->sconn->client,
641 vuid,
642 &session_info);
643 if (!NT_STATUS_IS_OK(status)) {
644 /* Invalid vuid sent */
645 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
646 (unsigned long long)vuid,
647 lp_const_servicename(snum));
648 return false;
649 }
650
651 ok = push_sec_ctx();
652 if (!ok) {
653 return false;
654 }
655
656 push_conn_ctx();
657
658 ok = change_to_user_impersonate(conn, session_info, vuid);
659 if (!ok) {
660 pop_sec_ctx();
661 pop_conn_ctx();
662 return false;
663 }
664
665 return true;
666 }
667
become_user_without_service_by_fsp(struct files_struct * fsp)668 bool become_user_without_service_by_fsp(struct files_struct *fsp)
669 {
670 return become_user_without_service(fsp->conn, fsp->vuid);
671 }
672
become_user_without_service_by_session(connection_struct * conn,const struct auth_session_info * session_info)673 bool become_user_without_service_by_session(connection_struct *conn,
674 const struct auth_session_info *session_info)
675 {
676 bool ok;
677
678 SMB_ASSERT(conn != NULL);
679 SMB_ASSERT(session_info != NULL);
680
681 ok = push_sec_ctx();
682 if (!ok) {
683 return false;
684 }
685
686 push_conn_ctx();
687
688 ok = change_to_user_impersonate(conn, session_info, UID_FIELD_INVALID);
689 if (!ok) {
690 pop_sec_ctx();
691 pop_conn_ctx();
692 return false;
693 }
694
695 return true;
696 }
697
unbecome_user_without_service(void)698 bool unbecome_user_without_service(void)
699 {
700 pop_sec_ctx();
701 pop_conn_ctx();
702 return True;
703 }
704
705 /****************************************************************************
706 Return the current user we are running effectively as on this connection.
707 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
708 doesn't alter this value.
709 ****************************************************************************/
710
get_current_uid(connection_struct * conn)711 uid_t get_current_uid(connection_struct *conn)
712 {
713 return current_user.ut.uid;
714 }
715
716 /****************************************************************************
717 Return the current group we are running effectively as on this connection.
718 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
719 doesn't alter this value.
720 ****************************************************************************/
721
get_current_gid(connection_struct * conn)722 gid_t get_current_gid(connection_struct *conn)
723 {
724 return current_user.ut.gid;
725 }
726
727 /****************************************************************************
728 Return the UNIX token we are running effectively as on this connection.
729 I'd like to make this return &conn->session_info->unix_token-> but become_root()
730 doesn't alter this value.
731 ****************************************************************************/
732
get_current_utok(connection_struct * conn)733 const struct security_unix_token *get_current_utok(connection_struct *conn)
734 {
735 return ¤t_user.ut;
736 }
737
738 /****************************************************************************
739 Return the Windows token we are running effectively as on this connection.
740 If this is currently a NULL token as we're inside become_root() - a temporary
741 UNIX security override, then we search up the stack for the previous active
742 token.
743 ****************************************************************************/
744
get_current_nttok(connection_struct * conn)745 const struct security_token *get_current_nttok(connection_struct *conn)
746 {
747 if (current_user.nt_user_token) {
748 return current_user.nt_user_token;
749 }
750 return sec_ctx_active_token();
751 }
752
get_current_vuid(connection_struct * conn)753 uint64_t get_current_vuid(connection_struct *conn)
754 {
755 return current_user.vuid;
756 }
757