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