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