Commit d09137aa authored by Niels Möller's avatar Niels Möller
Browse files

(do_verify_password): Interpret short

passwd-fields as password login disabled.
(do_lookup_user): Improved rules for dealing with shadow
passwords, disabled accounts, etc.

Rev: src/unix_user.c:1.50
parent 7448baf9
...@@ -253,8 +253,9 @@ do_verify_password(struct lsh_user *s, ...@@ -253,8 +253,9 @@ do_verify_password(struct lsh_user *s,
return; return;
} }
/* NOTE: Check for accounts with empty passwords. */ /* NOTE: Check for accounts with empty passwords, or generally short
if (!user->passwd || (user->passwd->length < 2) ) * passwd fields like "NP" or "x". */
if (!user->passwd || (user->passwd->length < 5) )
{ {
static const struct exception no_passwd static const struct exception no_passwd
= STATIC_EXCEPTION(EXC_USERAUTH, "No password in passwd db."); = STATIC_EXCEPTION(EXC_USERAUTH, "No password in passwd db.");
...@@ -922,16 +923,42 @@ make_unix_user(struct lsh_string *name, ...@@ -922,16 +923,42 @@ make_unix_user(struct lsh_string *name,
*/ */
/* NOTE: Calls functions using the disgusting convention of returning /* It's somewhat tricky to determine when accounts are disabled. To be
* pointers to static buffers. */ * safe, it is recommended that all disabled accounts have a harmless
* login-shell, like /bin/false.
/* This method filters out accounts that are known to be disabled *
* (i.e. root, or shadow style expiration). However, it may still * We return NULL for disabled accounts, according to the following
* return some disabled accounts. * rules:
*
* If our uid is non-zero, i.e. we're not running as root, then an
* account is considered valid if and only if it's uid matches the
* server's. We never try checking the shadow record.
*
* If we're running as root, first check the passwd record.
*
* o If the uid is zero, consider the account disabled. --root-login
* omits this check.
*
* o If the passwd equals "x", look up the shadow record, check
* expiration etc, and replace the passwd value with the one from the
* shadow record. If there's no shadow record, consider the account
* disabled.
* *
* An account that is disabled in /etc/passwd should have a value for * o If the passwd field is empty, consider the account disabled (we
* the login shell that prevents login; replacing the passwd field * usually don't want remote logins on pasword-less accounts). We may
* only doesn't prevent login using publickey authentication. */ * need to make this check optional, though.
*
* o If the passwd entry starts with a "*", consider the account
* disabled. (Other bogus values like "NP" means that the account is
* enabled, only password login is disabled)
*
* o Otherwise, the account is active, and a user record is returned.
*
* FIXME: One problem is sites that have active accounts with "*" in
* the password field. This seems common at sites using kerberos. We
* may need some option to disable the "*" == disabled interpretation.
*/
static struct lsh_user * static struct lsh_user *
do_lookup_user(struct user_db *s, do_lookup_user(struct user_db *s,
struct lsh_string *name, int free) struct lsh_string *name, int free)
...@@ -942,24 +969,57 @@ do_lookup_user(struct user_db *s, ...@@ -942,24 +969,57 @@ do_lookup_user(struct user_db *s,
const char *home; const char *home;
const char *shell; const char *shell;
const char *cname = lsh_get_cstring(name); const char *cname = lsh_get_cstring(name);
char *crypted;
uid_t me;
if (!cname) if (!cname)
{ {
if (free) if (free)
lsh_string_free(name); lsh_string_free(name);
return NULL; return NULL;
} }
me = getuid();
passwd = getpwnam(cname);
if (!passwd)
{
fail:
if (free)
lsh_string_free(name);
return NULL;
}
crypted = passwd->pw_passwd;
if ((passwd = getpwnam(cname)) if (!crypted || !*crypted)
/* Ignore accounts with empty passwords. */
goto fail;
if (me)
{
/* We're not root. Disable all accounts but our own. */
if (passwd->pw_uid != me)
goto fail;
/* NOTE: If we are running as the uid of the user, it seems like
* a good idea to let the HOME environment variable override the
* passwd-database. */
home = getenv("HOME");
if (!home)
home = passwd->pw_dir;
}
else
{
/* Check for root login */ /* Check for root login */
&& (passwd->pw_uid || self->allow_root)) if (!passwd->pw_uid && !self->allow_root)
{ goto fail;
char *crypted;
#if HAVE_GETSPNAM #if HAVE_GETSPNAM
/* FIXME: What's the most portable way to test for shadow passwords? /* FIXME: What's the most portable way to test for shadow
* A single character in the passwd field should cover most variants. */ * passwords? For now, we look up shadow database if and only if
if (passwd->pw_passwd && (strlen(passwd->pw_passwd) == 1)) * the passwd field equals "x". */
if (!strcmp(crypted, "x"))
{ {
struct spwd *shadowpwd; struct spwd *shadowpwd;
...@@ -1010,39 +1070,28 @@ do_lookup_user(struct user_db *s, ...@@ -1010,39 +1070,28 @@ do_lookup_user(struct user_db *s,
crypted = shadowpwd->sp_pwdp; crypted = shadowpwd->sp_pwdp;
} }
else
#endif /* HAVE_GETSPNAM */ #endif /* HAVE_GETSPNAM */
crypted = passwd->pw_passwd; /* Check again for empty passwd field (as it may have been
* replaced by the shadow one), and check if crypted starts with
/* NOTE: If we are running as the uid of the user, it seems * a star. */
* like a good idea to let the HOME environment variable if (!crypted || !*crypted || (*crypted == '*'))
* override the passwd-database. */ goto fail;
if (! (passwd->pw_uid
&& (passwd->pw_uid == getuid())
&& (home = getenv("HOME"))))
home = passwd->pw_dir;
if (self->login_shell) home = passwd->pw_dir;
/* Override the passwd database */
shell = self->login_shell;
else
/* Default login shell is /bin/sh */
shell = passwd->pw_shell ? passwd->pw_shell : "/bin/sh";
return make_unix_user(free ? name : lsh_string_dup(name),
passwd->pw_uid, passwd->pw_gid,
self,
crypted,
home, shell);
} }
if (self->login_shell)
/* Override the passwd database */
shell = self->login_shell;
else else
{ /* Default login shell is /bin/sh */
fail: shell = passwd->pw_shell ? passwd->pw_shell : "/bin/sh";
if (free)
lsh_string_free(name); return make_unix_user(free ? name : lsh_string_dup(name),
return NULL; passwd->pw_uid, passwd->pw_gid,
} self,
crypted,
home, shell);
} }
struct user_db * struct user_db *
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment