1 /*
2  *
3   ***** BEGIN LICENSE BLOCK *****
4 
5   Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
6 
7   This file is part of CLIXON.
8 
9   Licensed under the Apache License, Version 2.0 (the "License");
10   you may not use this file except in compliance with the License.
11   You may obtain a copy of the License at
12 
13     http://www.apache.org/licenses/LICENSE-2.0
14 
15   Unless required by applicable law or agreed to in writing, software
16   distributed under the License is distributed on an "AS IS" BASIS,
17   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   See the License for the specific language governing permissions and
19   limitations under the License.
20 
21   Alternatively, the contents of this file may be used under the terms of
22   the GNU General Public License Version 3 or later (the "GPL"),
23   in which case the provisions of the GPL are applicable instead
24   of those above. If you wish to allow use of your version of this file only
25   under the terms of the GPL, and not to allow others to
26   use your version of this file under the terms of Apache License version 2,
27   indicate your decision by deleting the provisions above and replace them with
28   the  notice and other provisions required by the GPL. If you do not delete
29   the provisions above, a recipient may use your version of this file under
30   the terms of any one of the Apache License version 2 or the GPL.
31 
32   ***** END LICENSE BLOCK *****
33 
34   * uid, gid, privileges
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include "clixon_config.h" /* generated by config & autoconf */
39 #endif
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #define _GNU_SOURCE
45 #define __USE_GNU
46 #include <unistd.h> /* For setresuid */
47 #undef _GNU_SOURCE
48 #undef __USE_GNU
49 #include <stdarg.h>
50 #include <signal.h>
51 #include <syslog.h>
52 #include <errno.h>
53 #include <grp.h>
54 #include <pwd.h>
55 
56 /* clicon */
57 #include "clixon_err.h"
58 #include "clixon_log.h"
59 #include "clixon_uid.h"
60 
61 /*! Translate group name to gid. Return -1 if error or not found.
62  * @param[in]   name  Name of group
63  * @param[out]  gid   Group id
64  * @retval  0   OK
65  * @retval -1   Error. or not found
66  */
67 int
group_name2gid(const char * name,gid_t * gid)68 group_name2gid(const char *name,
69 	       gid_t      *gid)
70 {
71     int           retval = -1;
72     char          buf[1024];
73     struct group  g0;
74     struct group *gr = &g0;
75     struct group *gtmp;
76 
77     gr = &g0;
78     /* This leaks memory in ubuntu */
79     if (getgrnam_r(name, gr, buf, sizeof(buf), &gtmp) < 0){
80 	clicon_err(OE_UNIX, errno, "getgrnam_r(%s)", name);
81 	goto done;
82     }
83     if (gtmp == NULL){
84 	clicon_err(OE_UNIX, 0, "No such group: %s", name);
85 	goto done;
86     }
87     if (gid)
88 	*gid = gr->gr_gid;
89     retval = 0;
90  done:
91     return retval;
92 }
93 
94 /*! Translate user name to uid. Return -1 if error or not found.
95  * @param[in]  name Name of user
96  * @param[out] uid  User id
97  * @retval     0    OK
98  * @retval    -1    Error. or not found
99  */
100 int
name2uid(const char * name,uid_t * uid)101 name2uid(const char *name,
102 	 uid_t      *uid)
103 {
104     int            retval = -1;
105     char           buf[1024];
106     struct passwd  pwbuf;
107     struct passwd *pwbufp = NULL;
108 
109     if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
110 	clicon_err(OE_UNIX, errno, "getpwnam_r(%s)", name);
111 	goto done;
112     }
113     if (pwbufp == NULL){
114 	clicon_err(OE_UNIX, 0, "No such user: %s", name);
115 	goto done;
116     }
117     if (uid)
118 	*uid = pwbufp->pw_uid;
119     retval = 0;
120  done:
121     return retval;
122 }
123 
124 /*! Translate uid to user name
125  * @param[in]  uid  User id
126  * @param[out] name User name (Malloced, need to be freed)
127  * @retval     0    OK
128  * @retval     -1   Error. or not found
129  */
130 int
uid2name(const uid_t uid,char ** name)131 uid2name(const uid_t uid,
132 	 char      **name)
133 {
134     int            retval = -1;
135     char           buf[1024];
136     struct passwd  pwbuf = {0,};
137     struct passwd *pwbufp = NULL;
138 
139     if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
140 	clicon_err(OE_UNIX, errno, "getpwuid_r(%u)", uid);
141 	goto done;
142     }
143     if (pwbufp == NULL){
144 	clicon_err(OE_UNIX, ENOENT, "No such user: %u", uid);
145 	goto done;
146     }
147 
148     if (name){
149 	if ((*name = strdup(pwbufp->pw_name)) == NULL){
150 	    clicon_err(OE_UNIX, errno, "strdup");
151 	    goto done;
152 	}
153     }
154     retval = 0;
155  done:
156     return retval;
157 }
158 
159 /* Privileges drop perm, temp and restore
160  * @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
161  */
162  /*! Temporarily drop privileges
163  * @param[in]  new_uid
164  */
165 int
drop_priv_temp(uid_t new_uid)166 drop_priv_temp(uid_t new_uid)
167 {
168     int retval = -1;
169 
170     /* XXX: implicit declaration of function 'setresuid' on travis */
171     if (setresuid(-1, new_uid, geteuid()) < 0){
172 	clicon_err(OE_UNIX, errno, "setresuid");
173 	goto done;
174     }
175     if (geteuid() != new_uid){
176 	clicon_err(OE_UNIX, errno, "geteuid");
177 	goto done;
178     }
179     retval = 0;
180  done:
181     return retval;
182 }
183 
184 /*! Permanently drop privileges
185  * @param[in]  new_uid
186  */
187 int
drop_priv_perm(uid_t new_uid)188 drop_priv_perm(uid_t new_uid)
189 {
190     int retval = -1;
191     uid_t ruid;
192     uid_t euid;
193     uid_t suid;
194 
195     if (setresuid(new_uid, new_uid, new_uid) < 0){
196 	clicon_err(OE_UNIX, errno, "setresuid");
197 	goto done;
198     }
199     if (getresuid(&ruid, &euid, &suid) < 0){
200 	clicon_err(OE_UNIX, errno, "getresuid");
201 	goto done;
202     }
203     if (ruid != new_uid ||
204 	euid != new_uid ||
205 	suid != new_uid){
206 	clicon_err(OE_UNIX, EINVAL, "Non-matching uid");
207 	goto done;
208     }
209     retval = 0;
210  done:
211     return retval;
212 }
213 
214 /*! Restore privileges to saved level */
215 int
restore_priv(void)216 restore_priv(void)
217 {
218     int retval = -1;
219     uid_t ruid;
220     uid_t euid;
221     uid_t suid;
222 
223     if (getresuid(&ruid, &euid, &suid) < 0){
224 	clicon_err(OE_UNIX, errno, "setresuid");
225 	goto done;
226     }
227     if (setresuid(-1, suid, -1) < 0){
228 	clicon_err(OE_UNIX, errno, "setresuid");
229 	goto done;
230     }
231     if (geteuid() != suid){
232 	clicon_err(OE_UNIX, EINVAL, "Non-matching uid");
233 	goto done;
234     }
235     retval = 0;
236  done:
237     return retval;
238 }
239