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