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 #include "lib/berrno.h"
24 
25 #undef ENABLE_KEEP_READALL_CAPS_SUPPORT
26 #if defined(HAVE_SYS_PRCTL_H) && defined(HAVE_SYS_CAPABILITY_H) && \
27     defined(HAVE_PRCTL) && defined(HAVE_SETREUID) && defined(HAVE_LIBCAP)
28 #include <sys/prctl.h>
29 #include <sys/capability.h>
30 #if defined(PR_SET_KEEPCAPS)
31 #define ENABLE_KEEP_READALL_CAPS_SUPPORT
32 #endif
33 #endif
34 
35 #ifdef HAVE_AIX_OS
36 #ifndef _AIX51
37 extern "C" int initgroups(const char*, int);
38 #endif
39 #endif
40 
41 /*
42  * Lower privileges by switching to new UID and GID if non-NULL.
43  * If requested, keep readall capabilities after switch.
44  */
drop(char * uname,char * gname,bool keep_readall_caps)45 void drop(char* uname, char* gname, bool keep_readall_caps)
46 {
47 #if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
48   struct passwd* passw = NULL;
49   struct group* group = NULL;
50   gid_t gid;
51   uid_t uid;
52   char username[1000];
53 
54   Dmsg2(900, "uname=%s gname=%s\n", uname ? uname : "NONE",
55         gname ? gname : "NONE");
56   if (!uname && !gname) { return; /* Nothing to do */ }
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,
89             _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"), gname,
90             username, be.bstrerror());
91     } else {
92       Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),
93             username, be.bstrerror());
94     }
95   }
96   if (gname) {
97     if (setgid(gid)) {
98       BErrNo be;
99       Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
100             be.bstrerror());
101     }
102   }
103   if (keep_readall_caps) {
104 #ifdef ENABLE_KEEP_READALL_CAPS_SUPPORT
105     cap_t caps;
106 
107     if (prctl(PR_SET_KEEPCAPS, 1)) {
108       BErrNo be;
109       Emsg1(M_ERROR_TERM, 0, _("prctl failed: ERR=%s\n"), be.bstrerror());
110     }
111     if (setreuid(uid, uid)) {
112       BErrNo be;
113       Emsg1(M_ERROR_TERM, 0, _("setreuid failed: ERR=%s\n"), be.bstrerror());
114     }
115     if (!(caps = cap_from_text("cap_dac_read_search=ep"))) {
116       BErrNo be;
117       Emsg1(M_ERROR_TERM, 0, _("cap_from_text failed: ERR=%s\n"),
118             be.bstrerror());
119     }
120     if (cap_set_proc(caps) < 0) {
121       BErrNo be;
122       Emsg1(M_ERROR_TERM, 0, _("cap_set_proc failed: ERR=%s\n"),
123             be.bstrerror());
124     }
125     cap_free(caps);
126 #else
127     Emsg0(
128         M_ERROR_TERM, 0,
129         _("Keep readall caps not implemented this OS or missing libraries.\n"));
130 #endif
131   } else if (setuid(uid)) {
132     BErrNo be;
133     Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
134   }
135 #endif
136 }
137