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

Reply via email to