]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/user-util.c
util: remove lookup_uid(), replace by uid_to_name()
[thirdparty/systemd.git] / src / basic / user-util.c
CommitLineData
b1d4f8e1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <pwd.h>
23#include <grp.h>
24
25#include "user-util.h"
26#include "macro.h"
27#include "util.h"
28#include "string-util.h"
29#include "path-util.h"
30
31bool uid_is_valid(uid_t uid) {
32
33 /* Some libc APIs use UID_INVALID as special placeholder */
b1d52773 34 if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
b1d4f8e1
LP
35 return false;
36
37 /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
b1d52773 38 if (uid == (uid_t) UINT32_C(0xFFFF))
b1d4f8e1
LP
39 return false;
40
41 return true;
42}
43
b1d52773
LP
44int parse_uid(const char *s, uid_t *ret) {
45 uint32_t uid = 0;
b1d4f8e1
LP
46 int r;
47
48 assert(s);
49
b1d52773
LP
50 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
51 r = safe_atou32(s, &uid);
b1d4f8e1
LP
52 if (r < 0)
53 return r;
54
b1d4f8e1
LP
55 if (!uid_is_valid(uid))
56 return -ENXIO; /* we return ENXIO instead of EINVAL
57 * here, to make it easy to distuingish
58 * invalid numeric uids invalid
59 * strings. */
60
b1d52773
LP
61 if (ret)
62 *ret = uid;
b1d4f8e1
LP
63
64 return 0;
65}
66
b1d4f8e1
LP
67char* getlogname_malloc(void) {
68 uid_t uid;
69 struct stat st;
70
71 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
72 uid = st.st_uid;
73 else
74 uid = getuid();
75
d0260817 76 return uid_to_name(uid);
b1d4f8e1
LP
77}
78
79char *getusername_malloc(void) {
80 const char *e;
81
82 e = getenv("USER");
83 if (e)
84 return strdup(e);
85
d0260817 86 return uid_to_name(getuid());
b1d4f8e1
LP
87}
88
89int get_user_creds(
90 const char **username,
91 uid_t *uid, gid_t *gid,
92 const char **home,
93 const char **shell) {
94
95 struct passwd *p;
96 uid_t u;
97
98 assert(username);
99 assert(*username);
100
101 /* We enforce some special rules for uid=0: in order to avoid
102 * NSS lookups for root we hardcode its data. */
103
104 if (streq(*username, "root") || streq(*username, "0")) {
105 *username = "root";
106
107 if (uid)
108 *uid = 0;
109
110 if (gid)
111 *gid = 0;
112
113 if (home)
114 *home = "/root";
115
116 if (shell)
117 *shell = "/bin/sh";
118
119 return 0;
120 }
121
122 if (parse_uid(*username, &u) >= 0) {
123 errno = 0;
124 p = getpwuid(u);
125
126 /* If there are multiple users with the same id, make
127 * sure to leave $USER to the configured value instead
128 * of the first occurrence in the database. However if
129 * the uid was configured by a numeric uid, then let's
130 * pick the real username from /etc/passwd. */
131 if (p)
132 *username = p->pw_name;
133 } else {
134 errno = 0;
135 p = getpwnam(*username);
136 }
137
138 if (!p)
139 return errno > 0 ? -errno : -ESRCH;
140
141 if (uid)
142 *uid = p->pw_uid;
143
144 if (gid)
145 *gid = p->pw_gid;
146
147 if (home)
148 *home = p->pw_dir;
149
150 if (shell)
151 *shell = p->pw_shell;
152
153 return 0;
154}
155
156int get_group_creds(const char **groupname, gid_t *gid) {
157 struct group *g;
158 gid_t id;
159
160 assert(groupname);
161
162 /* We enforce some special rules for gid=0: in order to avoid
163 * NSS lookups for root we hardcode its data. */
164
165 if (streq(*groupname, "root") || streq(*groupname, "0")) {
166 *groupname = "root";
167
168 if (gid)
169 *gid = 0;
170
171 return 0;
172 }
173
174 if (parse_gid(*groupname, &id) >= 0) {
175 errno = 0;
176 g = getgrgid(id);
177
178 if (g)
179 *groupname = g->gr_name;
180 } else {
181 errno = 0;
182 g = getgrnam(*groupname);
183 }
184
185 if (!g)
186 return errno > 0 ? -errno : -ESRCH;
187
188 if (gid)
189 *gid = g->gr_gid;
190
191 return 0;
192}
193
194char* uid_to_name(uid_t uid) {
d0260817
LP
195 char *ret;
196 int r;
b1d4f8e1 197
d0260817 198 /* Shortcut things to avoid NSS lookups */
b1d4f8e1
LP
199 if (uid == 0)
200 return strdup("root");
201
d0260817
LP
202 if (uid_is_valid(uid)) {
203 long bufsize;
204
205 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
206 if (bufsize <= 0)
207 bufsize = 4096;
208
209 for (;;) {
210 struct passwd pwbuf, *pw = NULL;
211 _cleanup_free_ char *buf = NULL;
212
213 buf = malloc(bufsize);
214 if (!buf)
215 return NULL;
216
217 r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
218 if (r == 0 && pw)
219 return strdup(pw->pw_name);
220 if (r != ERANGE)
221 break;
222
223 bufsize *= 2;
224 }
225 }
b1d4f8e1 226
d0260817 227 if (asprintf(&ret, UID_FMT, uid) < 0)
b1d4f8e1
LP
228 return NULL;
229
d0260817 230 return ret;
b1d4f8e1
LP
231}
232
233char* gid_to_name(gid_t gid) {
d0260817
LP
234 char *ret;
235 int r;
b1d4f8e1
LP
236
237 if (gid == 0)
238 return strdup("root");
239
d0260817
LP
240 if (gid_is_valid(gid)) {
241 long bufsize;
242
243 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
244 if (bufsize <= 0)
245 bufsize = 4096;
246
247 for (;;) {
248 struct group grbuf, *gr = NULL;
249 _cleanup_free_ char *buf = NULL;
250
251 buf = malloc(bufsize);
252 if (!buf)
253 return NULL;
254
255 r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
256 if (r == 0 && gr)
257 return strdup(gr->gr_name);
258 if (r != ERANGE)
259 break;
260
261 bufsize *= 2;
262 }
263 }
b1d4f8e1 264
d0260817 265 if (asprintf(&ret, GID_FMT, gid) < 0)
b1d4f8e1
LP
266 return NULL;
267
d0260817 268 return ret;
b1d4f8e1
LP
269}
270
271int in_gid(gid_t gid) {
272 gid_t *gids;
273 int ngroups_max, r, i;
274
275 if (getgid() == gid)
276 return 1;
277
278 if (getegid() == gid)
279 return 1;
280
281 ngroups_max = sysconf(_SC_NGROUPS_MAX);
282 assert(ngroups_max > 0);
283
284 gids = alloca(sizeof(gid_t) * ngroups_max);
285
286 r = getgroups(ngroups_max, gids);
287 if (r < 0)
288 return -errno;
289
290 for (i = 0; i < r; i++)
291 if (gids[i] == gid)
292 return 1;
293
294 return 0;
295}
296
297int in_group(const char *name) {
298 int r;
299 gid_t gid;
300
301 r = get_group_creds(&name, &gid);
302 if (r < 0)
303 return r;
304
305 return in_gid(gid);
306}
307
308int get_home_dir(char **_h) {
309 struct passwd *p;
310 const char *e;
311 char *h;
312 uid_t u;
313
314 assert(_h);
315
316 /* Take the user specified one */
317 e = secure_getenv("HOME");
318 if (e && path_is_absolute(e)) {
319 h = strdup(e);
320 if (!h)
321 return -ENOMEM;
322
323 *_h = h;
324 return 0;
325 }
326
327 /* Hardcode home directory for root to avoid NSS */
328 u = getuid();
329 if (u == 0) {
330 h = strdup("/root");
331 if (!h)
332 return -ENOMEM;
333
334 *_h = h;
335 return 0;
336 }
337
338 /* Check the database... */
339 errno = 0;
340 p = getpwuid(u);
341 if (!p)
342 return errno > 0 ? -errno : -ESRCH;
343
344 if (!path_is_absolute(p->pw_dir))
345 return -EINVAL;
346
347 h = strdup(p->pw_dir);
348 if (!h)
349 return -ENOMEM;
350
351 *_h = h;
352 return 0;
353}
354
355int get_shell(char **_s) {
356 struct passwd *p;
357 const char *e;
358 char *s;
359 uid_t u;
360
361 assert(_s);
362
363 /* Take the user specified one */
364 e = getenv("SHELL");
365 if (e) {
366 s = strdup(e);
367 if (!s)
368 return -ENOMEM;
369
370 *_s = s;
371 return 0;
372 }
373
374 /* Hardcode home directory for root to avoid NSS */
375 u = getuid();
376 if (u == 0) {
377 s = strdup("/bin/sh");
378 if (!s)
379 return -ENOMEM;
380
381 *_s = s;
382 return 0;
383 }
384
385 /* Check the database... */
386 errno = 0;
387 p = getpwuid(u);
388 if (!p)
389 return errno > 0 ? -errno : -ESRCH;
390
391 if (!path_is_absolute(p->pw_shell))
392 return -EINVAL;
393
394 s = strdup(p->pw_shell);
395 if (!s)
396 return -ENOMEM;
397
398 *_s = s;
399 return 0;
400}
401
402int reset_uid_gid(void) {
403
404 if (setgroups(0, NULL) < 0)
405 return -errno;
406
407 if (setresgid(0, 0, 0) < 0)
408 return -errno;
409
410 if (setresuid(0, 0, 0) < 0)
411 return -errno;
412
413 return 0;
414}