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
print_privs(priv_ptype_t which,const char * str)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
priv_on(const char * priv)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
priv_off(const char * priv)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*/
init_privs(const char * username)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*/
port_priv_on(uid_t uid)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*/
port_priv_off(uid_t uid)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 */
access_priv_on(uid_t uid)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
access_priv_off(uid_t uid)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*/
setid_priv_on(uid_t uid)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*/
setid_priv_off(uid_t uid)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 */
chown_priv_on(uid_t uid)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
chown_priv_off(uid_t uid)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 }
266