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