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