Mercurial > illumos > onarm
view usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/privs.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
line wrap: on
line source
/* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Least privilege support functions. */ #include "config.h" #ifdef SOLARIS_PRIVS #include <priv.h> #ifdef HAVE_SYS_SYSLOG_H #include <sys/syslog.h> #endif #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H)) #include <syslog.h> #endif #endif /* SOLARIS_PRIVS */ #include "proto.h" #ifdef SOLARIS_PRIVS /* * Before becoming privilege aware in init_privs(), no explicit privilege * manipulation using priv_on()/priv_off() is necessary as seteuid(0) sets * the effective privilege set to the limit set. Thus these are all * initialized to TRUE. */ static boolean_t got_setid_priv = B_TRUE; static boolean_t got_privaddr_priv = B_TRUE; static boolean_t got_read_priv = B_TRUE; static boolean_t got_search_priv = B_TRUE; static boolean_t got_chown_priv = B_TRUE; #endif /* SOLARIS_PRIVS */ #ifdef SOLARIS_PRIVS #ifdef PRIVS_DEBUG static void print_privs(priv_ptype_t which, const char *str) { priv_set_t *privset; char *privstr; if ((privset = priv_allocset()) == NULL) return; (void) getppriv(which, privset); privstr = priv_set_to_str(privset, ',', PRIV_STR_SHORT); syslog(LOG_DEBUG, "%s: %s", str, privstr); free(privstr); priv_freeset(privset); } #endif /* PRIVS_DEBUG */ static void priv_on(const char *priv, boolean_t already_have) { /* no need to add the privilege if already have it */ if (already_have) return; if (priv_set(PRIV_ON, PRIV_EFFECTIVE, priv, NULL) == -1) syslog(LOG_ERR, "priv_set: error adding privilege %s: %m", priv); } static void priv_off(const char *priv, boolean_t already_had) { /* don't remove the privilege if already had it */ if (already_had) return; if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, priv, NULL) == -1) syslog(LOG_ERR, "priv_set: error removing privilege %s: %m", priv); } #endif /* SOLARIS_PRIVS */ /* * init_privs() is called after a user has logged in to drop from the * permitted privilege set those privileges which are no longer required. */ /*ARGSUSED*/ void init_privs(const char *username) { #ifdef SOLARIS_PRIVS uid_t euid = geteuid(); priv_set_t *privset; /* * The FTP server runs with "basic" inheritable privileges, which are * reset in pam_setcred() for non anonymous users. The seteuid() call in * pass() sets the effective privileges to the inheritable privileges. */ if ((privset = priv_allocset()) == NULL) { syslog(LOG_ERR, "priv_allocset failed: %m"); dologout(1); } if (getppriv(PRIV_EFFECTIVE, privset) == -1) { syslog(LOG_ERR, "getppriv(effective) failed: %m"); dologout(1); } /* * Set the permitted privilege set to the effective privileges plus * those required after init_privs() is called. Keep note of which * effective privileges we already had so we don't turn them off. */ if (!priv_ismember(privset, PRIV_PROC_SETID)) { got_setid_priv = B_FALSE; (void) priv_addset(privset, PRIV_PROC_SETID); } if (!priv_ismember(privset, PRIV_NET_PRIVADDR)) { got_privaddr_priv = B_FALSE; (void) priv_addset(privset, PRIV_NET_PRIVADDR); } if (!priv_ismember(privset, PRIV_FILE_DAC_READ)) { got_read_priv = B_FALSE; (void) priv_addset(privset, PRIV_FILE_DAC_READ); } if (!priv_ismember(privset, PRIV_FILE_DAC_SEARCH)) { got_search_priv = B_FALSE; (void) priv_addset(privset, PRIV_FILE_DAC_SEARCH); } if (!priv_ismember(privset, PRIV_FILE_CHOWN)) { got_chown_priv = B_FALSE; (void) priv_addset(privset, PRIV_FILE_CHOWN); } #if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT) /* needed for audit_ftpd_logout() */ (void) priv_addset(privset, PRIV_PROC_AUDIT); #endif if (setppriv(PRIV_SET, PRIV_PERMITTED, privset) == -1) { syslog(LOG_ERR, "unable to set privileges for %s: setppriv(permitted): %m", username); dologout(1); } /* * setppriv() has made us privilege aware, so the effective privileges * are no longer modified by user ID changes. */ priv_freeset(privset); /* set the real, effective and saved group ID's */ setid_priv_on(0); if (setgid(getegid()) != 0) { syslog(LOG_ERR, "setgid(%d) failed: %m", getegid()); setid_priv_off(euid); dologout(1); } /* * Set the real and effective user ID's, leaving the saved user ID set * to 0 so seteuid(0) succeeds. */ (void) seteuid(0); if (setreuid(euid, -1) != 0) { syslog(LOG_ERR, "setreuid(%d, -1) failed: %m", euid); setid_priv_off(euid); dologout(1); } setid_priv_off(euid); if (seteuid(euid) != 0) { syslog(LOG_ERR, "seteuid(%d) failed: %m", euid); dologout(1); } #ifdef PRIVS_DEBUG print_privs(PRIV_EFFECTIVE, "effective privilege set"); print_privs(PRIV_PERMITTED, "permitted privilege set"); print_privs(PRIV_INHERITABLE, "inheritable privilege set"); print_privs(PRIV_LIMIT, "limit privilege set"); #endif /* PRIVS_DEBUG */ #endif /* SOLARIS_PRIVS */ } /* allow a process to bind to a privileged port */ /*ARGSUSED*/ void port_priv_on(uid_t uid) { delay_signaling(); #ifdef SOLARIS_PRIVS priv_on(PRIV_NET_PRIVADDR, got_privaddr_priv); #else (void) seteuid(uid); #endif } /*ARGSUSED*/ void port_priv_off(uid_t uid) { #ifdef SOLARIS_PRIVS priv_off(PRIV_NET_PRIVADDR, got_privaddr_priv); #else (void) seteuid(uid); #endif enable_signaling(); } /* allow a process to read any file or directory and to search any directory */ void access_priv_on(uid_t uid) { delay_signaling(); #ifdef SOLARIS_PRIVS priv_on(PRIV_FILE_DAC_READ, got_read_priv); priv_on(PRIV_FILE_DAC_SEARCH, got_search_priv); #endif /* necessary on Solaris for access over NFS */ (void) seteuid(uid); } void access_priv_off(uid_t uid) { #ifdef SOLARIS_PRIVS priv_off(PRIV_FILE_DAC_READ, got_read_priv); priv_off(PRIV_FILE_DAC_SEARCH, got_search_priv); #endif (void) seteuid(uid); enable_signaling(); } /* allow a process to set its user IDs and group IDs */ /*ARGSUSED*/ void setid_priv_on(uid_t uid) { delay_signaling(); #ifdef SOLARIS_PRIVS priv_on(PRIV_PROC_SETID, got_setid_priv); #else (void) seteuid(uid); #endif } /*ARGSUSED*/ void setid_priv_off(uid_t uid) { #ifdef SOLARIS_PRIVS priv_off(PRIV_PROC_SETID, got_setid_priv); #else (void) seteuid(uid); #endif enable_signaling(); } /* allow a process to change the ownership of files and directories */ void chown_priv_on(uid_t uid) { delay_signaling(); #ifdef SOLARIS_PRIVS priv_on(PRIV_FILE_CHOWN, got_chown_priv); #endif /* necessary on Solaris for chown over NFS */ (void) seteuid(uid); } void chown_priv_off(uid_t uid) { #ifdef SOLARIS_PRIVS priv_off(PRIV_FILE_CHOWN, got_chown_priv); #endif (void) seteuid(uid); enable_signaling(); }