• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/build/buildd-opendnssec_1.3.2-1~bpo60+1-powerpc-mjESd6/opendnssec-1.3.2/signer/src/shared/privdrop.c

Go to the documentation of this file.
00001 /*
00002  * $Id: privdrop.c 4340 2011-01-31 15:15:15Z matthijs $
00003  *
00004  * Copyright (c) 2009 Nominet UK. All rights reserved.
00005  *
00006  * Based heavily on uidswap.c from openssh-5.2p1
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00021  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00023  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00025  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00026  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00027  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  */
00030 
00036 #define _GNU_SOURCE /* defines for setres{g|u}id */
00037 
00038 #include "config.h"
00039 #include "shared/log.h"
00040 #include "shared/privdrop.h"
00041 #include "shared/status.h"
00042 
00043 #include <errno.h>
00044 #include <pwd.h>
00045 #include <grp.h>
00046 #include <ctype.h>
00047 #include <stdarg.h>
00048 #include <stdlib.h>
00049 #include <stdio.h>
00050 #include <string.h>
00051 #include <sys/types.h>
00052 #include <syslog.h>
00053 #include <unistd.h>
00054 
00055 #ifndef _SC_GETPW_R_SIZE_MAX
00056 #define _SC_GETPW_R_SIZE_MAX 16384
00057 #endif /* _SC_GETPW_R_SIZE_MAX */
00058 
00059 #ifndef _SC_GETGR_R_SIZE_MAX
00060 #define _SC_GETGR_R_SIZE_MAX 16384
00061 #endif /* _SC_GETGR_R_SIZE_MAX */
00062 
00063 static const char* privdrop_str = "privdrop";
00064 
00065 
00070 uid_t
00071 privuid(const char* username)
00072 {
00073     struct passwd pwd;
00074     struct passwd* result;
00075     long bufsize;
00076     char* buf;
00077     uid_t uid, olduid;
00078     int s;
00079 
00080     uid = olduid = geteuid();
00081 
00082     if (username) {
00083         bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
00084         if (bufsize == -1) {
00085             bufsize = 16384; /* should be more than enough */
00086         }
00087         buf = (char*) calloc(bufsize, sizeof(char));
00088         if (!buf) {
00089             ods_log_error("[%s] calloc failed: out of memory?", privdrop_str);
00090             return -1;
00091         }
00092         /* Lookup the user id in /etc/passwd */
00093         s = getpwnam_r(username, &pwd, buf, bufsize, &result); /* LEAK */
00094         if (result != NULL) {
00095             uid = pwd.pw_uid;
00096         }
00097         free((void*) buf);
00098     } else {
00099         uid = -1;
00100     }
00101     return uid;
00102 }
00103 
00104 
00109 gid_t
00110 privgid(const char *groupname)
00111 {
00112     struct group grp;
00113     struct group* result;
00114     long bufsize;
00115     char* buf;
00116     gid_t gid, oldgid;
00117     int s;
00118 
00119     gid = oldgid = getegid();
00120 
00121     if (groupname) {
00122         bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
00123         if (bufsize == -1) {
00124             bufsize = 16384; /* should be more than enough */
00125         }
00126         buf = (char*) calloc(bufsize, sizeof(char));
00127         if (!buf) {
00128             ods_log_error("[%s] calloc failed: out of memory?", privdrop_str);
00129             return -1;
00130         }
00131         /* Lookup the group id in /etc/group */
00132         s = getgrnam_r(groupname, &grp, buf, bufsize, &result); /* LEAK */
00133         if (result != NULL) {
00134             gid = grp.gr_gid;
00135         }
00136         free((void*) buf);
00137     } else {
00138         gid = -1;
00139     }
00140     return gid;
00141 }
00142 
00143 
00148 ods_status
00149 privdrop(const char *username, const char *groupname, const char *newroot,
00150     uid_t* puid, gid_t* pgid)
00151 {
00152     int status;
00153     uid_t uid, olduid;
00154     gid_t gid, oldgid;
00155     long ngroups_max;
00156     gid_t *final_groups;
00157     int final_group_len = -1;
00158 
00159     /* Save effective uid/gid */
00160     uid = olduid = geteuid();
00161     gid = oldgid = getegid();
00162 
00163     /* Check if we're going to drop uid */
00164     if (username) {
00165         uid = privuid(username);
00166         if (uid == (uid_t)-1) {
00167             ods_log_error("[%s] user %s does not exist", privdrop_str,
00168                 username);
00169             return ODS_STATUS_PRIVDROP_ERR;
00170         }
00171     }
00172 
00173     /* Check if we're going to drop gid */
00174     if (groupname) {
00175         gid = privgid(groupname);
00176         if (gid == (gid_t)-1) {
00177             ods_log_error("[%s] group %s does not exist", privdrop_str,
00178                 groupname);
00179             return ODS_STATUS_PRIVDROP_ERR;
00180         }
00181     }
00182 
00183     /* Change root if requested */
00184     if (newroot) {
00185 #ifdef HAVE_CHROOT
00186        status = chroot(newroot);
00187        if (status != 0 || chdir("/") != 0) {
00188             ods_log_error("[%s] chroot to %s failed: %.100s", privdrop_str,
00189                 newroot, strerror(errno));
00190             return ODS_STATUS_CHROOT_ERR;
00191        }
00192 #else
00193        ods_log_error("[%s] chroot to %s failed: !HAVE_CHROOT", privdrop_str,
00194            newroot);
00195        return ODS_STATUS_CHROOT_ERR;
00196 #endif /* HAVE_CHROOT */
00197     }
00198 
00199     /* Do additional groups first */
00200     if (username != NULL && !olduid) {
00201 #ifdef HAVE_INITGROUPS
00202         if (initgroups(username, gid) < 0) {
00203             ods_log_error("[%s] initgroups failed: %s: %.100s", privdrop_str,
00204                 username, strerror(errno));
00205             return ODS_STATUS_PRIVDROP_ERR;
00206         }
00207 #else
00208         ods_log_error("initgroups failed: %s: !HAVE_INITGROUPS", username);
00209         return ODS_STATUS_PRIVDROP_ERR;
00210 #endif /* HAVE_INITGROUPS */
00211 
00212         ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
00213         final_groups = (gid_t *)malloc(ngroups_max *sizeof(gid_t));
00214         if (!final_groups) {
00215             return ODS_STATUS_MALLOC_ERR;
00216         }
00217 #if defined(HAVE_GETGROUPS) && defined(HAVE_SETGROUPS)
00218         final_group_len = getgroups(ngroups_max, final_groups);
00219         /* If we are root then drop all groups other than the final one */
00220         if (!olduid) {
00221             setgroups(final_group_len, final_groups);
00222         }
00223 #endif /* defined(HAVE_GETGROUPS) && defined(HAVE_SETGROUPS) */
00224         free((void*)final_groups);
00225     }
00226     else {
00227         /* If we are root then drop all groups other than the final one */
00228 #if defined(HAVE_SETGROUPS)
00229         if (!olduid) setgroups(1, &(gid));
00230 #endif /* defined(HAVE_SETGROUPS) */
00231     }
00232 
00233     /* Drop gid? */
00234     if (groupname) {
00235 
00236 #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
00237         status = setresgid(gid, gid, gid);
00238 #elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID)
00239         status = setregid(gid, gid);
00240 #else
00241 
00242 # ifndef SETEUID_BREAKS_SETUID
00243         status = setegid(gid);
00244         if (status != 0) {
00245            ods_log_error("[%s] setegid() for %s (%lu) failed: %s",
00246                privdrop_str, groupname, (unsigned long) gid, strerror(errno));
00247            return ODS_STATUS_PRIVDROP_ERR;
00248         }
00249 # endif  /* SETEUID_BREAKS_SETUID */
00250 
00251         status = setgid(gid);
00252 #endif
00253 
00254         if (status != 0) {
00255            ods_log_error("[%s] setgid() for %s (%lu) failed: %s",
00256                privdrop_str, groupname, (unsigned long) gid, strerror(errno));
00257            return ODS_STATUS_PRIVDROP_ERR;
00258         } else {
00259             ods_log_debug("[%s] group set to %s (%lu)", privdrop_str,
00260                 groupname, (unsigned long) gid);
00261         }
00262     }
00263 
00264     /* Drop uid? */
00265     if (username) {
00266         /* Set the user to drop to if specified; else just set the uid as the real one */
00267 #if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID)
00268         status = setresuid(uid, uid, uid);
00269 #elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID)
00270         status = setreuid(uid, uid);
00271 #else
00272 
00273 # ifndef SETEUID_BREAKS_SETUID
00274         status = seteuid(uid);
00275         if (status != 0) {
00276            ods_log_error("[%s] seteuid() for %s (%lu) failed: %s",
00277                privdrop_str, username, (unsigned long) uid, strerror(errno));
00278            return ODS_STATUS_PRIVDROP_ERR;
00279         }
00280 # endif  /* SETEUID_BREAKS_SETUID */
00281 
00282         status = setuid(uid);
00283 #endif
00284 
00285         if (status != 0) {
00286            ods_log_error("[%s] setuid() for %s (%lu) failed: %s",
00287                privdrop_str, username, (unsigned long) uid, strerror(errno));
00288            return ODS_STATUS_PRIVDROP_ERR;
00289         } else {
00290             ods_log_debug("[%s] user set to %s (%lu)", privdrop_str,
00291                 username, (unsigned long) uid);
00292         }
00293     }
00294 
00295     *puid = uid;
00296     *pgid = gid;
00297     return ODS_STATUS_OK;
00298 }
00299 
00300 
00305 void
00306 privclose(const char* username, const char* groupname)
00307 {
00308     if (username) {
00309         endpwent();
00310     }
00311     if (groupname) {
00312         endgrent();
00313     }
00314     return;
00315 }

Generated on Sat Dec 17 2011 10:26:15 for OpenDNSSEC-signer by  doxygen 1.7.1