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