1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Least privilege support functions. 8 */ 9 10 #include "config.h" 11 12 #ifdef SOLARIS_PRIVS 13 #include <priv.h> 14 #ifdef HAVE_SYS_SYSLOG_H 15 #include <sys/syslog.h> 16 #endif 17 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H)) 18 #include <syslog.h> 19 #endif 20 #endif /* SOLARIS_PRIVS */ 21 22 #include "proto.h" 23 24 #ifdef SOLARIS_PRIVS 25 /* When ununitialized, this indicates we still have all privs */ 26 static priv_set_t *uprivs; 27 #endif /* SOLARIS_PRIVS */ 28 29 #ifdef SOLARIS_PRIVS 30 #ifdef PRIVS_DEBUG 31 static void print_privs(priv_ptype_t which, const char *str) 32 { 33 priv_set_t *privset; 34 char *privstr; 35 36 if ((privset = priv_allocset()) == NULL) 37 return; 38 39 (void) getppriv(which, privset); 40 privstr = priv_set_to_str(privset, ',', PRIV_STR_SHORT); 41 syslog(LOG_DEBUG, "%s: %s", str, privstr); 42 free(privstr); 43 priv_freeset(privset); 44 } 45 #endif /* PRIVS_DEBUG */ 46 47 static void priv_on(const char *priv) 48 { 49 /* no need to add the privilege if already have it */ 50 if (uprivs == NULL || priv_ismember(uprivs, priv)) 51 return; 52 53 if (priv_set(PRIV_ON, PRIV_EFFECTIVE, priv, NULL) == -1) 54 syslog(LOG_ERR, "priv_set: error adding privilege %s: %m", priv); 55 } 56 57 static void priv_off(const char *priv) 58 { 59 /* don't remove the privilege if already had it */ 60 if (uprivs == NULL || priv_ismember(uprivs, priv)) 61 return; 62 63 if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, priv, NULL) == -1) 64 syslog(LOG_ERR, "priv_set: error removing privilege %s: %m", priv); 65 } 66 #endif /* SOLARIS_PRIVS */ 67 68 /* 69 * init_privs() is called after a user has logged in to drop from the 70 * permitted privilege set those privileges which are no longer required. 71 */ 72 /*ARGSUSED*/ 73 void init_privs(const char *username) 74 { 75 #ifdef SOLARIS_PRIVS 76 uid_t euid = geteuid(); 77 priv_set_t *pset1, *pset2; 78 79 /* 80 * The FTP server runs with the inheritable set and the limit set 81 * filled in through user_attr (or with default values of basic and all). 82 * The privileges available to the user at login, is an intersection 83 * of both those sets. The only way to limit the root user is by 84 * changing the limit set, not by changing the I set. 85 */ 86 if ((pset1 = priv_allocset()) == NULL || 87 (uprivs = priv_allocset()) == NULL || 88 (pset2 = priv_allocset()) == NULL) { 89 syslog(LOG_ERR, "priv_allocset failed: %m"); 90 dologout(1); 91 } 92 if (getppriv(PRIV_LIMIT, pset1) == -1) { 93 syslog(LOG_ERR, "getppriv(limit) failed: %m"); 94 dologout(1); 95 } 96 if (getppriv(euid == 0 ? PRIV_PERMITTED : PRIV_INHERITABLE, pset2) == -1) { 97 syslog(LOG_ERR, "getppriv() failed: %m"); 98 dologout(1); 99 } 100 101 /* Compute the permitted set after login. */ 102 priv_intersect(pset2, pset1); 103 104 /* 105 * Set the permitted privilege set to the allowable privileges plus 106 * those required after init_privs() is called. Keep note of which 107 * effective privileges we already had in uprivs so we don't turn 108 * them off. 109 */ 110 priv_emptyset(pset2); 111 (void) priv_addset(pset2, PRIV_PROC_SETID); 112 (void) priv_addset(pset2, PRIV_NET_PRIVADDR); 113 (void) priv_addset(pset2, PRIV_FILE_DAC_READ); 114 (void) priv_addset(pset2, PRIV_FILE_DAC_SEARCH); 115 (void) priv_addset(pset2, PRIV_FILE_CHOWN); 116 117 priv_copyset(pset2, uprivs); 118 priv_intersect(pset1, uprivs); 119 120 /* Now, set the effective privileges. */ 121 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pset1) == -1) { 122 syslog(LOG_ERR, 123 "unable to set privileges for %s: setppriv(effective): %m", 124 username); 125 dologout(1); 126 } 127 128 #if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT) 129 /* needed for audit_ftpd_logout() */ 130 (void) priv_addset(pset1, PRIV_PROC_AUDIT); 131 #endif 132 /* And set the permitted, adding ftpd's required privileges in the mix. */ 133 priv_union(pset2, pset1); 134 if (setppriv(PRIV_SET, PRIV_PERMITTED, pset1) == -1) { 135 syslog(LOG_ERR, 136 "unable to set privileges for %s: setppriv(permitted): %m", 137 username); 138 dologout(1); 139 } 140 /* 141 * setppriv() has made us privilege aware, so the effective privileges 142 * are no longer modified by user ID changes. 143 */ 144 priv_freeset(pset1); 145 priv_freeset(pset2); 146 147 /* set the real, effective and saved group ID's */ 148 setid_priv_on(0); 149 if (setgid(getegid()) != 0) { 150 syslog(LOG_ERR, "setgid(%d) failed: %m", getegid()); 151 setid_priv_off(euid); 152 dologout(1); 153 } 154 /* 155 * Set the real and effective user ID's, leaving the saved user ID set 156 * to 0 so seteuid(0) succeeds. 157 */ 158 (void) seteuid(0); 159 if (setreuid(euid, -1) != 0) { 160 syslog(LOG_ERR, "setreuid(%d, -1) failed: %m", euid); 161 setid_priv_off(euid); 162 dologout(1); 163 } 164 setid_priv_off(euid); 165 if (seteuid(euid) != 0) { 166 syslog(LOG_ERR, "seteuid(%d) failed: %m", euid); 167 dologout(1); 168 } 169 170 #ifdef PRIVS_DEBUG 171 print_privs(PRIV_EFFECTIVE, "effective privilege set"); 172 print_privs(PRIV_PERMITTED, "permitted privilege set"); 173 print_privs(PRIV_INHERITABLE, "inheritable privilege set"); 174 print_privs(PRIV_LIMIT, "limit privilege set"); 175 #endif /* PRIVS_DEBUG */ 176 #endif /* SOLARIS_PRIVS */ 177 } 178 179 /* allow a process to bind to a privileged port */ 180 /*ARGSUSED*/ 181 void port_priv_on(uid_t uid) 182 { 183 delay_signaling(); 184 #ifdef SOLARIS_PRIVS 185 priv_on(PRIV_NET_PRIVADDR); 186 #else 187 (void) seteuid(uid); 188 #endif 189 } 190 191 /*ARGSUSED*/ 192 void port_priv_off(uid_t uid) 193 { 194 #ifdef SOLARIS_PRIVS 195 priv_off(PRIV_NET_PRIVADDR); 196 #else 197 (void) seteuid(uid); 198 #endif 199 enable_signaling(); 200 } 201 202 /* allow a process to read any file or directory and to search any directory */ 203 void access_priv_on(uid_t uid) 204 { 205 delay_signaling(); 206 #ifdef SOLARIS_PRIVS 207 priv_on(PRIV_FILE_DAC_READ); 208 priv_on(PRIV_FILE_DAC_SEARCH); 209 #endif 210 /* necessary on Solaris for access over NFS */ 211 (void) seteuid(uid); 212 } 213 214 void access_priv_off(uid_t uid) 215 { 216 #ifdef SOLARIS_PRIVS 217 priv_off(PRIV_FILE_DAC_READ); 218 priv_off(PRIV_FILE_DAC_SEARCH); 219 #endif 220 (void) seteuid(uid); 221 enable_signaling(); 222 } 223 224 /* allow a process to set its user IDs and group IDs */ 225 /*ARGSUSED*/ 226 void setid_priv_on(uid_t uid) 227 { 228 delay_signaling(); 229 #ifdef SOLARIS_PRIVS 230 priv_on(PRIV_PROC_SETID); 231 #else 232 (void) seteuid(uid); 233 #endif 234 } 235 236 /*ARGSUSED*/ 237 void setid_priv_off(uid_t uid) 238 { 239 #ifdef SOLARIS_PRIVS 240 priv_off(PRIV_PROC_SETID); 241 #else 242 (void) seteuid(uid); 243 #endif 244 enable_signaling(); 245 } 246 247 /* allow a process to change the ownership of files and directories */ 248 void chown_priv_on(uid_t uid) 249 { 250 delay_signaling(); 251 #ifdef SOLARIS_PRIVS 252 priv_on(PRIV_FILE_CHOWN); 253 #endif 254 /* necessary on Solaris for chown over NFS */ 255 (void) seteuid(uid); 256 } 257 258 void chown_priv_off(uid_t uid) 259 { 260 #ifdef SOLARIS_PRIVS 261 priv_off(PRIV_FILE_CHOWN); 262 #endif 263 (void) seteuid(uid); 264 enable_signaling(); 265 }