LCOV - code coverage report
Current view: top level - source3/smbd - sec_ctx.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 135 178 75.8 %
Date: 2021-08-25 13:27:56 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    uid/user handling
       4             :    Copyright (C) Tim Potter 2000
       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 "libcli/security/security_token.h"
      25             : #include "auth.h"
      26             : #include "smbprofile.h"
      27             : #include "../lib/util/setid.h"
      28             : 
      29             : extern struct current_user current_user;
      30             : 
      31             : /****************************************************************************
      32             :  Are two UNIX tokens equal ?
      33             : ****************************************************************************/
      34             : 
      35      173691 : bool unix_token_equal(const struct security_unix_token *t1, const struct security_unix_token *t2)
      36             : {
      37      347192 :         if (t1->uid != t2->uid || t1->gid != t2->gid ||
      38      173501 :                         t1->ngroups != t2->ngroups) {
      39         189 :                 return false;
      40             :         }
      41      173501 :         if (memcmp(t1->groups, t2->groups,
      42      173501 :                         t1->ngroups*sizeof(gid_t)) != 0) {
      43           0 :                 return false;
      44             :         }
      45      173501 :         return true;
      46             : }
      47             : 
      48             : /****************************************************************************
      49             :  Become the specified uid.
      50             : ****************************************************************************/
      51             : 
      52    11052764 : static bool become_uid(uid_t uid)
      53             : {
      54             :         /* Check for dodgy uid values */
      55             : 
      56    11052764 :         if (uid == (uid_t)-1 || 
      57             :             ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
      58           0 :                 if (!become_uid_done) {
      59           0 :                         DEBUG(1,("WARNING: using uid %d is a security risk\n",
      60             :                                  (int)uid));
      61           0 :                         become_uid_done = true;
      62             :                 }
      63             :         }
      64             : 
      65             :         /* Set effective user id */
      66             : 
      67    11052764 :         set_effective_uid(uid);
      68             : 
      69    11052764 :         return True;
      70             : }
      71             : 
      72             : /****************************************************************************
      73             :  Become the specified gid.
      74             : ****************************************************************************/
      75             : 
      76    11052764 : static bool become_gid(gid_t gid)
      77             : {
      78             :         /* Check for dodgy gid values */
      79             : 
      80    11052764 :         if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && 
      81             :                                  (gid == (gid_t)65535))) {
      82           0 :                 if (!become_gid_done) {
      83           0 :                         DEBUG(1,("WARNING: using gid %d is a security risk\n",
      84             :                                  (int)gid));  
      85           0 :                         become_gid_done = true;
      86             :                 }
      87             :         }
      88             : 
      89             :         /* Set effective group id */
      90             : 
      91    11052764 :         set_effective_gid(gid);
      92    11052764 :         return True;
      93             : }
      94             : 
      95             : /****************************************************************************
      96             :  Become the specified uid and gid.
      97             : ****************************************************************************/
      98             : 
      99    11052764 : static bool become_id(uid_t uid, gid_t gid)
     100             : {
     101    11052764 :         return become_gid(gid) && become_uid(uid);
     102             : }
     103             : 
     104             : /****************************************************************************
     105             :  Drop back to root privileges in order to change to another user.
     106             : ****************************************************************************/
     107             : 
     108    11052764 : static void gain_root(void)
     109             : {
     110    11052764 :         if (non_root_mode()) {
     111    11034887 :                 return;
     112             :         }
     113             : 
     114           0 :         if (geteuid() != 0) {
     115           0 :                 set_effective_uid(0);
     116             : 
     117           0 :                 if (geteuid() != 0) {
     118           0 :                         DEBUG(0,
     119             :                               ("Warning: You appear to have a trapdoor "
     120             :                                "uid system\n"));
     121             :                 }
     122             :         }
     123             : 
     124           0 :         if (getegid() != 0) {
     125           0 :                 set_effective_gid(0);
     126             : 
     127           0 :                 if (getegid() != 0) {
     128           0 :                         DEBUG(0,
     129             :                               ("Warning: You appear to have a trapdoor "
     130             :                                "gid system\n"));
     131             :                 }
     132             :         }
     133             : }
     134             : 
     135             : /****************************************************************************
     136             :  Get the list of current groups.
     137             : ****************************************************************************/
     138             : 
     139          82 : static int get_current_groups(gid_t gid, uint32_t *p_ngroups, gid_t **p_groups)
     140             : {
     141             :         int i;
     142             :         int ngroups;
     143          82 :         gid_t *groups = NULL;
     144             : 
     145          82 :         (*p_ngroups) = 0;
     146          82 :         (*p_groups) = NULL;
     147             : 
     148             :         /* this looks a little strange, but is needed to cope with
     149             :            systems that put the current egid in the group list
     150             :            returned from getgroups() (tridge) */
     151          82 :         save_re_gid();
     152          82 :         set_effective_gid(gid);
     153          82 :         samba_setgid(gid);
     154             : 
     155          82 :         ngroups = sys_getgroups(0, NULL);
     156          82 :         if (ngroups <= 0) {
     157           0 :                 goto fail;
     158             :         }
     159             : 
     160          82 :         if((groups = SMB_MALLOC_ARRAY(gid_t, ngroups+1)) == NULL) {
     161           0 :                 DEBUG(0,("setup_groups malloc fail !\n"));
     162           0 :                 goto fail;
     163             :         }
     164             : 
     165          82 :         if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
     166           0 :                 goto fail;
     167             :         }
     168             : 
     169          82 :         restore_re_gid();
     170             : 
     171          82 :         (*p_ngroups) = ngroups;
     172          82 :         (*p_groups) = groups;
     173             : 
     174          82 :         DEBUG( 4, ( "get_current_groups: user is in %u groups: ", ngroups));
     175         162 :         for (i = 0; i < ngroups; i++ ) {
     176          82 :                 DEBUG( 4, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
     177             :         }
     178          82 :         DEBUG( 4, ( "\n" ) );
     179             : 
     180          80 :         return ngroups;
     181             : 
     182           0 : fail:
     183           0 :         SAFE_FREE(groups);
     184           0 :         restore_re_gid();
     185           0 :         return -1;
     186             : }
     187             : 
     188             : /****************************************************************************
     189             :  Create a new security context on the stack.  It is the same as the old
     190             :  one.  User changes are done using the set_sec_ctx() function.
     191             : ****************************************************************************/
     192             : 
     193     5113184 : bool push_sec_ctx(void)
     194             : {
     195             :         struct sec_ctx *ctx_p;
     196             : 
     197     5113184 :         START_PROFILE(push_sec_ctx);
     198             : 
     199             :         /* Check we don't overflow our stack */
     200             : 
     201     5113184 :         if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
     202           0 :                 DEBUG(0, ("Security context stack overflow!\n"));
     203           0 :                 smb_panic("Security context stack overflow!");
     204             :         }
     205             : 
     206             :         /* Store previous user context */
     207             : 
     208     5113184 :         sec_ctx_stack_ndx++;
     209             : 
     210     5113184 :         ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
     211             : 
     212     5113184 :         ctx_p->ut.uid = geteuid();
     213     5113184 :         ctx_p->ut.gid = getegid();
     214             : 
     215     5113184 :         DEBUG(4, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", 
     216             :                   (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx ));
     217             : 
     218     5113184 :         ctx_p->token = dup_nt_token(NULL,
     219     5113184 :                                     sec_ctx_stack[sec_ctx_stack_ndx-1].token);
     220             : 
     221     5113184 :         ctx_p->ut.ngroups = sys_getgroups(0, NULL);
     222             : 
     223     5113184 :         if (ctx_p->ut.ngroups != 0) {
     224     4531064 :                 if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) {
     225           0 :                         DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
     226           0 :                         TALLOC_FREE(ctx_p->token);
     227           0 :                         return False;
     228             :                 }
     229             : 
     230     4531064 :                 sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
     231             :         } else {
     232      582120 :                 ctx_p->ut.groups = NULL;
     233             :         }
     234             : 
     235     5113184 :         END_PROFILE(push_sec_ctx);
     236             : 
     237     5108131 :         return True;
     238             : }
     239             : 
     240             : /****************************************************************************
     241             :  Change UNIX security context. Calls panic if not successful so no return value.
     242             : ****************************************************************************/
     243             : 
     244             : #ifndef HAVE_DARWIN_INITGROUPS
     245             : 
     246             : /* Normal credential switch path. */
     247             : 
     248    11052764 : static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
     249             : {
     250             :         /* Start context switch */
     251    11052764 :         gain_root();
     252             : #ifdef HAVE_SETGROUPS
     253    11052764 :         if (sys_setgroups(gid, ngroups, groups) != 0 && !non_root_mode()) {
     254           0 :                 smb_panic("sys_setgroups failed");
     255             :         }
     256             : #endif
     257    11052764 :         become_id(uid, gid);
     258             :         /* end context switch */
     259    11052764 : }
     260             : 
     261             : #else /* HAVE_DARWIN_INITGROUPS */
     262             : 
     263             : /* The Darwin groups implementation is a little unusual. The list of
     264             : * groups in the kernel credential is not exhaustive, but more like
     265             : * a cache. The full group list is held in userspace and checked
     266             : * dynamically.
     267             : *
     268             : * This is an optional mechanism, and setgroups(2) opts out
     269             : * of it. That is, if you call setgroups, then the list of groups you
     270             : * set are the only groups that are ever checked. This is not what we
     271             : * want. We want to opt in to the dynamic resolution mechanism, so we
     272             : * need to specify the uid of the user whose group list (cache) we are
     273             : * setting.
     274             : *
     275             : * The Darwin rules are:
     276             : *  1. Thou shalt setegid, initgroups and seteuid IN THAT ORDER
     277             : *  2. Thou shalt not pass more that NGROUPS_MAX to initgroups
     278             : *  3. Thou shalt leave the first entry in the groups list well alone
     279             : */
     280             : 
     281             : #include <sys/syscall.h>
     282             : 
     283             : static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
     284             : {
     285             :         int max = groups_max();
     286             : 
     287             :         /* Start context switch */
     288             :         gain_root();
     289             : 
     290             :         become_gid(gid);
     291             : 
     292             : 
     293             :         if (syscall(SYS_initgroups, (ngroups > max) ? max : ngroups,
     294             :                         groups, uid) == -1 && !non_root_mode()) {
     295             :                 DEBUG(0, ("WARNING: failed to set group list "
     296             :                         "(%d groups) for UID %d: %s\n",
     297             :                         ngroups, uid, strerror(errno)));
     298             :                 smb_panic("sys_setgroups failed");
     299             :         }
     300             : 
     301             :         become_uid(uid);
     302             :         /* end context switch */
     303             : }
     304             : 
     305             : #endif /* HAVE_DARWIN_INITGROUPS */
     306             : 
     307             : /****************************************************************************
     308             :  Set the current security context to a given user.
     309             : ****************************************************************************/
     310             : 
     311     5939690 : static void set_sec_ctx_internal(uid_t uid, gid_t gid,
     312             :                                  int ngroups, gid_t *groups,
     313             :                                  const struct security_token *token)
     314             : {
     315     5939690 :         struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
     316             : 
     317             :         /* Set the security context */
     318             : 
     319     5939690 :         DEBUG(4, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
     320             :                 (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
     321             : 
     322     5939690 :         security_token_debug(DBGC_CLASS, 5, token);
     323     5939690 :         debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
     324             : 
     325             :         /* Change uid, gid and supplementary group list. */
     326     5939690 :         set_unix_security_ctx(uid, gid, ngroups, groups);
     327             : 
     328     5939690 :         ctx_p->ut.ngroups = ngroups;
     329             : 
     330     5939690 :         SAFE_FREE(ctx_p->ut.groups);
     331     5939690 :         if (token && (token == ctx_p->token)) {
     332           0 :                 smb_panic("DUPLICATE_TOKEN");
     333             :         }
     334             : 
     335     5939690 :         TALLOC_FREE(ctx_p->token);
     336             : 
     337     5939690 :         if (ngroups) {
     338      301110 :                 ctx_p->ut.groups = (gid_t *)smb_xmemdup(groups,
     339             :                                                         sizeof(gid_t) * ngroups);
     340             :         } else {
     341     5638580 :                 ctx_p->ut.groups = NULL;
     342             :         }
     343             : 
     344     5939690 :         if (token) {
     345      301110 :                 ctx_p->token = dup_nt_token(NULL, token);
     346      301110 :                 if (!ctx_p->token) {
     347           0 :                         smb_panic("dup_nt_token failed");
     348             :                 }
     349             :         } else {
     350     5638580 :                 ctx_p->token = NULL;
     351             :         }
     352             : 
     353     5939690 :         ctx_p->ut.uid = uid;
     354     5939690 :         ctx_p->ut.gid = gid;
     355             : 
     356             :         /* Update current_user stuff */
     357             : 
     358     5939690 :         current_user.ut.uid = uid;
     359     5939690 :         current_user.ut.gid = gid;
     360     5939690 :         current_user.ut.ngroups = ngroups;
     361     5939690 :         current_user.ut.groups = groups;
     362     5939690 :         current_user.nt_user_token = ctx_p->token;
     363     5939690 : }
     364             : 
     365      301194 : void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, const struct security_token *token)
     366             : {
     367      301194 :         START_PROFILE(set_sec_ctx);
     368      301194 :         set_sec_ctx_internal(uid, gid, ngroups, groups, token);
     369      301194 :         END_PROFILE(set_sec_ctx);
     370      301194 : }
     371             : 
     372             : /****************************************************************************
     373             :  Become root context.
     374             : ****************************************************************************/
     375             : 
     376     5638496 : void set_root_sec_ctx(void)
     377             : {
     378             :         /* May need to worry about supplementary groups at some stage */
     379             : 
     380     5638496 :         START_PROFILE(set_root_sec_ctx);
     381     5638496 :         set_sec_ctx_internal(0, 0, 0, NULL, NULL);
     382     5638496 :         END_PROFILE(set_root_sec_ctx);
     383     5638496 : }
     384             : 
     385             : /****************************************************************************
     386             :  Pop a security context from the stack.
     387             : ****************************************************************************/
     388             : 
     389     5113074 : bool pop_sec_ctx(void)
     390             : {
     391             :         struct sec_ctx *ctx_p;
     392             :         struct sec_ctx *prev_ctx_p;
     393             : 
     394     5113074 :         START_PROFILE(pop_sec_ctx);
     395             : 
     396             :         /* Check for stack underflow */
     397             : 
     398     5113074 :         if (sec_ctx_stack_ndx == 0) {
     399           0 :                 DEBUG(0, ("Security context stack underflow!\n"));
     400           0 :                 smb_panic("Security context stack underflow!");
     401             :         }
     402             : 
     403     5113074 :         ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
     404             : 
     405             :         /* Clear previous user info */
     406             : 
     407     5113074 :         ctx_p->ut.uid = (uid_t)-1;
     408     5113074 :         ctx_p->ut.gid = (gid_t)-1;
     409             : 
     410     5113074 :         SAFE_FREE(ctx_p->ut.groups);
     411     5113074 :         ctx_p->ut.ngroups = 0;
     412             : 
     413     5113074 :         TALLOC_FREE(ctx_p->token);
     414             : 
     415             :         /* Pop back previous user */
     416             : 
     417     5113074 :         sec_ctx_stack_ndx--;
     418             : 
     419     5113074 :         prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
     420             : 
     421             :         /* Change uid, gid and supplementary group list. */
     422    10226148 :         set_unix_security_ctx(prev_ctx_p->ut.uid,
     423             :                         prev_ctx_p->ut.gid,
     424     5113074 :                         prev_ctx_p->ut.ngroups,
     425             :                         prev_ctx_p->ut.groups);
     426             : 
     427             :         /* Update current_user stuff */
     428             : 
     429     5113074 :         current_user.ut.uid = prev_ctx_p->ut.uid;
     430     5113074 :         current_user.ut.gid = prev_ctx_p->ut.gid;
     431     5113074 :         current_user.ut.ngroups = prev_ctx_p->ut.ngroups;
     432     5113074 :         current_user.ut.groups = prev_ctx_p->ut.groups;
     433     5113074 :         current_user.nt_user_token = prev_ctx_p->token;
     434             : 
     435     5113074 :         END_PROFILE(pop_sec_ctx);
     436             : 
     437     5113074 :         DEBUG(4, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
     438             :                 (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
     439             : 
     440     5113074 :         return True;
     441             : }
     442             : 
     443             : /* Initialise the security context system */
     444             : 
     445          82 : void init_sec_ctx(void)
     446             : {
     447             :         int i;
     448             :         struct sec_ctx *ctx_p;
     449             : 
     450             :         /* Initialise security context stack */
     451             : 
     452          82 :         memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
     453             : 
     454         738 :         for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
     455         656 :                 sec_ctx_stack[i].ut.uid = (uid_t)-1;
     456         656 :                 sec_ctx_stack[i].ut.gid = (gid_t)-1;
     457             :         }
     458             : 
     459             :         /* Initialise first level of stack.  It is the current context */
     460          82 :         ctx_p = &sec_ctx_stack[0];
     461             : 
     462          82 :         ctx_p->ut.uid = geteuid();
     463          82 :         ctx_p->ut.gid = getegid();
     464             : 
     465          82 :         get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups);
     466             : 
     467          82 :         ctx_p->token = NULL; /* Maps to guest user. */
     468             : 
     469             :         /* Initialise current_user global */
     470             : 
     471          82 :         current_user.ut.uid = ctx_p->ut.uid;
     472          82 :         current_user.ut.gid = ctx_p->ut.gid;
     473          82 :         current_user.ut.ngroups = ctx_p->ut.ngroups;
     474          82 :         current_user.ut.groups = ctx_p->ut.groups;
     475             : 
     476             :         /* The conn and vuid are usually taken care of by other modules.
     477             :            We initialise them here. */
     478             : 
     479          82 :         current_user.conn = NULL;
     480          82 :         current_user.vuid = UID_FIELD_INVALID;
     481          82 :         current_user.nt_user_token = NULL;
     482          82 : }
     483             : 
     484             : /*************************************************************
     485             :  Called when we're inside a become_root() temporary escalation
     486             :  of privileges and the nt_user_token is NULL. Return the last
     487             :  active token on the context stack. We know there is at least
     488             :  one valid non-NULL token on the stack so panic if we underflow.
     489             : *************************************************************/
     490             : 
     491           0 : const struct security_token *sec_ctx_active_token(void)
     492             : {
     493           0 :         int stack_index = sec_ctx_stack_ndx;
     494           0 :         struct sec_ctx *ctx_p = &sec_ctx_stack[stack_index];
     495             : 
     496           0 :         while (ctx_p->token == NULL) {
     497           0 :                 stack_index--;
     498           0 :                 if (stack_index < 0) {
     499           0 :                         DEBUG(0, ("Security context active token "
     500             :                                   "stack underflow!\n"));
     501           0 :                         smb_panic("Security context active token "
     502             :                                   "stack underflow!");
     503             :                 }
     504           0 :                 ctx_p = &sec_ctx_stack[stack_index];
     505             :         }
     506           0 :         return ctx_p->token;
     507             : }

Generated by: LCOV version 1.13