diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-01-30 14:28:10 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-02-02 10:35:30 +0100 |
commit | 7b1aaf6633cad80c1e59eeedaf60595a3ec1efc5 (patch) | |
tree | 336ef1589bf1329e9665597aa380e40f9325feb0 /src/sysusers | |
parent | 1b600bd522d2c01c493729cdda4bcc2e01203e98 (diff) | |
download | systemd-7b1aaf6633cad80c1e59eeedaf60595a3ec1efc5.tar.gz |
sysusers: allow the shell to be specified
This is necessary for some system users where the "login shell" is
set to a specific binary.
Diffstat (limited to 'src/sysusers')
-rw-r--r-- | src/sysusers/sysusers.c | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 340e0db798..e2a3b9968c 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -59,6 +59,7 @@ typedef struct Item { char *gid_path; char *description; char *home; + char *shell; gid_t gid; uid_t uid; @@ -384,6 +385,10 @@ static int rename_and_apply_smack(const char *temp_path, const char *dest_path) return r; } +static const char* default_shell(uid_t uid) { + return uid == 0 ? "/bin/sh" : "/sbin/nologin"; +} + static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) { _cleanup_fclose_ FILE *original = NULL, *passwd = NULL; _cleanup_(unlink_and_freep) char *passwd_tmp = NULL; @@ -451,7 +456,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char /* Initialize the shell to nologin, with one exception: * for root we patch in something special */ - .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin", + .pw_shell = i->shell ?: (char*) default_shell(i->uid), }; errno = 0; @@ -1225,6 +1230,7 @@ static void item_free(Item *i) { free(i->gid_path); free(i->description); free(i->home); + free(i->shell); free(i); } @@ -1332,6 +1338,9 @@ static bool item_equal(Item *a, Item *b) { if (!streq_ptr(a->home, b->home)) return false; + if (!streq_ptr(a->shell, b->shell)) + return false; + return true; } @@ -1345,7 +1354,12 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { {} }; - _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL; + _cleanup_free_ char *action = NULL, + *name = NULL, *resolved_name = NULL, + *id = NULL, *resolved_id = NULL, + *description = NULL, + *home = NULL, + *shell, *resolved_shell = NULL; _cleanup_(item_freep) Item *i = NULL; Item *existing; OrderedHashmap *h; @@ -1358,7 +1372,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { /* Parse columns */ p = buffer; - r = extract_many_words(&p, NULL, EXTRACT_QUOTES, &action, &name, &id, &description, &home, NULL); + r = extract_many_words(&p, NULL, EXTRACT_QUOTES, + &action, &name, &id, &description, &home, &shell, NULL); if (r < 0) { log_error("[%s:%u] Syntax error.", fname, line); return r; @@ -1434,6 +1449,24 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } } + /* Verify shell */ + if (isempty(shell) || streq(shell, "-")) + shell = mfree(shell); + + if (shell) { + r = specifier_printf(shell, specifier_table, NULL, &resolved_shell); + if (r < 0) { + log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, shell); + return r; + } + + if (!valid_shell(resolved_shell)) { + log_error("[%s:%u] '%s' is not a valid login shell field.", fname, line, resolved_shell); + return -EINVAL; + } + } + + switch (action[0]) { case ADD_RANGE: @@ -1447,13 +1480,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - if (description) { - log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line); - return -EINVAL; - } - - if (home) { - log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line); + if (description || home || shell) { + log_error("[%s:%u] Lines of type '%c' don't take a %s field.", + fname, line, action[0], + description ? "GECOS" : home ? "home directory" : "login shell"); return -EINVAL; } @@ -1484,13 +1514,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - if (description) { - log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line); - return -EINVAL; - } - - if (home) { - log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line); + if (description || home || shell) { + log_error("[%s:%u] Lines of type '%c' don't take a %s field.", + fname, line, action[0], + description ? "GECOS" : home ? "home directory" : "login shell"); return -EINVAL; } @@ -1574,6 +1601,9 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i->home = home; home = NULL; + i->shell = resolved_shell; + resolved_shell = NULL; + h = users; break; @@ -1583,13 +1613,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - if (description) { - log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line); - return -EINVAL; - } - - if (home) { - log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line); + if (description || home || shell) { + log_error("[%s:%u] Lines of type '%c' don't take a %s field.", + fname, line, action[0], + description ? "GECOS" : home ? "home directory" : "login shell"); return -EINVAL; } |