LCOV - code coverage report
Current view: top level - util - become_user.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 84 0.0 %
Date: 2016-06-29 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Kerberos 5 Backend Module -- Utilities
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2009 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "util/util.h"
      26             : #include <grp.h>
      27             : 
      28           0 : errno_t become_user(uid_t uid, gid_t gid)
      29             : {
      30             :     uid_t cuid;
      31             :     int ret;
      32             : 
      33           0 :     DEBUG(SSSDBG_FUNC_DATA,
      34             :           "Trying to become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid);
      35             : 
      36             :     /* skip call if we already are the requested user */
      37           0 :     cuid = geteuid();
      38           0 :     if (uid == cuid) {
      39           0 :         DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid);
      40           0 :         return EOK;
      41             :     }
      42             : 
      43             :     /* drop supplmentary groups first */
      44           0 :     ret = setgroups(0, NULL);
      45           0 :     if (ret == -1) {
      46           0 :         ret = errno;
      47           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      48             :               "setgroups failed [%d][%s].\n", ret, strerror(ret));
      49           0 :         return ret;
      50             :     }
      51             : 
      52             :     /* change gid so that root cannot be regained (changes saved gid too) */
      53           0 :     ret = setresgid(gid, gid, gid);
      54           0 :     if (ret == -1) {
      55           0 :         ret = errno;
      56           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      57             :               "setresgid failed [%d][%s].\n", ret, strerror(ret));
      58           0 :         return ret;
      59             :     }
      60             : 
      61             :     /* change uid so that root cannot be regained (changes saved uid too) */
      62             :     /* this call also takes care of dropping CAP_SETUID, so this is a PNR */
      63           0 :     ret = setresuid(uid, uid, uid);
      64           0 :     if (ret == -1) {
      65           0 :         ret = errno;
      66           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      67             :               "setresuid failed [%d][%s].\n", ret, strerror(ret));
      68           0 :         return ret;
      69             :     }
      70             : 
      71           0 :     return EOK;
      72             : }
      73             : 
      74             : struct sss_creds {
      75             :     uid_t uid;
      76             :     gid_t gid;
      77             :     int num_gids;
      78             :     gid_t gids[];
      79             : };
      80             : 
      81             : errno_t restore_creds(struct sss_creds *saved_creds);
      82             : 
      83             : /* This is a reversible version of become_user, and returns the saved
      84             :  * credentials so that creds can be switched back calling restore_creds */
      85           0 : errno_t switch_creds(TALLOC_CTX *mem_ctx,
      86             :                      uid_t uid, gid_t gid,
      87             :                      int num_gids, gid_t *gids,
      88             :                      struct sss_creds **saved_creds)
      89             : {
      90           0 :     struct sss_creds *ssc = NULL;
      91             :     int size;
      92             :     int ret;
      93             :     uid_t myuid;
      94             :     uid_t mygid;
      95             : 
      96           0 :     DEBUG(SSSDBG_FUNC_DATA, "Switch user to [%d][%d].\n", uid, gid);
      97             : 
      98           0 :     myuid = geteuid();
      99           0 :     mygid = getegid();
     100             : 
     101           0 :     if (saved_creds) {
     102             :         /* save current user credentials */
     103           0 :         size = getgroups(0, NULL);
     104           0 :         if (size == -1) {
     105           0 :             ret = errno;
     106           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n",
     107             :                                         ret, strerror(ret));
     108           0 :             goto done;
     109             :         }
     110             : 
     111           0 :         ssc = talloc_size(mem_ctx,
     112             :                           (sizeof(struct sss_creds) + size * sizeof(gid_t)));
     113           0 :         if (!ssc) {
     114           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Allocation failed!\n");
     115           0 :             ret = ENOMEM;
     116           0 :             goto done;
     117             :         }
     118           0 :         ssc->num_gids = size;
     119             : 
     120           0 :         size = getgroups(ssc->num_gids, ssc->gids);
     121           0 :         if (size == -1) {
     122           0 :             ret = errno;
     123           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n",
     124             :                                         ret, strerror(ret));
     125             :             /* free ssc immediately otherwise the code will try to restore
     126             :              * wrong creds */
     127           0 :             talloc_zfree(ssc);
     128           0 :             goto done;
     129             :         }
     130             : 
     131             :         /* we care only about effective ids */
     132           0 :         ssc->uid = myuid;
     133           0 :         ssc->gid = mygid;
     134             :     }
     135             : 
     136             :     /* if we are regaining root set euid first so that we have CAP_SETUID back,
     137             :      * ane the other calls work too, otherwise call it last so that we can
     138             :      * change groups before we loose CAP_SETUID */
     139           0 :     if (uid == 0) {
     140           0 :         ret = setresuid(0, 0, 0);
     141           0 :         if (ret == -1) {
     142           0 :             ret = errno;
     143           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     144             :                   "setresuid failed [%d][%s].\n", ret, strerror(ret));
     145           0 :             goto done;
     146             :         }
     147             :     }
     148             : 
     149             :     /* TODO: use libcap-ng if we need to get/set capabilities too ? */
     150             : 
     151           0 :     if (myuid == uid && mygid == gid) {
     152           0 :         DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid);
     153           0 :         talloc_zfree(ssc);
     154           0 :         return EOK;
     155             :     }
     156             : 
     157             :     /* try to setgroups first should always work if CAP_SETUID is set,
     158             :      * otherwise it will always fail, failure is not critical though as
     159             :      * generally we only really care about uid and at mot primary gid */
     160           0 :     ret = setgroups(num_gids, gids);
     161           0 :     if (ret == -1) {
     162           0 :         ret = errno;
     163           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     164             :               "setgroups failed [%d][%s].\n", ret, strerror(ret));
     165             :     }
     166             : 
     167             :     /* change gid now, (leaves saved gid to current, so we can restore) */
     168           0 :     ret = setresgid(-1, gid, -1);
     169           0 :     if (ret == -1) {
     170           0 :         ret = errno;
     171           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     172             :               "setresgid failed [%d][%s].\n", ret, strerror(ret));
     173           0 :         goto done;
     174             :     }
     175             : 
     176           0 :     if (uid != 0) {
     177             :         /* change uid, (leaves saved uid to current, so we can restore) */
     178           0 :         ret = setresuid(-1, uid, -1);
     179           0 :         if (ret == -1) {
     180           0 :             ret = errno;
     181           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     182             :                   "setresuid failed [%d][%s].\n", ret, strerror(ret));
     183           0 :             goto done;
     184             :         }
     185             :     }
     186             : 
     187           0 :     ret = 0;
     188             : 
     189             : done:
     190           0 :     if (ret) {
     191             :         /* attempt to restore creds first */
     192           0 :         restore_creds(ssc);
     193           0 :         talloc_free(ssc);
     194           0 :     } else if (saved_creds) {
     195           0 :         *saved_creds = ssc;
     196             :     }
     197           0 :     return ret;
     198             : }
     199             : 
     200           0 : errno_t restore_creds(struct sss_creds *saved_creds)
     201             : {
     202           0 :     if (saved_creds == NULL) {
     203             :         /* In case save_creds was saved with the UID already dropped */
     204           0 :         return EOK;
     205             :     }
     206             : 
     207           0 :     return switch_creds(saved_creds,
     208             :                         saved_creds->uid,
     209             :                         saved_creds->gid,
     210             :                         saved_creds->num_gids,
     211           0 :                         saved_creds->gids, NULL);
     212             : }

Generated by: LCOV version 1.10