]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/sysusers/sysusers.c
sysusers: be nice and print a warning if futimens() fails
[thirdparty/systemd.git] / src / sysusers / sysusers.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 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 <sys/types.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <shadow.h>
26 #include <gshadow.h>
27 #include <getopt.h>
28 #include <utmp.h>
29
30 #include "util.h"
31 #include "hashmap.h"
32 #include "specifier.h"
33 #include "path-util.h"
34 #include "build.h"
35 #include "strv.h"
36 #include "conf-files.h"
37 #include "copy.h"
38 #include "utf8.h"
39 #include "label.h"
40 #include "fileio-label.h"
41 #include "uid-range.h"
42
43 typedef enum ItemType {
44 ADD_USER = 'u',
45 ADD_GROUP = 'g',
46 ADD_MEMBER = 'm',
47 ADD_RANGE = 'r',
48 } ItemType;
49 typedef struct Item {
50 ItemType type;
51
52 char *name;
53 char *uid_path;
54 char *gid_path;
55 char *description;
56 char *home;
57
58 gid_t gid;
59 uid_t uid;
60
61 bool gid_set:1;
62 bool uid_set:1;
63
64 bool todo_user:1;
65 bool todo_group:1;
66 } Item;
67
68 static char *arg_root = NULL;
69
70 static const char conf_file_dirs[] =
71 "/etc/sysusers.d\0"
72 "/run/sysusers.d\0"
73 "/usr/local/lib/sysusers.d\0"
74 "/usr/lib/sysusers.d\0"
75 #ifdef HAVE_SPLIT_USR
76 "/lib/sysusers.d\0"
77 #endif
78 ;
79
80 static Hashmap *users = NULL, *groups = NULL;
81 static Hashmap *todo_uids = NULL, *todo_gids = NULL;
82 static Hashmap *members = NULL;
83
84 static Hashmap *database_uid = NULL, *database_user = NULL;
85 static Hashmap *database_gid = NULL, *database_group = NULL;
86
87 static uid_t search_uid = (uid_t) -1;
88 static UidRange *uid_range = NULL;
89 static unsigned n_uid_range = 0;
90
91 #define UID_TO_PTR(u) (ULONG_TO_PTR(u+1))
92 #define PTR_TO_UID(u) ((uid_t) (PTR_TO_ULONG(u)-1))
93
94 #define GID_TO_PTR(g) (ULONG_TO_PTR(g+1))
95 #define PTR_TO_GID(g) ((gid_t) (PTR_TO_ULONG(g)-1))
96
97 #define fix_root(x) (arg_root ? strappenda(arg_root, x) : x)
98
99 static int load_user_database(void) {
100 _cleanup_fclose_ FILE *f = NULL;
101 const char *passwd_path;
102 struct passwd *pw;
103 int r;
104
105 passwd_path = fix_root("/etc/passwd");
106 f = fopen(passwd_path, "re");
107 if (!f)
108 return errno == ENOENT ? 0 : -errno;
109
110 r = hashmap_ensure_allocated(&database_user, &string_hash_ops);
111 if (r < 0)
112 return r;
113
114 r = hashmap_ensure_allocated(&database_uid, NULL);
115 if (r < 0)
116 return r;
117
118 errno = 0;
119 while ((pw = fgetpwent(f))) {
120 char *n;
121 int k, q;
122
123 n = strdup(pw->pw_name);
124 if (!n)
125 return -ENOMEM;
126
127 k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid));
128 if (k < 0 && k != -EEXIST) {
129 free(n);
130 return k;
131 }
132
133 q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid), n);
134 if (q < 0 && q != -EEXIST) {
135 if (k < 0)
136 free(n);
137 return q;
138 }
139
140 if (q < 0 && k < 0)
141 free(n);
142
143 errno = 0;
144 }
145 if (!IN_SET(errno, 0, ENOENT))
146 return -errno;
147
148 return 0;
149 }
150
151 static int load_group_database(void) {
152 _cleanup_fclose_ FILE *f = NULL;
153 const char *group_path;
154 struct group *gr;
155 int r;
156
157 group_path = fix_root("/etc/group");
158 f = fopen(group_path, "re");
159 if (!f)
160 return errno == ENOENT ? 0 : -errno;
161
162 r = hashmap_ensure_allocated(&database_group, &string_hash_ops);
163 if (r < 0)
164 return r;
165
166 r = hashmap_ensure_allocated(&database_gid, NULL);
167 if (r < 0)
168 return r;
169
170 errno = 0;
171 while ((gr = fgetgrent(f))) {
172 char *n;
173 int k, q;
174
175 n = strdup(gr->gr_name);
176 if (!n)
177 return -ENOMEM;
178
179 k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid));
180 if (k < 0 && k != -EEXIST) {
181 free(n);
182 return k;
183 }
184
185 q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid), n);
186 if (q < 0 && q != -EEXIST) {
187 if (k < 0)
188 free(n);
189 return q;
190 }
191
192 if (q < 0 && k < 0)
193 free(n);
194
195 errno = 0;
196 }
197 if (!IN_SET(errno, 0, ENOENT))
198 return -errno;
199
200 return 0;
201 }
202
203 static int make_backup(const char *target, const char *x) {
204 _cleanup_close_ int src = -1;
205 _cleanup_fclose_ FILE *dst = NULL;
206 char *backup, *temp;
207 struct timespec ts[2];
208 struct stat st;
209 int r;
210
211 src = open(x, O_RDONLY|O_CLOEXEC|O_NOCTTY);
212 if (src < 0) {
213 if (errno == ENOENT) /* No backup necessary... */
214 return 0;
215
216 return -errno;
217 }
218
219 if (fstat(src, &st) < 0)
220 return -errno;
221
222 r = fopen_temporary_label(target, x, &dst, &temp);
223 if (r < 0)
224 return r;
225
226 r = copy_bytes(src, fileno(dst), (off_t) -1);
227 if (r < 0)
228 goto fail;
229
230 /* Don't fail on chmod() or chown(). If it stays owned by us
231 * and/or unreadable by others, then it isn't too bad... */
232
233 backup = strappenda(x, "-");
234
235 /* Copy over the access mask */
236 if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
237 log_warning("Failed to change mode on %s: %m", backup);
238
239 if (fchown(fileno(dst), st.st_uid, st.st_gid)< 0)
240 log_warning("Failed to change ownership of %s: %m", backup);
241
242 ts[0] = st.st_atim;
243 ts[1] = st.st_mtim;
244 if (futimens(fileno(dst), ts) < 0)
245 log_warning("Failed to fix access and modification time of %s: %m", backup);
246
247 if (rename(temp, backup) < 0)
248 goto fail;
249
250 return 0;
251
252 fail:
253 unlink(temp);
254 return r;
255 }
256
257 static int putgrent_with_members(const struct group *gr, FILE *group) {
258 char **a;
259
260 assert(gr);
261 assert(group);
262
263 a = hashmap_get(members, gr->gr_name);
264 if (a) {
265 _cleanup_strv_free_ char **l = NULL;
266 bool added = false;
267 char **i;
268
269 l = strv_copy(gr->gr_mem);
270 if (!l)
271 return -ENOMEM;
272
273 STRV_FOREACH(i, a) {
274 if (strv_find(l, *i))
275 continue;
276
277 if (strv_extend(&l, *i) < 0)
278 return -ENOMEM;
279
280 added = true;
281 }
282
283 if (added) {
284 struct group t;
285
286 strv_uniq(l);
287 strv_sort(l);
288
289 t = *gr;
290 t.gr_mem = l;
291
292 errno = 0;
293 if (putgrent(&t, group) != 0)
294 return errno ? -errno : -EIO;
295
296 return 1;
297 }
298 }
299
300 errno = 0;
301 if (putgrent(gr, group) != 0)
302 return errno ? -errno : -EIO;
303
304 return 0;
305 }
306
307 static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
308 char **a;
309
310 assert(sg);
311 assert(gshadow);
312
313 a = hashmap_get(members, sg->sg_namp);
314 if (a) {
315 _cleanup_strv_free_ char **l = NULL;
316 bool added = false;
317 char **i;
318
319 l = strv_copy(sg->sg_mem);
320 if (!l)
321 return -ENOMEM;
322
323 STRV_FOREACH(i, a) {
324 if (strv_find(l, *i))
325 continue;
326
327 if (strv_extend(&l, *i) < 0)
328 return -ENOMEM;
329
330 added = true;
331 }
332
333 if (added) {
334 struct sgrp t;
335
336 strv_uniq(l);
337 strv_sort(l);
338
339 t = *sg;
340 t.sg_mem = l;
341
342 errno = 0;
343 if (putsgent(&t, gshadow) != 0)
344 return errno ? -errno : -EIO;
345
346 return 1;
347 }
348 }
349
350 errno = 0;
351 if (putsgent(sg, gshadow) != 0)
352 return errno ? -errno : -EIO;
353
354 return 0;
355 }
356
357 static int write_files(void) {
358
359 _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
360 _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL;
361 const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL;
362 struct stat st;
363 bool group_changed = false;
364 Iterator iterator;
365 Item *i;
366 int r;
367
368 if (hashmap_size(todo_gids) > 0 || hashmap_size(members) > 0) {
369 _cleanup_fclose_ FILE *original = NULL;
370
371 /* First we update the actual group list file */
372 group_path = fix_root("/etc/group");
373 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
374 if (r < 0)
375 goto finish;
376
377 original = fopen(group_path, "re");
378 if (original) {
379 struct group *gr;
380
381 if (fstat(fileno(original), &st) < 0 ||
382 fchmod(fileno(group), st.st_mode & 07777) < 0 ||
383 fchown(fileno(group), st.st_uid, st.st_gid) < 0) {
384 r = -errno;
385 goto finish;
386 }
387
388 errno = 0;
389 while ((gr = fgetgrent(original))) {
390 /* Safety checks against name and GID
391 * collisions. Normally, this should
392 * be unnecessary, but given that we
393 * look at the entries anyway here,
394 * let's make an extra verification
395 * step that we don't generate
396 * duplicate entries. */
397
398 i = hashmap_get(groups, gr->gr_name);
399 if (i && i->todo_group) {
400 r = -EEXIST;
401 goto finish;
402 }
403
404 if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) {
405 r = -EEXIST;
406 goto finish;
407 }
408
409 r = putgrent_with_members(gr, group);
410 if (r < 0)
411 goto finish;
412 if (r > 0)
413 group_changed = true;
414
415 errno = 0;
416 }
417 if (!IN_SET(errno, 0, ENOENT)) {
418 r = -errno;
419 goto finish;
420 }
421
422 } else if (errno != ENOENT) {
423 r = -errno;
424 goto finish;
425 } else if (fchmod(fileno(group), 0644) < 0) {
426 r = -errno;
427 goto finish;
428 }
429
430 HASHMAP_FOREACH(i, todo_gids, iterator) {
431 struct group n = {
432 .gr_name = i->name,
433 .gr_gid = i->gid,
434 .gr_passwd = (char*) "x",
435 };
436
437 r = putgrent_with_members(&n, group);
438 if (r < 0)
439 goto finish;
440
441 group_changed = true;
442 }
443
444 r = fflush_and_check(group);
445 if (r < 0)
446 goto finish;
447
448 if (original) {
449 fclose(original);
450 original = NULL;
451 }
452
453 /* OK, now also update the shadow file for the group list */
454 gshadow_path = fix_root("/etc/gshadow");
455 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
456 if (r < 0)
457 goto finish;
458
459 original = fopen(gshadow_path, "re");
460 if (original) {
461 struct sgrp *sg;
462
463 if (fstat(fileno(original), &st) < 0 ||
464 fchmod(fileno(gshadow), st.st_mode & 07777) < 0 ||
465 fchown(fileno(gshadow), st.st_uid, st.st_gid) < 0) {
466 r = -errno;
467 goto finish;
468 }
469
470 errno = 0;
471 while ((sg = fgetsgent(original))) {
472
473 i = hashmap_get(groups, sg->sg_namp);
474 if (i && i->todo_group) {
475 r = -EEXIST;
476 goto finish;
477 }
478
479 r = putsgent_with_members(sg, gshadow);
480 if (r < 0)
481 goto finish;
482 if (r > 0)
483 group_changed = true;
484
485 errno = 0;
486 }
487 if (!IN_SET(errno, 0, ENOENT)) {
488 r = -errno;
489 goto finish;
490 }
491
492 } else if (errno != ENOENT) {
493 r = -errno;
494 goto finish;
495 } else if (fchmod(fileno(gshadow), 0000) < 0) {
496 r = -errno;
497 goto finish;
498 }
499
500 HASHMAP_FOREACH(i, todo_gids, iterator) {
501 struct sgrp n = {
502 .sg_namp = i->name,
503 .sg_passwd = (char*) "!!",
504 };
505
506 r = putsgent_with_members(&n, gshadow);
507 if (r < 0)
508 goto finish;
509
510 group_changed = true;
511 }
512
513 r = fflush_and_check(gshadow);
514 if (r < 0)
515 goto finish;
516 }
517
518 if (hashmap_size(todo_uids) > 0) {
519 _cleanup_fclose_ FILE *original = NULL;
520 long lstchg;
521
522 /* First we update the user database itself */
523 passwd_path = fix_root("/etc/passwd");
524 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
525 if (r < 0)
526 goto finish;
527
528 original = fopen(passwd_path, "re");
529 if (original) {
530 struct passwd *pw;
531
532 if (fstat(fileno(original), &st) < 0 ||
533 fchmod(fileno(passwd), st.st_mode & 07777) < 0 ||
534 fchown(fileno(passwd), st.st_uid, st.st_gid) < 0) {
535 r = -errno;
536 goto finish;
537 }
538
539 errno = 0;
540 while ((pw = fgetpwent(original))) {
541
542 i = hashmap_get(users, pw->pw_name);
543 if (i && i->todo_user) {
544 r = -EEXIST;
545 goto finish;
546 }
547
548 if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) {
549 r = -EEXIST;
550 goto finish;
551 }
552
553 errno = 0;
554 if (putpwent(pw, passwd) < 0) {
555 r = errno ? -errno : -EIO;
556 goto finish;
557 }
558
559 errno = 0;
560 }
561 if (!IN_SET(errno, 0, ENOENT)) {
562 r = -errno;
563 goto finish;
564 }
565
566 } else if (errno != ENOENT) {
567 r = -errno;
568 goto finish;
569 } else if (fchmod(fileno(passwd), 0644) < 0) {
570 r = -errno;
571 goto finish;
572 }
573
574 HASHMAP_FOREACH(i, todo_uids, iterator) {
575 struct passwd n = {
576 .pw_name = i->name,
577 .pw_uid = i->uid,
578 .pw_gid = i->gid,
579 .pw_gecos = i->description,
580
581 /* "x" means the password is stored in
582 * the shadow file */
583 .pw_passwd = (char*) "x",
584
585 /* We default to the root directory as home */
586 .pw_dir = i->home ? i->home : (char*) "/",
587
588 /* Initialize the shell to nologin,
589 * with one exception: for root we
590 * patch in something special */
591 .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin",
592 };
593
594 errno = 0;
595 if (putpwent(&n, passwd) != 0) {
596 r = errno ? -errno : -EIO;
597 goto finish;
598 }
599 }
600
601 r = fflush_and_check(passwd);
602 if (r < 0)
603 goto finish;
604
605 if (original) {
606 fclose(original);
607 original = NULL;
608 }
609
610 /* The we update the shadow database */
611 shadow_path = fix_root("/etc/shadow");
612 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
613 if (r < 0)
614 goto finish;
615
616 original = fopen(shadow_path, "re");
617 if (original) {
618 struct spwd *sp;
619
620 if (fstat(fileno(original), &st) < 0 ||
621 fchmod(fileno(shadow), st.st_mode & 07777) < 0 ||
622 fchown(fileno(shadow), st.st_uid, st.st_gid) < 0) {
623 r = -errno;
624 goto finish;
625 }
626
627 errno = 0;
628 while ((sp = fgetspent(original))) {
629
630 i = hashmap_get(users, sp->sp_namp);
631 if (i && i->todo_user) {
632 r = -EEXIST;
633 goto finish;
634 }
635
636 errno = 0;
637 if (putspent(sp, shadow) < 0) {
638 r = errno ? -errno : -EIO;
639 goto finish;
640 }
641
642 errno = 0;
643 }
644 if (!IN_SET(errno, 0, ENOENT)) {
645 r = -errno;
646 goto finish;
647 }
648 } else if (errno != ENOENT) {
649 r = -errno;
650 goto finish;
651 } else if (fchmod(fileno(shadow), 0000) < 0) {
652 r = -errno;
653 goto finish;
654 }
655
656 lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
657 HASHMAP_FOREACH(i, todo_uids, iterator) {
658 struct spwd n = {
659 .sp_namp = i->name,
660 .sp_pwdp = (char*) "!!",
661 .sp_lstchg = lstchg,
662 .sp_min = -1,
663 .sp_max = -1,
664 .sp_warn = -1,
665 .sp_inact = -1,
666 .sp_expire = -1,
667 .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
668 };
669
670 errno = 0;
671 if (putspent(&n, shadow) != 0) {
672 r = errno ? -errno : -EIO;
673 goto finish;
674 }
675 }
676
677 r = fflush_and_check(shadow);
678 if (r < 0)
679 goto finish;
680 }
681
682 /* Make a backup of the old files */
683 if (group_changed) {
684 if (group) {
685 r = make_backup("/etc/group", group_path);
686 if (r < 0)
687 goto finish;
688 }
689 if (gshadow) {
690 r = make_backup("/etc/gshadow", gshadow_path);
691 if (r < 0)
692 goto finish;
693 }
694 }
695
696 if (passwd) {
697 r = make_backup("/etc/passwd", passwd_path);
698 if (r < 0)
699 goto finish;
700 }
701 if (shadow) {
702 r = make_backup("/etc/shadow", shadow_path);
703 if (r < 0)
704 goto finish;
705 }
706
707 /* And make the new files count */
708 if (group_changed) {
709 if (group) {
710 if (rename(group_tmp, group_path) < 0) {
711 r = -errno;
712 goto finish;
713 }
714
715 free(group_tmp);
716 group_tmp = NULL;
717 }
718 if (gshadow) {
719 if (rename(gshadow_tmp, gshadow_path) < 0) {
720 r = -errno;
721 goto finish;
722 }
723
724 free(gshadow_tmp);
725 gshadow_tmp = NULL;
726 }
727 }
728
729 if (passwd) {
730 if (rename(passwd_tmp, passwd_path) < 0) {
731 r = -errno;
732 goto finish;
733 }
734
735 free(passwd_tmp);
736 passwd_tmp = NULL;
737 }
738 if (shadow) {
739 if (rename(shadow_tmp, shadow_path) < 0) {
740 r = -errno;
741 goto finish;
742 }
743
744 free(shadow_tmp);
745 shadow_tmp = NULL;
746 }
747
748 r = 0;
749
750 finish:
751 if (passwd_tmp)
752 unlink(passwd_tmp);
753 if (shadow_tmp)
754 unlink(shadow_tmp);
755 if (group_tmp)
756 unlink(group_tmp);
757 if (gshadow_tmp)
758 unlink(gshadow_tmp);
759
760 return r;
761 }
762
763 static int uid_is_ok(uid_t uid, const char *name) {
764 struct passwd *p;
765 struct group *g;
766 const char *n;
767 Item *i;
768
769 /* Let's see if we already have assigned the UID a second time */
770 if (hashmap_get(todo_uids, UID_TO_PTR(uid)))
771 return 0;
772
773 /* Try to avoid using uids that are already used by a group
774 * that doesn't have the same name as our new user. */
775 i = hashmap_get(todo_gids, GID_TO_PTR(uid));
776 if (i && !streq(i->name, name))
777 return 0;
778
779 /* Let's check the files directly */
780 if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
781 return 0;
782
783 n = hashmap_get(database_gid, GID_TO_PTR(uid));
784 if (n && !streq(n, name))
785 return 0;
786
787 /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
788 if (!arg_root) {
789 errno = 0;
790 p = getpwuid(uid);
791 if (p)
792 return 0;
793 if (!IN_SET(errno, 0, ENOENT))
794 return -errno;
795
796 errno = 0;
797 g = getgrgid((gid_t) uid);
798 if (g) {
799 if (!streq(g->gr_name, name))
800 return 0;
801 } else if (!IN_SET(errno, 0, ENOENT))
802 return -errno;
803 }
804
805 return 1;
806 }
807
808 static int root_stat(const char *p, struct stat *st) {
809 const char *fix;
810
811 fix = fix_root(p);
812 if (stat(fix, st) < 0)
813 return -errno;
814
815 return 0;
816 }
817
818 static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
819 struct stat st;
820 bool found_uid = false, found_gid = false;
821 uid_t uid = 0;
822 gid_t gid = 0;
823
824 assert(i);
825
826 /* First, try to get the gid directly */
827 if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
828 gid = st.st_gid;
829 found_gid = true;
830 }
831
832 /* Then, try to get the uid directly */
833 if ((_uid || (_gid && !found_gid))
834 && i->uid_path
835 && root_stat(i->uid_path, &st) >= 0) {
836
837 uid = st.st_uid;
838 found_uid = true;
839
840 /* If we need the gid, but had no success yet, also derive it from the uid path */
841 if (_gid && !found_gid) {
842 gid = st.st_gid;
843 found_gid = true;
844 }
845 }
846
847 /* If that didn't work yet, then let's reuse the gid as uid */
848 if (_uid && !found_uid && i->gid_path) {
849
850 if (found_gid) {
851 uid = (uid_t) gid;
852 found_uid = true;
853 } else if (root_stat(i->gid_path, &st) >= 0) {
854 uid = (uid_t) st.st_gid;
855 found_uid = true;
856 }
857 }
858
859 if (_uid) {
860 if (!found_uid)
861 return 0;
862
863 *_uid = uid;
864 }
865
866 if (_gid) {
867 if (!found_gid)
868 return 0;
869
870 *_gid = gid;
871 }
872
873 return 1;
874 }
875
876 static int add_user(Item *i) {
877 void *z;
878 int r;
879
880 assert(i);
881
882 /* Check the database directly */
883 z = hashmap_get(database_user, i->name);
884 if (z) {
885 log_debug("User %s already exists.", i->name);
886 i->uid = PTR_TO_UID(z);
887 i->uid_set = true;
888 return 0;
889 }
890
891 if (!arg_root) {
892 struct passwd *p;
893 struct spwd *sp;
894
895 /* Also check NSS */
896 errno = 0;
897 p = getpwnam(i->name);
898 if (p) {
899 log_debug("User %s already exists.", i->name);
900 i->uid = p->pw_uid;
901 i->uid_set = true;
902
903 free(i->description);
904 i->description = strdup(p->pw_gecos);
905 return 0;
906 }
907 if (!IN_SET(errno, 0, ENOENT)) {
908 log_error("Failed to check if user %s already exists: %m", i->name);
909 return -errno;
910 }
911
912 /* And shadow too, just to be sure */
913 errno = 0;
914 sp = getspnam(i->name);
915 if (sp) {
916 log_error("User %s already exists in shadow database, but not in user database.", i->name);
917 return -EBADMSG;
918 }
919 if (!IN_SET(errno, 0, ENOENT)) {
920 log_error("Failed to check if user %s already exists in shadow database: %m", i->name);
921 return -errno;
922 }
923 }
924
925 /* Try to use the suggested numeric uid */
926 if (i->uid_set) {
927 r = uid_is_ok(i->uid, i->name);
928 if (r < 0) {
929 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
930 return r;
931 }
932 if (r == 0) {
933 log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name);
934 i->uid_set = false;
935 }
936 }
937
938 /* If that didn't work, try to read it from the specified path */
939 if (!i->uid_set) {
940 uid_t c;
941
942 if (read_id_from_file(i, &c, NULL) > 0) {
943
944 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
945 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
946 else {
947 r = uid_is_ok(c, i->name);
948 if (r < 0) {
949 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
950 return r;
951 } else if (r > 0) {
952 i->uid = c;
953 i->uid_set = true;
954 } else
955 log_debug("User ID " UID_FMT " of file for %s is already used.", c, i->name);
956 }
957 }
958 }
959
960 /* Otherwise try to reuse the group ID */
961 if (!i->uid_set && i->gid_set) {
962 r = uid_is_ok((uid_t) i->gid, i->name);
963 if (r < 0) {
964 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
965 return r;
966 }
967 if (r > 0) {
968 i->uid = (uid_t) i->gid;
969 i->uid_set = true;
970 }
971 }
972
973 /* And if that didn't work either, let's try to find a free one */
974 if (!i->uid_set) {
975 for (;;) {
976 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
977 if (r < 0) {
978 log_error("No free user ID available for %s.", i->name);
979 return r;
980 }
981
982 r = uid_is_ok(search_uid, i->name);
983 if (r < 0) {
984 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
985 return r;
986 } else if (r > 0)
987 break;
988 }
989
990 i->uid_set = true;
991 i->uid = search_uid;
992 }
993
994 r = hashmap_ensure_allocated(&todo_uids, NULL);
995 if (r < 0)
996 return log_oom();
997
998 r = hashmap_put(todo_uids, UID_TO_PTR(i->uid), i);
999 if (r < 0)
1000 return log_oom();
1001
1002 i->todo_user = true;
1003 log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid);
1004
1005 return 0;
1006 }
1007
1008 static int gid_is_ok(gid_t gid) {
1009 struct group *g;
1010 struct passwd *p;
1011
1012 if (hashmap_get(todo_gids, GID_TO_PTR(gid)))
1013 return 0;
1014
1015 /* Avoid reusing gids that are already used by a different user */
1016 if (hashmap_get(todo_uids, UID_TO_PTR(gid)))
1017 return 0;
1018
1019 if (hashmap_contains(database_gid, GID_TO_PTR(gid)))
1020 return 0;
1021
1022 if (hashmap_contains(database_uid, UID_TO_PTR(gid)))
1023 return 0;
1024
1025 if (!arg_root) {
1026 errno = 0;
1027 g = getgrgid(gid);
1028 if (g)
1029 return 0;
1030 if (!IN_SET(errno, 0, ENOENT))
1031 return -errno;
1032
1033 errno = 0;
1034 p = getpwuid((uid_t) gid);
1035 if (p)
1036 return 0;
1037 if (!IN_SET(errno, 0, ENOENT))
1038 return -errno;
1039 }
1040
1041 return 1;
1042 }
1043
1044 static int add_group(Item *i) {
1045 void *z;
1046 int r;
1047
1048 assert(i);
1049
1050 /* Check the database directly */
1051 z = hashmap_get(database_group, i->name);
1052 if (z) {
1053 log_debug("Group %s already exists.", i->name);
1054 i->gid = PTR_TO_GID(z);
1055 i->gid_set = true;
1056 return 0;
1057 }
1058
1059 /* Also check NSS */
1060 if (!arg_root) {
1061 struct group *g;
1062
1063 errno = 0;
1064 g = getgrnam(i->name);
1065 if (g) {
1066 log_debug("Group %s already exists.", i->name);
1067 i->gid = g->gr_gid;
1068 i->gid_set = true;
1069 return 0;
1070 }
1071 if (!IN_SET(errno, 0, ENOENT)) {
1072 log_error("Failed to check if group %s already exists: %m", i->name);
1073 return -errno;
1074 }
1075 }
1076
1077 /* Try to use the suggested numeric gid */
1078 if (i->gid_set) {
1079 r = gid_is_ok(i->gid);
1080 if (r < 0) {
1081 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1082 return r;
1083 }
1084 if (r == 0) {
1085 log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
1086 i->gid_set = false;
1087 }
1088 }
1089
1090 /* Try to reuse the numeric uid, if there's one */
1091 if (!i->gid_set && i->uid_set) {
1092 r = gid_is_ok((gid_t) i->uid);
1093 if (r < 0) {
1094 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1095 return r;
1096 }
1097 if (r > 0) {
1098 i->gid = (gid_t) i->uid;
1099 i->gid_set = true;
1100 }
1101 }
1102
1103 /* If that didn't work, try to read it from the specified path */
1104 if (!i->gid_set) {
1105 gid_t c;
1106
1107 if (read_id_from_file(i, NULL, &c) > 0) {
1108
1109 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
1110 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
1111 else {
1112 r = gid_is_ok(c);
1113 if (r < 0) {
1114 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1115 return r;
1116 } else if (r > 0) {
1117 i->gid = c;
1118 i->gid_set = true;
1119 } else
1120 log_debug("Group ID " GID_FMT " of file for %s already used.", c, i->name);
1121 }
1122 }
1123 }
1124
1125 /* And if that didn't work either, let's try to find a free one */
1126 if (!i->gid_set) {
1127 for (;;) {
1128 /* We look for new GIDs in the UID pool! */
1129 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1130 if (r < 0) {
1131 log_error("No free group ID available for %s.", i->name);
1132 return r;
1133 }
1134
1135 r = gid_is_ok(search_uid);
1136 if (r < 0) {
1137 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1138 return r;
1139 } else if (r > 0)
1140 break;
1141 }
1142
1143 i->gid_set = true;
1144 i->gid = search_uid;
1145 }
1146
1147 r = hashmap_ensure_allocated(&todo_gids, NULL);
1148 if (r < 0)
1149 return log_oom();
1150
1151 r = hashmap_put(todo_gids, GID_TO_PTR(i->gid), i);
1152 if (r < 0)
1153 return log_oom();
1154
1155 i->todo_group = true;
1156 log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid);
1157
1158 return 0;
1159 }
1160
1161 static int process_item(Item *i) {
1162 int r;
1163
1164 assert(i);
1165
1166 switch (i->type) {
1167
1168 case ADD_USER:
1169 r = add_group(i);
1170 if (r < 0)
1171 return r;
1172
1173 return add_user(i);
1174
1175 case ADD_GROUP: {
1176 Item *j;
1177
1178 j = hashmap_get(users, i->name);
1179 if (j) {
1180 /* There's already user to be created for this
1181 * name, let's process that in one step */
1182
1183 if (i->gid_set) {
1184 j->gid = i->gid;
1185 j->gid_set = true;
1186 }
1187
1188 if (i->gid_path) {
1189 free(j->gid_path);
1190 j->gid_path = strdup(i->gid_path);
1191 if (!j->gid_path)
1192 return log_oom();
1193 }
1194
1195 return 0;
1196 }
1197
1198 return add_group(i);
1199 }
1200
1201 default:
1202 assert_not_reached("Unknown item type");
1203 }
1204 }
1205
1206 static void item_free(Item *i) {
1207
1208 if (!i)
1209 return;
1210
1211 free(i->name);
1212 free(i->uid_path);
1213 free(i->gid_path);
1214 free(i->description);
1215 free(i);
1216 }
1217
1218 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1219
1220 static int add_implicit(void) {
1221 char *g, **l;
1222 Iterator iterator;
1223 int r;
1224
1225 /* Implicitly create additional users and groups, if they were listed in "m" lines */
1226
1227 HASHMAP_FOREACH_KEY(l, g, members, iterator) {
1228 Item *i;
1229 char **m;
1230
1231 i = hashmap_get(groups, g);
1232 if (!i) {
1233 _cleanup_(item_freep) Item *j = NULL;
1234
1235 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1236 if (r < 0)
1237 return log_oom();
1238
1239 j = new0(Item, 1);
1240 if (!j)
1241 return log_oom();
1242
1243 j->type = ADD_GROUP;
1244 j->name = strdup(g);
1245 if (!j->name)
1246 return log_oom();
1247
1248 r = hashmap_put(groups, j->name, j);
1249 if (r < 0)
1250 return log_oom();
1251
1252 log_debug("Adding implicit group '%s' due to m line", j->name);
1253 j = NULL;
1254 }
1255
1256 STRV_FOREACH(m, l) {
1257
1258 i = hashmap_get(users, *m);
1259 if (!i) {
1260 _cleanup_(item_freep) Item *j = NULL;
1261
1262 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1263 if (r < 0)
1264 return log_oom();
1265
1266 j = new0(Item, 1);
1267 if (!j)
1268 return log_oom();
1269
1270 j->type = ADD_USER;
1271 j->name = strdup(*m);
1272 if (!j->name)
1273 return log_oom();
1274
1275 r = hashmap_put(users, j->name, j);
1276 if (r < 0)
1277 return log_oom();
1278
1279 log_debug("Adding implicit user '%s' due to m line", j->name);
1280 j = NULL;
1281 }
1282 }
1283 }
1284
1285 return 0;
1286 }
1287
1288 static bool item_equal(Item *a, Item *b) {
1289 assert(a);
1290 assert(b);
1291
1292 if (a->type != b->type)
1293 return false;
1294
1295 if (!streq_ptr(a->name, b->name))
1296 return false;
1297
1298 if (!streq_ptr(a->uid_path, b->uid_path))
1299 return false;
1300
1301 if (!streq_ptr(a->gid_path, b->gid_path))
1302 return false;
1303
1304 if (!streq_ptr(a->description, b->description))
1305 return false;
1306
1307 if (a->uid_set != b->uid_set)
1308 return false;
1309
1310 if (a->uid_set && a->uid != b->uid)
1311 return false;
1312
1313 if (a->gid_set != b->gid_set)
1314 return false;
1315
1316 if (a->gid_set && a->gid != b->gid)
1317 return false;
1318
1319 if (!streq_ptr(a->home, b->home))
1320 return false;
1321
1322 return true;
1323 }
1324
1325 static bool valid_user_group_name(const char *u) {
1326 const char *i;
1327 long sz;
1328
1329 if (isempty(u))
1330 return false;
1331
1332 if (!(u[0] >= 'a' && u[0] <= 'z') &&
1333 !(u[0] >= 'A' && u[0] <= 'Z') &&
1334 u[0] != '_')
1335 return false;
1336
1337 for (i = u+1; *i; i++) {
1338 if (!(*i >= 'a' && *i <= 'z') &&
1339 !(*i >= 'A' && *i <= 'Z') &&
1340 !(*i >= '0' && *i <= '9') &&
1341 *i != '_' &&
1342 *i != '-')
1343 return false;
1344 }
1345
1346 sz = sysconf(_SC_LOGIN_NAME_MAX);
1347 assert_se(sz > 0);
1348
1349 if ((size_t) (i-u) > (size_t) sz)
1350 return false;
1351
1352 if ((size_t) (i-u) > UT_NAMESIZE - 1)
1353 return false;
1354
1355 return true;
1356 }
1357
1358 static bool valid_gecos(const char *d) {
1359
1360 if (!d)
1361 return false;
1362
1363 if (!utf8_is_valid(d))
1364 return false;
1365
1366 if (string_has_cc(d, NULL))
1367 return false;
1368
1369 /* Colons are used as field separators, and hence not OK */
1370 if (strchr(d, ':'))
1371 return false;
1372
1373 return true;
1374 }
1375
1376 static bool valid_home(const char *p) {
1377
1378 if (isempty(p))
1379 return false;
1380
1381 if (!utf8_is_valid(p))
1382 return false;
1383
1384 if (string_has_cc(p, NULL))
1385 return false;
1386
1387 if (!path_is_absolute(p))
1388 return false;
1389
1390 if (!path_is_safe(p))
1391 return false;
1392
1393 /* Colons are used as field separators, and hence not OK */
1394 if (strchr(p, ':'))
1395 return false;
1396
1397 return true;
1398 }
1399
1400 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1401
1402 static const Specifier specifier_table[] = {
1403 { 'm', specifier_machine_id, NULL },
1404 { 'b', specifier_boot_id, NULL },
1405 { 'H', specifier_host_name, NULL },
1406 { 'v', specifier_kernel_release, NULL },
1407 {}
1408 };
1409
1410 _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL;
1411 _cleanup_(item_freep) Item *i = NULL;
1412 Item *existing;
1413 Hashmap *h;
1414 int r;
1415 const char *p;
1416
1417 assert(fname);
1418 assert(line >= 1);
1419 assert(buffer);
1420
1421 /* Parse columns */
1422 p = buffer;
1423 r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
1424 if (r < 0) {
1425 log_error("[%s:%u] Syntax error.", fname, line);
1426 return r;
1427 }
1428 if (r < 2) {
1429 log_error("[%s:%u] Missing action and name columns.", fname, line);
1430 return -EINVAL;
1431 }
1432 if (*p != 0) {
1433 log_error("[%s:%u] Trailing garbage.", fname, line);
1434 return -EINVAL;
1435 }
1436
1437 /* Verify action */
1438 if (strlen(action) != 1) {
1439 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1440 return -EINVAL;
1441 }
1442
1443 if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) {
1444 log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]);
1445 return -EBADMSG;
1446 }
1447
1448 /* Verify name */
1449 if (isempty(name) || streq(name, "-")) {
1450 free(name);
1451 name = NULL;
1452 }
1453
1454 if (name) {
1455 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
1456 if (r < 0) {
1457 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1458 return r;
1459 }
1460
1461 if (!valid_user_group_name(resolved_name)) {
1462 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
1463 return -EINVAL;
1464 }
1465 }
1466
1467 /* Verify id */
1468 if (isempty(id) || streq(id, "-")) {
1469 free(id);
1470 id = NULL;
1471 }
1472
1473 if (id) {
1474 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
1475 if (r < 0) {
1476 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1477 return r;
1478 }
1479 }
1480
1481 /* Verify description */
1482 if (isempty(description) || streq(description, "-")) {
1483 free(description);
1484 description = NULL;
1485 }
1486
1487 if (description) {
1488 if (!valid_gecos(description)) {
1489 log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, description);
1490 return -EINVAL;
1491 }
1492 }
1493
1494 /* Verify home */
1495 if (isempty(home) || streq(home, "-")) {
1496 free(home);
1497 home = NULL;
1498 }
1499
1500 if (home) {
1501 if (!valid_home(home)) {
1502 log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, home);
1503 return -EINVAL;
1504 }
1505 }
1506
1507 switch (action[0]) {
1508
1509 case ADD_RANGE:
1510 if (resolved_name) {
1511 log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line);
1512 return -EINVAL;
1513 }
1514
1515 if (!resolved_id) {
1516 log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line);
1517 return -EINVAL;
1518 }
1519
1520 if (description) {
1521 log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line);
1522 return -EINVAL;
1523 }
1524
1525 if (home) {
1526 log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line);
1527 return -EINVAL;
1528 }
1529
1530 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
1531 if (r < 0) {
1532 log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
1533 return -EINVAL;
1534 }
1535
1536 return 0;
1537
1538 case ADD_MEMBER: {
1539 char **l;
1540
1541 /* Try to extend an existing member or group item */
1542 if (!name) {
1543 log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line);
1544 return -EINVAL;
1545 }
1546
1547 if (!resolved_id) {
1548 log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line);
1549 return -EINVAL;
1550 }
1551
1552 if (!valid_user_group_name(resolved_id)) {
1553 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
1554 return -EINVAL;
1555 }
1556
1557 if (description) {
1558 log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line);
1559 return -EINVAL;
1560 }
1561
1562 if (home) {
1563 log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line);
1564 return -EINVAL;
1565 }
1566
1567 r = hashmap_ensure_allocated(&members, &string_hash_ops);
1568 if (r < 0)
1569 return log_oom();
1570
1571 l = hashmap_get(members, resolved_id);
1572 if (l) {
1573 /* A list for this group name already exists, let's append to it */
1574 r = strv_push(&l, resolved_name);
1575 if (r < 0)
1576 return log_oom();
1577
1578 resolved_name = NULL;
1579
1580 assert_se(hashmap_update(members, resolved_id, l) >= 0);
1581 } else {
1582 /* No list for this group name exists yet, create one */
1583
1584 l = new0(char *, 2);
1585 if (!l)
1586 return -ENOMEM;
1587
1588 l[0] = resolved_name;
1589 l[1] = NULL;
1590
1591 r = hashmap_put(members, resolved_id, l);
1592 if (r < 0) {
1593 free(l);
1594 return log_oom();
1595 }
1596
1597 resolved_id = resolved_name = NULL;
1598 }
1599
1600 return 0;
1601 }
1602
1603 case ADD_USER:
1604 if (!name) {
1605 log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line);
1606 return -EINVAL;
1607 }
1608
1609 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1610 if (r < 0)
1611 return log_oom();
1612
1613 i = new0(Item, 1);
1614 if (!i)
1615 return log_oom();
1616
1617 if (resolved_id) {
1618 if (path_is_absolute(resolved_id)) {
1619 i->uid_path = resolved_id;
1620 resolved_id = NULL;
1621
1622 path_kill_slashes(i->uid_path);
1623 } else {
1624 r = parse_uid(resolved_id, &i->uid);
1625 if (r < 0) {
1626 log_error("Failed to parse UID: %s", id);
1627 return -EBADMSG;
1628 }
1629
1630 i->uid_set = true;
1631 }
1632 }
1633
1634 i->description = description;
1635 description = NULL;
1636
1637 i->home = home;
1638 home = NULL;
1639
1640 h = users;
1641 break;
1642
1643 case ADD_GROUP:
1644 if (!name) {
1645 log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line);
1646 return -EINVAL;
1647 }
1648
1649 if (description) {
1650 log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line);
1651 return -EINVAL;
1652 }
1653
1654 if (home) {
1655 log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line);
1656 return -EINVAL;
1657 }
1658
1659 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1660 if (r < 0)
1661 return log_oom();
1662
1663 i = new0(Item, 1);
1664 if (!i)
1665 return log_oom();
1666
1667 if (resolved_id) {
1668 if (path_is_absolute(resolved_id)) {
1669 i->gid_path = resolved_id;
1670 resolved_id = NULL;
1671
1672 path_kill_slashes(i->gid_path);
1673 } else {
1674 r = parse_gid(resolved_id, &i->gid);
1675 if (r < 0) {
1676 log_error("Failed to parse GID: %s", id);
1677 return -EBADMSG;
1678 }
1679
1680 i->gid_set = true;
1681 }
1682 }
1683
1684 h = groups;
1685 break;
1686
1687 default:
1688 return -EBADMSG;
1689 }
1690
1691 i->type = action[0];
1692 i->name = resolved_name;
1693 resolved_name = NULL;
1694
1695 existing = hashmap_get(h, i->name);
1696 if (existing) {
1697
1698 /* Two identical items are fine */
1699 if (!item_equal(existing, i))
1700 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name);
1701
1702 return 0;
1703 }
1704
1705 r = hashmap_put(h, i->name, i);
1706 if (r < 0)
1707 return log_oom();
1708
1709 i = NULL;
1710 return 0;
1711 }
1712
1713 static int read_config_file(const char *fn, bool ignore_enoent) {
1714 _cleanup_fclose_ FILE *rf = NULL;
1715 FILE *f = NULL;
1716 char line[LINE_MAX];
1717 unsigned v = 0;
1718 int r = 0;
1719
1720 assert(fn);
1721
1722 if (streq(fn, "-"))
1723 f = stdin;
1724 else {
1725 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf);
1726 if (r < 0) {
1727 if (ignore_enoent && r == -ENOENT)
1728 return 0;
1729
1730 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1731 return r;
1732 }
1733
1734 f = rf;
1735 }
1736
1737 FOREACH_LINE(line, f, break) {
1738 char *l;
1739 int k;
1740
1741 v++;
1742
1743 l = strstrip(line);
1744 if (*l == '#' || *l == 0)
1745 continue;
1746
1747 k = parse_line(fn, v, l);
1748 if (k < 0 && r == 0)
1749 r = k;
1750 }
1751
1752 if (ferror(f)) {
1753 log_error("Failed to read from file %s: %m", fn);
1754 if (r == 0)
1755 r = -EIO;
1756 }
1757
1758 return r;
1759 }
1760
1761 static void free_database(Hashmap *by_name, Hashmap *by_id) {
1762 char *name;
1763
1764 for (;;) {
1765 name = hashmap_first(by_id);
1766 if (!name)
1767 break;
1768
1769 hashmap_remove(by_name, name);
1770
1771 hashmap_steal_first_key(by_id);
1772 free(name);
1773 }
1774
1775 while ((name = hashmap_steal_first_key(by_name)))
1776 free(name);
1777
1778 hashmap_free(by_name);
1779 hashmap_free(by_id);
1780 }
1781
1782 static void help(void) {
1783 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1784 "Creates system user accounts.\n\n"
1785 " -h --help Show this help\n"
1786 " --version Show package version\n"
1787 " --root=PATH Operate on an alternate filesystem root\n"
1788 , program_invocation_short_name);
1789 }
1790
1791 static int parse_argv(int argc, char *argv[]) {
1792
1793 enum {
1794 ARG_VERSION = 0x100,
1795 ARG_ROOT,
1796 };
1797
1798 static const struct option options[] = {
1799 { "help", no_argument, NULL, 'h' },
1800 { "version", no_argument, NULL, ARG_VERSION },
1801 { "root", required_argument, NULL, ARG_ROOT },
1802 {}
1803 };
1804
1805 int c;
1806
1807 assert(argc >= 0);
1808 assert(argv);
1809
1810 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1811
1812 switch (c) {
1813
1814 case 'h':
1815 help();
1816 return 0;
1817
1818 case ARG_VERSION:
1819 puts(PACKAGE_STRING);
1820 puts(SYSTEMD_FEATURES);
1821 return 0;
1822
1823 case ARG_ROOT:
1824 free(arg_root);
1825 arg_root = path_make_absolute_cwd(optarg);
1826 if (!arg_root)
1827 return log_oom();
1828
1829 path_kill_slashes(arg_root);
1830 break;
1831
1832 case '?':
1833 return -EINVAL;
1834
1835 default:
1836 assert_not_reached("Unhandled option");
1837 }
1838
1839 return 1;
1840 }
1841
1842 int main(int argc, char *argv[]) {
1843
1844 _cleanup_close_ int lock = -1;
1845 Iterator iterator;
1846 int r, k;
1847 Item *i;
1848 char *n;
1849
1850 r = parse_argv(argc, argv);
1851 if (r <= 0)
1852 goto finish;
1853
1854 log_set_target(LOG_TARGET_AUTO);
1855 log_parse_environment();
1856 log_open();
1857
1858 umask(0022);
1859
1860 r = mac_selinux_init(NULL);
1861 if (r < 0) {
1862 log_error("SELinux setup failed: %s", strerror(-r));
1863 goto finish;
1864 }
1865
1866 if (optind < argc) {
1867 int j;
1868
1869 for (j = optind; j < argc; j++) {
1870 k = read_config_file(argv[j], false);
1871 if (k < 0 && r == 0)
1872 r = k;
1873 }
1874 } else {
1875 _cleanup_strv_free_ char **files = NULL;
1876 char **f;
1877
1878 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1879 if (r < 0) {
1880 log_error("Failed to enumerate sysusers.d files: %s", strerror(-r));
1881 goto finish;
1882 }
1883
1884 STRV_FOREACH(f, files) {
1885 k = read_config_file(*f, true);
1886 if (k < 0 && r == 0)
1887 r = k;
1888 }
1889 }
1890
1891 if (!uid_range) {
1892 /* Default to default range of 1..SYSTEMD_UID_MAX */
1893 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
1894 if (r < 0) {
1895 log_oom();
1896 goto finish;
1897 }
1898 }
1899
1900 r = add_implicit();
1901 if (r < 0)
1902 goto finish;
1903
1904 lock = take_password_lock(arg_root);
1905 if (lock < 0) {
1906 log_error("Failed to take lock: %s", strerror(-lock));
1907 goto finish;
1908 }
1909
1910 r = load_user_database();
1911 if (r < 0) {
1912 log_error("Failed to load user database: %s", strerror(-r));
1913 goto finish;
1914 }
1915
1916 r = load_group_database();
1917 if (r < 0) {
1918 log_error("Failed to read group database: %s", strerror(-r));
1919 goto finish;
1920 }
1921
1922 HASHMAP_FOREACH(i, groups, iterator)
1923 process_item(i);
1924
1925 HASHMAP_FOREACH(i, users, iterator)
1926 process_item(i);
1927
1928 r = write_files();
1929 if (r < 0)
1930 log_error("Failed to write files: %s", strerror(-r));
1931
1932 finish:
1933 while ((i = hashmap_steal_first(groups)))
1934 item_free(i);
1935
1936 while ((i = hashmap_steal_first(users)))
1937 item_free(i);
1938
1939 while ((n = hashmap_first_key(members))) {
1940 strv_free(hashmap_steal_first(members));
1941 free(n);
1942 }
1943
1944 hashmap_free(groups);
1945 hashmap_free(users);
1946 hashmap_free(members);
1947 hashmap_free(todo_uids);
1948 hashmap_free(todo_gids);
1949
1950 free_database(database_user, database_uid);
1951 free_database(database_group, database_gid);
1952
1953 free(arg_root);
1954
1955 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1956 }