1 /*
2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
3 * Inferno Nettverk A/S, Norway. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. The above copyright notice, this list of conditions and the following
9 * disclaimer must appear in all copies of the software, derivative works
10 * or modified versions, and any portions thereof, aswell as in all
11 * supporting documentation.
12 * 2. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by
15 * Inferno Nettverk A/S, Norway.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Inferno Nettverk A/S requests users of this software to return to
31 *
32 * Software Distribution Coordinator or sdc@inet.no
33 * Inferno Nettverk A/S
34 * Oslo Research Park
35 * Gaustadall�en 21
36 * NO-0349 Oslo
37 * Norway
38 *
39 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40 * the rights to redistribute these changes.
41 *
42 */
43
44 #include "common.h"
45
46 static const char rcsid[] =
47 "$Id: privileges.c,v 1.64.4.2 2014/08/15 18:16:42 karls Exp $";
48
49 static privilege_t lastprivelege = SOCKD_PRIV_NOTSET;
50
51 int
sockd_initprivs(void)52 sockd_initprivs(void)
53 {
54 const char *function = "sockd_initprivs()";
55
56 #if HAVE_SOLARIS_PRIVS
57 char *privstr;
58 priv_set_t *privset;
59 const char *extra_privs[] = {
60 PRIV_FILE_DAC_READ, /* password file, and pam? */
61 PRIV_FILE_DAC_SEARCH, /* password file, and pam? */
62 PRIV_FILE_DAC_WRITE, /* writing pidfile. */
63 PRIV_NET_PRIVADDR, /*
64 * binding ports < 1024 on behalf of the client,
65 * if so configured.
66 */
67 PRIV_PROC_LOCK_MEMORY, /* shmem; want it paged in as locks are used. */
68 #if HAVE_UDP_SUPPORT
69 PRIV_NET_ICMPACCESS, /*
70 * sending/receiving icmp errors related to sent
71 * udp packets.
72 */
73 #endif /* HAVE_UDP_SUPPORT */
74 };
75 size_t i;
76
77 if ((sockscf.privileges.privileged = priv_allocset()) == NULL
78 || (sockscf.privileges.unprivileged = priv_allocset()) == NULL) {
79 swarn("%s: priv_allocset()", function);
80 return -1;
81 }
82
83 if ((privset = priv_str_to_set ("basic", ",", NULL)) == NULL) {
84 swarn("%s: priv_str_to_set failed", function);
85 return -1;
86 }
87
88 /*
89 * First add/remove what we need from the basic set and save it as the
90 * unprivileged set. The unprivileged set is also the set used by libwrap.
91 */
92
93 /* add ... Nothing. */
94
95 #if 0
96 /* ... and remove. */
97
98 /*
99 * removing this would mean libwraps exec statement won't work, but
100 * probably nobody uses that from sockd anyway. Could it be needed
101 * by pam, though? Leave it in for now.
102 */
103 if (priv_delset(privset, PRIV_PROC_EXEC) != 0) {
104 swarn("%s: cannot remove %s privilege", function, PRIV_PROC_EXEC);
105 return -1;
106 }
107 #endif
108
109 priv_copyset(privset, sockscf.privileges.unprivileged);
110
111 /*
112 * Then add the extra privileges we need.
113 */
114
115 for (i = 0; i < ELEMENTS(extra_privs); ++i)
116 if (priv_addset(privset, extra_privs[i]) != 0) {
117 swarn("%s: cannot add %s privilege", function, extra_privs[i]);
118 return -1;
119 }
120 else
121 slog(LOG_DEBUG, "%s: added privilege %s to the privileged set",
122 function, extra_privs[i]);
123
124 /*
125 * any privileges we may ever need.
126 */
127
128 priv_copyset(privset, sockscf.privileges.privileged);
129 priv_freeset(privset);
130
131 if ((privstr = priv_set_to_str(sockscf.privileges.privileged,
132 ',',
133 PRIV_STR_LIT)) == NULL)
134 swarn("%s: priv_set_to_str(sockscf.privileges.privileged) failed",
135 function);
136
137 if (setppriv(PRIV_SET, PRIV_PERMITTED, sockscf.privileges.privileged) == -1){
138 swarn("%s: cannot set the PRIV_PERMITTED privilege set (%s)",
139 function, privstr == NULL ? "" : privstr);
140
141 free(privstr);
142 return -1;
143 }
144
145 slog(LOG_DEBUG, "%s: using the following privileges for PRIV_PERMITTED: %s",
146 function, privstr == NULL ? "<error>" : privstr);
147
148 free(privstr);
149
150 /*
151 * unprivileged is what we'll be running with normally.
152 */
153
154 if ((privstr = priv_set_to_str(sockscf.privileges.unprivileged,
155 ',',
156 PRIV_STR_LIT)) == NULL)
157 swarn("%s: priv_set_to_str(sockscf.privileges.unprivileged) failed",
158 function);
159
160 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, sockscf.privileges.unprivileged)
161 == -1) {
162 swarn("%s: cannot set the PRIV_EFFECTIVE privilege set (%s)",
163 function, privstr == NULL ? "" : privstr);
164
165 free(privstr);
166 return -1;
167 }
168
169 /*
170 * Same for inherited. Only applies to libwrap's exec statement, and
171 * PAM?
172 */
173 if (setppriv(PRIV_SET, PRIV_INHERITABLE, sockscf.privileges.unprivileged)
174 == -1) {
175 swarn("%s: cannot set PRIV_INHERITABLE privilege set (%s)",
176 function, privstr == NULL ? "" : privstr);
177
178 free(privstr);
179 return -1;
180 }
181
182 slog(LOG_DEBUG, "%s: using the following privileges for PRIV_EFFECTIVE "
183 "and PRIV_INHERITABLE: %s",
184 function, privstr == NULL ? "<error>" : privstr);
185
186 free(privstr);
187
188 setreuid(getuid(), getuid());
189 setregid(getgid(), getgid());
190
191 slog(LOG_DEBUG, "%s: privileges relinquished successfully", function);
192
193 /* should be able to use special privileges. */
194 sockscf.state.haveprivs = 1;
195
196 #else /* !HAVE_SOLARIS_PRIVS */
197
198 if (geteuid() == 0)
199 /* should be able to use special privileges. */
200 sockscf.state.haveprivs = 1;
201
202 if (setegid(sockscf.uid.unprivileged_gid) != 0) {
203 swarn("%s: setegid(2) to unprivileged gid %lu failed",
204 function, (unsigned long)sockscf.uid.unprivileged_gid);
205
206 sockscf.state.haveprivs = 0;
207 return -1;
208 }
209 sockscf.state.egid = sockscf.uid.unprivileged_gid;
210
211 if (seteuid(sockscf.uid.unprivileged_uid) != 0) {
212 swarn("%s: seteuid(2) to unprivileged uid %lu failed",
213 function, (unsigned long)sockscf.uid.unprivileged_uid);
214
215 sockscf.state.haveprivs = 0;
216 return -1;
217 }
218 sockscf.state.euid = sockscf.uid.unprivileged_uid;
219
220 slog(LOG_DEBUG, "%s: will use euid/egid %lu/%lu normally",
221 function,
222 (unsigned long)sockscf.uid.unprivileged_uid,
223 (unsigned long)sockscf.uid.unprivileged_gid);
224
225 #endif /* !HAVE_SOLARIS_PRIVS */
226
227 return 0;
228 }
229
230 void
sockd_priv(privilege,op)231 sockd_priv(privilege, op)
232 const privilege_t privilege;
233 const priv_op_t op;
234 {
235 const char *function = "sockd_priv()";
236 #if HAVE_PRIVILEGES
237 static priv_set_t *lastprivset;
238
239 #else /* !HAVE_PRIVILEGES */
240 static uid_t lasteuid;
241 static gid_t lastegid;
242 int p;
243
244 #endif /* !HAVE_PRIVILEGES */
245
246 if (!sockscf.state.haveprivs)
247 return;
248
249 slog(LOG_DEBUG, "%s: switching privilege %d %s",
250 function, (int)privilege, privop2string(op));
251
252 #define FULLSETS \
253 SOCKD_PRIV_LIBWRAP: \
254 case SOCKD_PRIV_PRIVILEGED: \
255 case SOCKD_PRIV_UNPRIVILEGED: \
256 case SOCKD_PRIV_PAM: \
257 case SOCKD_PRIV_BSDAUTH
258
259 #if HAVE_PRIVILEGES
260 if (lastprivset == NULL)
261 if ((lastprivset = priv_allocset()) == NULL) {
262 serr("%s: priv_allocset()", function);
263 }
264 #endif /* HAVE_PRIVILEGES */
265
266 /*
267 * these asserts are only valid as long as we never turn more than
268 * one privilege on/off at a time. If that ever changes, we need
269 * to remove these asserts, but until then, they are useful.
270 */
271 if (op == PRIV_ON) {
272 SASSERTX(lastprivelege == SOCKD_PRIV_NOTSET);
273 lastprivelege = privilege;
274
275 #if HAVE_PRIVILEGES
276 switch (privilege) {
277 case FULLSETS:
278 /*
279 * needs to be handled special as it's not a single privilege
280 * we turn on/off, but a full set we PRIV_SET.
281 */
282 if (getppriv(PRIV_EFFECTIVE, lastprivset) != 0) {
283 swarn("%s: very strange ... getppriv(PRIV_EFFECTIVE) failed. "
284 "This might not work out too well ...",
285 function);
286 SWARN(errno);
287 }
288 break;
289
290 default:
291 break;
292 }
293 #endif /* HAVE_PRIVILEGES */
294 }
295 else {
296 SASSERTX(op == PRIV_OFF);
297 SASSERTX(lastprivelege == privilege);
298 lastprivelege = SOCKD_PRIV_NOTSET;
299 }
300
301 switch (privilege) {
302 case FULLSETS: {
303 #if HAVE_PRIVILEGES
304 priv_set_t *privtoset;
305
306 #else /* !HAVE_PRIVILEGES */
307 uid_t neweuid;
308 gid_t newegid;
309
310 if (op == PRIV_ON) {
311 lasteuid = sockscf.state.euid;
312 lastegid = sockscf.state.egid;
313 }
314
315 #endif /* HAVE_PRIVILEGES */
316
317 if (op == PRIV_ON) {
318 switch (privilege) {
319 case SOCKD_PRIV_PRIVILEGED:
320 case SOCKD_PRIV_PAM:
321 case SOCKD_PRIV_BSDAUTH:
322 #if HAVE_PRIVILEGES
323
324 privtoset = sockscf.privileges.privileged;
325
326 #else /* !HAVE_PRIVILEGES */
327
328 neweuid = sockscf.uid.privileged_uid;
329 newegid = sockscf.uid.privileged_gid;
330 #endif /* HAVE_PRIVILEGES */
331
332 break;
333
334 case SOCKD_PRIV_UNPRIVILEGED:
335 #if HAVE_PRIVILEGES
336
337 privtoset = sockscf.privileges.unprivileged;
338
339 #else /* !HAVE_PRIVILEGES */
340
341 neweuid = sockscf.uid.unprivileged_uid;
342 newegid = sockscf.uid.unprivileged_gid;
343 #endif /* HAVE_PRIVILEGES */
344
345 break;
346
347 case SOCKD_PRIV_LIBWRAP:
348 #if HAVE_PRIVILEGES
349
350 privtoset = sockscf.privileges.unprivileged;/* same for now */
351
352 #else /* !HAVE_PRIVILEGES */
353
354 neweuid = sockscf.uid.libwrap_uid;
355 newegid = sockscf.uid.libwrap_gid;
356 #endif /* HAVE_PRIVILEGES */
357
358 break;
359
360 default:
361 SERRX(privilege);
362 }
363 }
364 else {
365 #if HAVE_PRIVILEGES
366
367 privtoset = lastprivset;
368
369 #else /* !HAVE_PRIVILEGES */
370
371 neweuid = lasteuid;
372 newegid = lastegid;
373 #endif /* HAVE_PRIVILEGES */
374 }
375
376 #if HAVE_PRIVILEGES
377 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privtoset) != 0)
378 serr("%s: switching privilege level %d %s failed",
379 function, (int)privilege, privop2string(op));
380
381 #else /* !HAVE_PRIVILEGES */
382 if (sockd_seteugid(neweuid, newegid) != 0)
383 serr("%s: switching to euid/egid %u/%u failed",
384 function,
385 op == PRIV_ON ? (unsigned )neweuid : (unsigned )lasteuid,
386 op == PRIV_ON ? (unsigned )newegid : (unsigned )lastegid);
387 #endif /* HAVE_PRIVILEGES */
388
389 break;
390 }
391
392 case SOCKD_PRIV_FILE_READ:
393 case SOCKD_PRIV_GSSAPI:
394 #if HAVE_PRIVILEGES
395 if (priv_set(op, PRIV_EFFECTIVE, PRIV_FILE_DAC_SEARCH, NULL) != 0)
396 serr("%s: switching PRIV_FILE_DAC_SEARCH %s failed",
397 function, privop2string(op));
398
399 if (priv_set(op, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL) != 0)
400 serr("%s: switching PRIV_FILE_DAC_READ %s failed",
401 function, privop2string(op));
402
403 #else /* !HAVE_PRIVILEGES */
404 if (op == PRIV_ON)
405 p = sockd_seteugid(sockscf.uid.privileged_uid,
406 sockscf.uid.privileged_gid);
407 else
408 p = sockd_seteugid(lasteuid, lastegid);
409
410 if (p != 0)
411 serr("%s: switching to euid/egid %u/%u failed",
412 function,
413 op == PRIV_ON ?
414 (unsigned)sockscf.uid.privileged_uid : (unsigned)lasteuid,
415 op == PRIV_ON ?
416 (unsigned)sockscf.uid.privileged_gid : (unsigned)lastegid);
417 #endif /* !HAVE_PRIVILEGES */
418
419 break;
420
421 case SOCKD_PRIV_FILE_WRITE:
422 #if HAVE_PRIVILEGES
423 if (priv_set(op, PRIV_EFFECTIVE, PRIV_FILE_DAC_SEARCH, NULL) != 0)
424 serr("%s: switching PRIV_FILE_DAC_SEARCH %s failed",
425 function, privop2string(op));
426
427 if (priv_set(op, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL) != 0)
428 serr("%s: switching PRIV_FILE_DAC_READ %s failed",
429 function, privop2string(op));
430
431 if (priv_set(op, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL) != 0)
432 serr("%s: switching PRIV_FILE_DAC_WRITE %s failed",
433 function, privop2string(op));
434
435 #else /* !HAVE_PRIVILEGES */
436 if (op == PRIV_ON)
437 p = sockd_seteugid(sockscf.uid.privileged_uid,
438 sockscf.uid.privileged_gid);
439 else
440 p = sockd_seteugid(lasteuid, lastegid);
441
442 if (p != 0)
443 serr("%s: switching to euid/egid %u/%u failed",
444 function,
445 op == PRIV_ON ?
446 (unsigned)sockscf.uid.privileged_uid : (unsigned)lasteuid,
447 op == PRIV_ON ?
448 (unsigned)sockscf.uid.privileged_gid : (unsigned)lastegid);
449 #endif /* !HAVE_PRIVILEGES */
450
451 break;
452
453 case SOCKD_PRIV_NET_ADDR:
454 #if HAVE_PRIVILEGES
455 if (priv_set(op, PRIV_EFFECTIVE, PRIV_NET_PRIVADDR, NULL) != 0)
456 serr("%s: switching PRIV_NET_PRIVADDR %s failed",
457 function, privop2string(op));
458
459 #else /* !HAVE_PRIVILEGES */
460 if (op == PRIV_ON)
461 p = sockd_seteugid(sockscf.uid.privileged_uid,
462 sockscf.uid.privileged_uid);
463 else
464 p = sockd_seteugid(lasteuid, lastegid);
465
466 if (p != 0)
467 serr("%s: switching to euid/egid %u/%u failed",
468 function,
469 op == PRIV_ON ?
470 (unsigned)sockscf.uid.privileged_uid : (unsigned)lasteuid,
471 op == PRIV_ON ?
472 (unsigned)sockscf.uid.privileged_gid : (unsigned)lastegid);
473 #endif /* !HAVE_PRIVILEGES */
474
475 break;
476
477 case SOCKD_PRIV_NET_ICMPACCESS:
478 #if HAVE_PRIVILEGES
479 if (priv_set(op, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS, NULL) != 0)
480 serr("%s: switching PRIV_NET_ICMPACCESS %s failed",
481 function, privop2string(op));
482
483 #else /* !HAVE_PRIVILEGES */
484 if (op == PRIV_ON)
485 p = sockd_seteugid(sockscf.uid.privileged_uid,
486 sockscf.uid.privileged_uid);
487 else
488 p = sockd_seteugid(lasteuid, lastegid);
489
490 if (p != 0)
491 serr("%s: switching to euid/egid %u/%u failed",
492 function,
493 op == PRIV_ON ?
494 (unsigned)sockscf.uid.privileged_uid : (unsigned)lasteuid,
495 op == PRIV_ON ?
496 (unsigned)sockscf.uid.privileged_gid : (unsigned)lastegid);
497 #endif /* !HAVE_PRIVILEGES */
498
499 break;
500
501 case SOCKD_PRIV_NET_ROUTESOCKET:
502 #if HAVE_PRIVILEGES
503 /* nothing special required on Solaris apparently. */
504
505 #else /* !HAVE_PRIVILEGES */
506 if (op == PRIV_ON)
507 p = sockd_seteugid(sockscf.uid.privileged_uid,
508 sockscf.uid.privileged_gid);
509 else
510 p = sockd_seteugid(lasteuid, lastegid);
511
512 if (p != 0)
513 serr("%s: switching to euid/egid %u/%u failed",
514 function,
515 op == PRIV_ON ?
516 (unsigned)sockscf.uid.privileged_uid : (unsigned)lasteuid,
517 op == PRIV_ON ?
518 (unsigned)sockscf.uid.privileged_gid : (unsigned)lastegid);
519 #endif /* !HAVE_PRIVILEGES */
520
521 break;
522
523 default:
524 SERRX(privilege);
525 }
526 }
527
528 void
resetprivileges(void)529 resetprivileges(void)
530 {
531 const char *function = "resetprivileges()";
532
533 slog(LOG_DEBUG, "%s: euid/egid %ld/%ld",
534 function, (long)geteuid(), (long)getegid());
535
536 #if !HAVE_PRIVILEGES
537 if (sockscf.uid.privileged_uid == sockscf.uid.unprivileged_uid
538 && sockscf.uid.privileged_uid == sockscf.uid.libwrap_uid
539 && sockscf.uid.privileged_uid != geteuid()) {
540 slog(LOG_DEBUG,
541 "%s: no alternate userids configured for use. Will use uid %lu "
542 "in all contexts and permanently drop all others",
543 function, (unsigned long)sockscf.uid.unprivileged_uid);
544
545 (void)seteuid(0);
546
547 if (setgid(sockscf.uid.unprivileged_gid) != 0) {
548 if (getegid() != sockscf.uid.unprivileged_gid
549 || getgid() != sockscf.uid.unprivileged_gid)
550 serr("setgid(2) to unprivileged gid %lu failed",
551 (unsigned long)sockscf.uid.unprivileged_gid);
552 }
553
554 if (setuid(sockscf.uid.unprivileged_uid) != 0) {
555 if (geteuid() != sockscf.uid.unprivileged_uid
556 || getuid() != sockscf.uid.unprivileged_uid)
557 serr("setuid(2) to unprivileged uid %lu failed",
558 (unsigned long)sockscf.uid.unprivileged_uid);
559 }
560
561 sockscf.state.egid = sockscf.uid.unprivileged_gid;
562 sockscf.state.euid = sockscf.uid.unprivileged_uid;
563
564 sockscf.state.haveprivs = 0; /* don't have it anymore. */
565 }
566 #endif /* !HAVE_PRIVILEGES */
567 }
568
569
570 #if !HAVE_PRIVILEGES
571 int
sockd_seteugid(uid,gid)572 sockd_seteugid(uid, gid)
573 const uid_t uid;
574 const gid_t gid;
575 {
576 const char *function = "sockd_setugid()";
577
578 if (sockscf.state.inited && !sockscf.state.haveprivs)
579 return -1;
580
581 slog(LOG_DEBUG, "%s: old uid/gid: %lu/%lu, new: %lu/%lu",
582 function,
583 (unsigned long)sockscf.state.euid,
584 (unsigned long)sockscf.state.egid,
585 (unsigned long)uid,
586 (unsigned long)gid);
587
588 #if DIAGNOSTIC
589 SASSERTX(geteuid() == sockscf.state.euid);
590 SASSERTX(getegid() == sockscf.state.egid);
591 #endif /* DIAGNOSTIC */
592
593 if (sockscf.state.euid == uid
594 && sockscf.state.egid == gid)
595 return 0;
596
597 if (sockscf.state.euid != 0) {
598 /* revert back to original (presumably 0) euid before changing. */
599 if (seteuid(sockscf.initial.euid) != 0) {
600 swarn("%s: failed revering to original euid %lu",
601 function, (unsigned long)sockscf.initial.euid);
602
603 return -1;
604 }
605 }
606
607 /* first the groupid ... */
608 if (setegid(gid) != 0) {
609 swarn("%s: setegid(2) to gid %lu from euid/egid %lu/%lu failed",
610 function,
611 (unsigned long)gid,
612 (unsigned long)sockscf.state.euid,
613 (unsigned long)sockscf.state.egid);
614
615 return -1;
616 }
617
618 sockscf.state.egid = gid;
619
620 /* ... and then the uid. */
621 if (seteuid(uid) != 0) {
622 swarn("%s: seteuid(2) to uid %lu from euid/egid %lu/%lu failed",
623 function,
624 (unsigned long)uid,
625 (unsigned long)sockscf.state.euid,
626 (unsigned long)sockscf.state.egid);
627
628 return -1;
629 }
630
631 sockscf.state.euid = uid;
632
633 return 0;
634 }
635
636 #endif /* !HAVE_PRIVILEGES */
637