diff options
Diffstat (limited to 'src/userprivs.c')
-rw-r--r-- | src/userprivs.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/userprivs.c b/src/userprivs.c new file mode 100644 index 0000000..e6a18c8 --- /dev/null +++ b/src/userprivs.c @@ -0,0 +1,118 @@ +/* wydawca - automatic release submission daemon + Copyright (C) 2007, 2009 Sergey Poznyakoff + + Wydawca is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Wydawca is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with wydawca. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" + +int +wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp) +{ + int rc = 0; + size_t size = 1, j = 1; + + if (uid == 0) + return 0; + + /* Reset group permissions */ + if (geteuid () == 0 && setgroups (ngrp, grplist)) + { + logmsg (LOG_CRIT, "setgroups(%lu, %lu...): %s", + ngrp, grplist[0], 0, strerror (errno)); + return rc; + } + + /* Switch to the user's gid. On some OSes the effective gid must + be reset first */ + +#if defined(HAVE_SETEGID) + if ((rc = setegid (gid)) < 0) + logmsg (LOG_CRIT, "setegid(%lu): %s", gid, strerror (errno)); +#elif defined(HAVE_SETREGID) + if ((rc = setregid (gid, gid)) < 0) + logmsg (LOG_CRIT, "setregid(%lu,%lu)d: %s", + (unsigned long) gid, (unsigned long) gid, strerror (errno)); +#elif defined(HAVE_SETRESGID) + if ((rc = setresgid (gid, gid, gid)) < 0) + logmsg (LOG_CRIT, "setresgid(%lu,%lu,%lu): %s", + (unsigned long) gid, (unsigned long) gid, + (unsigned long) gid, + strerror (errno)); +#endif + + if (rc == 0 && gid != 0) + { + if ((rc = setgid (gid)) < 0 && getegid () != gid) + logmsg (LOG_CRIT, "setgid(%lu): %s", + (unsigned long) gid, strerror (errno)); + if (rc == 0 && getegid () != gid) + { + logmsg (LOG_CRIT, _("cannot set effective gid to %lu"), + (unsigned long) gid); + rc = 1; + } + } + + /* Now reset uid */ + if (rc == 0 && uid != 0) + { + uid_t euid; + + if (setuid (uid) + || geteuid () != uid + || (getuid () != uid + && (geteuid () == 0 || getuid () == 0))) + { + +#if defined(HAVE_SETREUID) + if (geteuid () != uid) + { + if (setreuid (uid, -1) < 0) + { + logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + if (setuid (uid) < 0) + { + logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + } + else +#endif + { + logmsg (LOG_CRIT, "setuid(%lu): %s", + (unsigned long) uid, strerror (errno)); + rc = 1; + } + } + + euid = geteuid (); + if (uid != 0 && setuid (0) == 0) + { + logmsg (LOG_CRIT, _("seteuid(0) succeeded when it should not")); + rc = 1; + } + else if (uid != euid && setuid (euid) == 0) + { + logmsg (LOG_CRIT, _("cannot drop non-root setuid privileges")); + rc = 1; + } + + } + + return rc; +} |