1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version three of the GNU Affero General Public
8    License as published by the Free Software Foundation and included
9    in the file LICENSE.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14    Affero General Public License for more details.
15 
16    You should have received a copy of the GNU Affero General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301, USA.
20 */
21 
22 #include "include/bareos.h"
23 
24 #undef ENABLE_KEEP_READALL_CAPS_SUPPORT
25 #if defined(HAVE_SYS_PRCTL_H) && defined(HAVE_SYS_CAPABILITY_H) && \
26    defined(HAVE_PRCTL) && defined(HAVE_SETREUID) && defined(HAVE_LIBCAP)
27 #include <sys/prctl.h>
28 #include <sys/capability.h>
29 #if defined(PR_SET_KEEPCAPS)
30 #define ENABLE_KEEP_READALL_CAPS_SUPPORT
31 #endif
32 #endif
33 
34 #ifdef HAVE_AIX_OS
35 #ifndef _AIX51
36 extern "C" int initgroups(const char *,int);
37 #endif
38 #endif
39 
40 /*
41  * Lower privileges by switching to new UID and GID if non-NULL.
42  * If requested, keep readall capabilities after switch.
43  */
drop(char * uname,char * gname,bool keep_readall_caps)44 void drop(char *uname, char *gname, bool keep_readall_caps)
45 {
46 #if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
47    struct passwd *passw = NULL;
48    struct group *group = NULL;
49    gid_t gid;
50    uid_t uid;
51    char username[1000];
52 
53    Dmsg2(900, "uname=%s gname=%s\n", uname?uname:"NONE", gname?gname:"NONE");
54    if (!uname && !gname) {
55       return;                            /* Nothing to do */
56    }
57 
58    if (uname) {
59       if ((passw = getpwnam(uname)) == NULL) {
60          BErrNo be;
61          Emsg2(M_ERROR_TERM, 0, _("Could not find userid=%s: ERR=%s\n"), uname,
62             be.bstrerror());
63       }
64    } else {
65       if ((passw = getpwuid(getuid())) == NULL) {
66          BErrNo be;
67          Emsg1(M_ERROR_TERM, 0, _("Could not find password entry. ERR=%s\n"),
68             be.bstrerror());
69       } else {
70          uname = passw->pw_name;
71       }
72    }
73    /* Any OS uname pointer may get overwritten, so save name, uid, and gid */
74    bstrncpy(username, uname, sizeof(username));
75    uid = passw->pw_uid;
76    gid = passw->pw_gid;
77    if (gname) {
78       if ((group = getgrnam(gname)) == NULL) {
79          BErrNo be;
80          Emsg2(M_ERROR_TERM, 0, _("Could not find group=%s: ERR=%s\n"), gname,
81             be.bstrerror());
82       }
83       gid = group->gr_gid;
84    }
85    if (initgroups(username, gid)) {
86       BErrNo be;
87       if (gname) {
88          Emsg3(M_ERROR_TERM, 0, _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"),
89             gname, username, be.bstrerror());
90       } else {
91          Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),
92             username, be.bstrerror());
93       }
94    }
95    if (gname) {
96       if (setgid(gid)) {
97          BErrNo be;
98          Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
99             be.bstrerror());
100       }
101    }
102    if (keep_readall_caps) {
103 #ifdef ENABLE_KEEP_READALL_CAPS_SUPPORT
104       cap_t caps;
105 
106       if (prctl(PR_SET_KEEPCAPS, 1)) {
107          BErrNo be;
108          Emsg1(M_ERROR_TERM, 0, _("prctl failed: ERR=%s\n"), be.bstrerror());
109       }
110       if (setreuid(uid, uid)) {
111          BErrNo be;
112          Emsg1(M_ERROR_TERM, 0, _("setreuid failed: ERR=%s\n"), be.bstrerror());
113       }
114       if (!(caps = cap_from_text("cap_dac_read_search=ep"))) {
115          BErrNo be;
116          Emsg1(M_ERROR_TERM, 0, _("cap_from_text failed: ERR=%s\n"), be.bstrerror());
117       }
118       if (cap_set_proc(caps) < 0) {
119          BErrNo be;
120          Emsg1(M_ERROR_TERM, 0, _("cap_set_proc failed: ERR=%s\n"), be.bstrerror());
121       }
122       cap_free(caps);
123 #else
124       Emsg0(M_ERROR_TERM, 0, _("Keep readall caps not implemented this OS or missing libraries.\n"));
125 #endif
126    } else if (setuid(uid)) {
127       BErrNo be;
128       Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
129    }
130 #endif
131 }
132