I'm sorry to nag you about this, but I would *really* appreciate some
comments on this code from those of you who are familiar with shadow
passwords. I don't want to release security critical code based on my
guesses about how things work, so if I don't get any more solid
reasons to believe that the below code is reasonably correct, I would
have to disable it.
I know that the support for shadow passwords in the previous versions
is also somewhat broken (as reported on the list), but at least I
*understand* in which way it is broken.
Regards,
/Niels
[EMAIL PROTECTED] (Niels M�ller) writes:
> Thayne Harbaugh <[EMAIL PROTECTED]> writes:
>
> > /etc/shadow contains userids (which correlate to /etc/passwd),
> > encrytped passwords, and password dates/days for how often
> > passwords have to and can be changed, when users are warned
> > about their passwords needing changing, and when accounts
> > are forcibly expired. "man chage" and "man shadow".
>
> I have tried to get this right, based on the manpages for "shadow" and
> "getspnam" on a Solaris box. Some questions I could not find answers
> for in the docs:
>
> o What values will I find in the shadowpwd struct if there is no
> expiration date and no limit on password age? My guess is zero.
>
> o What about timezones? Are the absolute "days" values in sp_lstchg
> and sp_expire in GMT or localtime? For now, I'm assuming GMT and if
> that's wrong I hope a few hours off isn't too bad.
>
> I would be grateful if you could review the new code (do_lookup_user()
> in unix_user.c) and tell me if I have gotten the shadow stuff right.
> The function is included below, the rest of the code is at
> http://www.lysator.liu.se/~nisse/lsh/src as usual.
>
> /* This method filters out accounts that are known to be disabled
> * (i.e. root, or shadow style expiration). However, it may still
> * return some disabled accounts.
> *
> * An account that is disabled in /etc/passwd should have a value for
> * the login shell that prevents login; replacing the passwd field
> * only doesn't prevent login using publickey authentication. */
> static struct user *
> do_lookup_user(struct user_db *s,
> struct lsh_string *name, int free)
> {
> CAST(unix_user_db, self, s);
>
> struct passwd *passwd;
>
> name = make_cstring(name, free);
>
> if (!name)
> return NULL;
>
> if ((passwd = getpwnam(name->data))
> /* Check for root login */
> && (passwd->pw_uid || self->allow_root))
> {
> char *crypted;
>
> #if HAVE_GETSPNAM
> /* FIXME: What's the most portable way to test for shadow passwords?
> * A single character in the passwd field should cover most variants. */
> if (passwd->pw_passwd && (strlen(passwd->pw_passwd) == 1))
> {
> struct spwd *shadowpwd;
>
> /* Current day number since January 1, 1970.
> *
> * FIXME: Which timezone is used in the /etc/shadow file? */
> long now = time(NULL) / (3600 * 24);
>
> if (!(shadowpwd = getspnam(name->data)))
> goto fail;
>
> /* FIXME: I'm assuming that zero means there's no expiry
> * date. */
> if (shadowpwd->sp_expire && (now > shadowpwd->sp_expire))
> {
> werror("Access denied for user '%pS', account expired.\n", name);
> goto fail;
> }
>
> /* FIXME: I'm assuming that zero means that there is no
> * restriction on password age. */
> if (shadowpwd->sp_max &&
> (now > (shadowpwd->sp_lstchg + shadowpwd->sp_max)))
> {
> werror("Access denied for user '%pS', password too old.\n", name);
> goto fail;
> }
>
> /* FIXME: We could look at sp_warn and figure out if it is
> * appropriate to send an SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
> * message. */
>
> crypted = shadowpwd->sp_pwdp;
> }
> else
> #endif /* HAVE_GETSPNAM */
> crypted = passwd->pw_passwd;
>
> return make_unix_user(name,
> passwd->pw_uid, passwd->pw_gid,
> crypted,
> passwd->pw_dir, passwd->pw_shell);
> }
> else
> {
> fail:
> lsh_string_free(name);
> return NULL;
> }
> }
>
> Regards,
> /Niels