1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2009-2020 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project and other respective copyright
20  * holders give permission to link this program with OpenSSL, and distribute
21  * the resulting executable, without including the source code for OpenSSL in
22  * the source distribution.
23  */
24 
25 #include "conf.h"
26 #include "privs.h"
27 
28 /* If proftpd was started up without root privs, then this is set to TRUE.
29  * It is used to prevent spamming the logs with error messages about being
30  * unable to switch privs.
31  */
32 static int nonroot_daemon = FALSE;
33 
34 /* Functions for manipulating saved, real and effective UID for easy switching
35  * from/to root.
36  *
37  * Note: In version 1.1.5, all of this changed.  We USED to play games with
38  * the saved-UID/GID AND setreuid()/setregid(); however this appears to be
39  * slightly non-portable (i.e. w/ BSDs).  Since POSIX.1 saved-UIDs are pretty
40  * much useless without setre* (in the case of root), we now use basic UID
41  * swapping if we have seteuid(), and setreuid() swapping if not.
42  *
43  * If seteuid() is present, we set the saved UID/GID using setuid/seteuid().
44  * setreuid() is no longer used as it is considered obsolete on many systems.
45  * GIDS are also no longer swapped, as they are unnecessary.
46  *
47  * If run as root, proftpd now normally runs as:
48  *   real user            : root
49  *   effective user       : <user>
50  *   saved user           : root
51  *   real/eff/saved group : <group>
52  */
53 
54 /* Porters, please put the most reasonable and secure method of
55  * doing this in here.
56  */
57 
58 static const char *trace_channel = "privs";
59 
60 /* We keep a count of the number of times PRIVS_ROOT/PRIVS_RELINQUISH have
61  * been called.  This allows for nesting calls to PRIVS_ROOT/PRIVS_RELINQUISH,
62  * so that the last PRIVS_RELINQUISH call actually releases the privs.
63  */
64 static unsigned int root_privs = 0;
65 static unsigned int user_privs = 0;
66 
privs_log_error(const char * msg,int xerrno)67 static void privs_log_error(const char *msg, int xerrno) {
68   switch (xerrno) {
69     case EPERM:
70       pr_log_debug(DEBUG2, "%s: %s", msg, strerror(xerrno));
71       break;
72 
73     default:
74       pr_log_pri(PR_LOG_ERR, "%s: %s", msg, strerror(xerrno));
75   }
76 }
77 
pr_privs_setup(uid_t uid,gid_t gid,const char * file,int lineno)78 int pr_privs_setup(uid_t uid, gid_t gid, const char *file, int lineno) {
79   if (nonroot_daemon == TRUE) {
80     session.ouid = session.uid = getuid();
81     session.gid = getgid();
82 
83     pr_trace_msg(trace_channel, 9,
84       "PRIVS_SETUP called at %s:%d for nonroot daemon, ignoring", file, lineno);
85     return 0;
86   }
87 
88   pr_log_debug(DEBUG9, "SETUP PRIVS at %s:%d", file, lineno);
89 
90   /* Reset the user/root privs counters. */
91   root_privs = user_privs = 0;
92   pr_trace_msg(trace_channel, 9, "PRIVS_SETUP called, "
93     "resetting user/root privs count");
94 
95   pr_signals_block();
96 
97   if (getuid() != PR_ROOT_UID) {
98     session.ouid = session.uid = getuid();
99     session.gid = getgid();
100 
101     if (setgid(session.gid) < 0) {
102       privs_log_error("SETUP PRIVS: unable to setgid()", errno);
103     }
104 
105 #if defined(HAVE_SETEUID)
106     if (setuid(session.uid) < 0) {
107       privs_log_error("SETUP PRIVS: unable to setuid()", errno);
108     }
109 
110     if (seteuid(session.uid) < 0) {
111       privs_log_error("SETUP PRIVS: unable to seteuid()", errno);
112     }
113 #else
114     if (setreuid(session.uid, session.uid) < 0) {
115       privs_log_error("SETUP PRIVS: unable to setreuid()", errno);
116     }
117 #endif /* !HAVE_SETEUID */
118 
119   } else {
120     session.ouid = getuid();
121     session.uid = uid;
122     session.gid = gid;
123 
124 #if defined(HAVE_SETEUID)
125     if (setuid(PR_ROOT_UID) < 0) {
126       privs_log_error("SETUP PRIVS: unable to setuid()", errno);
127     }
128 
129     if (setgid(gid) < 0) {
130       privs_log_error("SETUP PRIVS: unable to setgid()", errno);
131     }
132 
133     if (seteuid(uid) < 0) {
134       privs_log_error("SETUP PRIVS: unable to seteuid()", errno);
135     }
136 #else
137     if (setgid(session.gid) < 0) {
138       privs_log_error("SETUP PRIVS: unable to setgid()", errno);
139     }
140 
141     if (setreuid(PR_ROOT_UID, session.uid) < 0) {
142       privs_log_error("SETUP PRIVS: unable to setreuid()", errno);
143     }
144 #endif /* !HAVE_SETEUID */
145   }
146 
147   pr_signals_unblock();
148   return 0;
149 }
150 
pr_privs_root(const char * file,int lineno)151 int pr_privs_root(const char *file, int lineno) {
152   if (nonroot_daemon == TRUE) {
153     pr_trace_msg(trace_channel, 9,
154       "PRIVS_ROOT called at %s:%d for nonroot daemon, ignoring", file, lineno);
155     return 0;
156   }
157 
158   pr_log_debug(DEBUG9, "ROOT PRIVS at %s:%d", file, lineno);
159 
160   if (root_privs > 0) {
161     pr_trace_msg(trace_channel, 9, "root privs count = %u, ignoring PRIVS_ROOT",
162       root_privs);
163     return 0;
164   }
165 
166   pr_trace_msg(trace_channel, 9, "root privs count = %u, honoring PRIVS_ROOT",
167     root_privs);
168   root_privs++;
169 
170   pr_signals_block();
171 
172   if (!session.disable_id_switching) {
173 
174 #if defined(HAVE_SETEUID)
175     if (seteuid(PR_ROOT_UID) < 0) {
176       privs_log_error("ROOT PRIVS: unable to seteuid()", errno);
177     }
178 
179     if (setegid(PR_ROOT_GID) < 0) {
180       privs_log_error("ROOT PRIVS: unable to setegid()", errno);
181     }
182 #else
183     if (setreuid(session.uid, PR_ROOT_UID) < 0) {
184       privs_log_error("ROOT PRIVS: unable to setreuid()", errno);
185     }
186 
187     if (setregid(session.gid, PR_ROOT_GID)) {
188       privs_log_error("ROOT PRIVS: unable to setregid()", errno);
189     }
190 #endif /* !HAVE_SETEUID */
191 
192   } else {
193     pr_log_debug(DEBUG9, "ROOT PRIVS: ID switching disabled");
194   }
195 
196   pr_signals_unblock();
197   return 0;
198 }
199 
pr_privs_user(const char * file,int lineno)200 int pr_privs_user(const char *file, int lineno) {
201   if (nonroot_daemon == TRUE) {
202     pr_trace_msg(trace_channel, 9,
203       "PRIVS_USER called at %s:%d for nonroot daemon, ignoring", file, lineno);
204     return 0;
205   }
206 
207   pr_log_debug(DEBUG9, "USER PRIVS %s at %s:%d",
208     pr_uid2str(NULL, session.login_uid), file, lineno);
209 
210   if (user_privs > 0) {
211     pr_trace_msg(trace_channel, 9, "user privs count = %u, ignoring PRIVS_USER",
212       user_privs);
213     return 0;
214   }
215 
216   pr_trace_msg(trace_channel, 9, "user privs count = %u, honoring PRIVS_USER",
217     user_privs);
218   user_privs++;
219 
220   pr_signals_block();
221 
222   if (!session.disable_id_switching) {
223 #if defined(HAVE_SETEUID)
224     if (seteuid(PR_ROOT_UID) < 0) {
225       privs_log_error("USER PRIVS: unable to seteuid(PR_ROOT_UID)", errno);
226     }
227 
228     if (setegid(session.login_gid) < 0) {
229       privs_log_error("USER PRIVS: unable to setegid(session.login_gid)",
230         errno);
231     }
232 
233     if (seteuid(session.login_uid) < 0) {
234       privs_log_error("USER PRIVS: unable to seteuid(session.login_uid)",
235         errno);
236     }
237 #else
238     if (setreuid(session.uid, PR_ROOT_UID) < 0) {
239       privs_log_error(
240         "USER PRIVS: unable to setreuid(session.uid, PR_ROOT_UID)", errno);
241     }
242 
243     if (setregid(session.gid, session.login_gid) < 0) {
244       privs_log_error(
245         "USER PRIVS: unable to setregid(session.gid, session.login_gid)",
246         errno);
247     }
248 
249     if (setreuid(session.uid, session.login_uid) < 0) {
250       privs_log_error(
251         "USER PRIVS: unable to setreuid(session.uid, session.login_uid)",
252         errno);
253     }
254 #endif /* !HAVE_SETEUID */
255 
256   } else {
257     pr_log_debug(DEBUG9, "USER PRIVS: ID switching disabled");
258   }
259 
260   pr_signals_unblock();
261   return 0;
262 }
263 
pr_privs_relinquish(const char * file,int lineno)264 int pr_privs_relinquish(const char *file, int lineno) {
265   if (nonroot_daemon == TRUE) {
266     pr_trace_msg(trace_channel, 9,
267       "PRIVS_RELINQUISH called at %s:%d for nonroot daemon, ignoring", file,
268       lineno);
269     return 0;
270   }
271 
272   pr_log_debug(DEBUG9, "RELINQUISH PRIVS at %s:%d", file, lineno);
273 
274   if (root_privs == 0 &&
275       user_privs == 0) {
276     /* No privs to relinquish here. */
277     pr_trace_msg(trace_channel, 9,
278       "user/root privs count = 0, ignoring PRIVS_RELINQUISH");
279     return 0;
280   }
281 
282   /* We only want to actually relinquish the privs (user or root) when
283    * the nesting count reaches 1.
284    */
285   if (root_privs + user_privs > 1) {
286     pr_trace_msg(trace_channel, 9,
287       "root privs count = %u, user privs count = %u, ignoring PRIVS_RELINQUISH",
288       root_privs, user_privs);
289     return 0;
290 
291   } else {
292     pr_trace_msg(trace_channel, 9, "root privs count = %u, user privs "
293       "count = %u, honoring PRIVS_RELINQUISH", root_privs, user_privs);
294   }
295 
296   pr_signals_block();
297 
298   if (!session.disable_id_switching) {
299 #if defined(HAVE_SETEUID)
300     if (geteuid() != PR_ROOT_UID) {
301       if (seteuid(PR_ROOT_UID) < 0) {
302         privs_log_error(
303           "RELINQUISH PRIVS: unable to seteuid(PR_ROOT_UID)", errno);
304       }
305 
306       if (user_privs > 0) {
307         user_privs--;
308       }
309 
310     } else {
311       if (root_privs > 0) {
312         root_privs--;
313       }
314     }
315 
316     if (setegid(session.gid) < 0) {
317       privs_log_error(
318         "RELINQUISH PRIVS: unable to setegid(session.gid)", errno);
319     }
320 
321     if (seteuid(session.uid) < 0) {
322       privs_log_error(
323         "RELINQUISH PRIVS: unable to seteuid(session.uid)", errno);
324     }
325 #else
326     if (geteuid() != PR_ROOT_UID) {
327       if (setreuid(session.uid, PR_ROOT_UID) < 0) {
328         privs_log_error(
329           "RELINQUISH PRIVS: unable to setreuid(session.uid, PR_ROOT_UID)",
330           errno);
331       }
332 
333       if (user_privs > 0) {
334         user_privs--;
335       }
336 
337     } else {
338       if (root_privs > 0) {
339         root_privs--;
340       }
341     }
342 
343     if (getegid() != PR_ROOT_GID) {
344       if (setregid(session.gid, PR_ROOT_GID) < 0) {
345         privs_log_error(
346           "RELINQUISH PRIVS: unable to setregid(session.gid, PR_ROOT_GID)",
347           errno);
348       }
349     }
350 
351     if (setregid(session.gid, session.gid)) {
352       privs_log_error(
353         "RELINQUISH PRIVS: unable to setregid(session.gid, session.gid)",
354         errno);
355     }
356 
357     if (setreuid(session.uid, session.uid)) {
358       privs_log_error(
359         "RELINQUISH PRIVS: unable to setreuid(session.uid, session.uid)",
360         errno);
361     }
362 
363 #endif /* !HAVE_SETEUID */
364   } else {
365     pr_log_debug(DEBUG9, "RELINQUISH PRIVS: ID switching disabled");
366   }
367 
368   pr_signals_unblock();
369   return 0;
370 }
371 
pr_privs_revoke(const char * file,int lineno)372 int pr_privs_revoke(const char *file, int lineno) {
373   if (nonroot_daemon == TRUE) {
374     pr_trace_msg(trace_channel, 9,
375       "PRIVS_REVOKE called at %s:%d for nonroot daemon, ignoring", file,
376       lineno);
377     return 0;
378   }
379 
380   pr_log_debug(DEBUG9, "REVOKE PRIVS at %s:%d", file, lineno);
381 
382   root_privs = user_privs = 0;
383   pr_trace_msg(trace_channel, 9, "PRIVS_REVOKE called, "
384     "clearing user/root privs count");
385 
386   pr_signals_block();
387 
388 #if defined(HAVE_SETEUID)
389   if (seteuid(PR_ROOT_UID) < 0) {
390     privs_log_error("REVOKE PRIVS: unable to seteuid()", errno);
391   }
392 
393   if (setgid(session.gid) < 0) {
394     privs_log_error("REVOKE PRIVS: unable to setgid()", errno);
395   }
396 
397   if (setuid(session.uid) < 0) {
398     privs_log_error("REVOKE PRIVS: unable to setuid()", errno);
399   }
400 #else
401   if (setreuid(PR_ROOT_UID, PR_ROOT_UID) < 0) {
402     privs_log_error(
403       "REVOKE PRIVS: unable to setreuid(PR_ROOT_UID, PR_ROOT_UID)", errno);
404   }
405 
406   if (setgid(session.gid) < 0) {
407     privs_log_error("REVOKE PRIVS: unable to setgid()", errno);
408   }
409 
410   if (setuid(session.uid) < 0) {
411     privs_log_error("REVOKE PRIVS: unable to setuid()", errno);
412   }
413 #endif /* !HAVE_SETEUID */
414 
415   pr_signals_unblock();
416   return 0;
417 }
418 
419 /* Returns the previous value, or -1 on error. */
set_nonroot_daemon(int nonroot)420 int set_nonroot_daemon(int nonroot) {
421   int was_nonroot;
422 
423   if (nonroot != TRUE &&
424       nonroot != FALSE) {
425     errno = EINVAL;
426     return -1;
427   }
428 
429   was_nonroot = nonroot_daemon;
430   nonroot_daemon = nonroot;
431 
432   return was_nonroot;
433 }
434 
init_privs(void)435 int init_privs(void) {
436   /* Check to see if we have real root privs. */
437   if (getuid() != PR_ROOT_UID) {
438     set_nonroot_daemon(TRUE);
439   }
440 
441   return 0;
442 }
443