/* * pwconv - create or update /etc/shadow with information from * /etc/passwd. * * It is more like SysV pwconv, slightly different from the original Shadow * pwconv. Depends on "x" as password in /etc/passwd which means that the * password has already been moved to /etc/shadow. There is no need to move * /etc/npasswd to /etc/passwd, password files are updated using library * routines with proper locking. * * Can be used to update /etc/shadow after adding/deleting users by editing * /etc/passwd. There is no man page yet, but this program should be close * to pwconv(1M) on Solaris 2.x. * * Warning: make sure that all users have "x" as the password in /etc/passwd * before running this program for the first time on a system which already * has shadow passwords. Anything else (like "*" from old versions of the * shadow suite) will replace the user's encrypted password in /etc/shadow. * * Doesn't currently support pw_age information in /etc/passwd, and doesn't * support DBM files. Add it if you need it... * * Copyright (C) 1996-1997, Marek Michalkiewicz * * This program may be freely used and distributed for any purposes. If you * improve it, please send me your changes. Thanks! */ #include #include "rcsid.h" RCSID (PKG_VER "$Id: pwconv.c,v 1.15 2003/06/19 18:11:01 kloczek Exp $") #include #include #include #include #include #include #include #include #include "prototypes.h" #include "defines.h" #include "pwio.h" #include "shadowio.h" #include "getdef.h" #ifdef SHADOWPWD /* * exit status values */ #define E_SUCCESS 0 /* success */ #define E_NOPERM 1 /* permission denied */ #define E_USAGE 2 /* invalid command syntax */ #define E_FAILURE 3 /* unexpected failure, nothing done */ #define E_MISSING 4 /* unexpected failure, passwd file missing */ #define E_PWDBUSY 5 /* passwd file(s) busy */ #define E_BADENTRY 6 /* bad shadow entry */ static int shadow_locked = 0, passwd_locked = 0; /* local function prototypes */ static void fail_exit (int); static void fail_exit (int status) { if (shadow_locked) spw_unlock (); if (passwd_locked) pw_unlock (); exit (status); } int main (int argc, char **argv) { const struct passwd *pw; struct passwd pwent; const struct spwd *sp; struct spwd spent; char *Prog = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); if (!pw_lock ()) { fprintf (stderr, _("%s: can't lock passwd file\n"), Prog); fail_exit (E_PWDBUSY); } passwd_locked++; if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: can't open passwd file\n"), Prog); fail_exit (E_MISSING); } if (!spw_lock ()) { fprintf (stderr, _("%s: can't lock shadow file\n"), Prog); fail_exit (E_PWDBUSY); } shadow_locked++; if (!spw_open (O_CREAT | O_RDWR)) { fprintf (stderr, _("%s: can't open shadow file\n"), Prog); fail_exit (E_FAILURE); } /* * Remove /etc/shadow entries for users not in /etc/passwd. */ spw_rewind (); while ((sp = spw_next ())) { if (pw_locate (sp->sp_namp)) continue; if (!spw_remove (sp->sp_namp)) { /* * This shouldn't happen (the entry exists) but... */ fprintf (stderr, _ ("%s: can't remove shadow entry for %s\n"), Prog, sp->sp_namp); fail_exit (E_FAILURE); } } /* * Update shadow entries which don't have "x" as pw_passwd. Add any * missing shadow entries. */ pw_rewind (); while ((pw = pw_next ())) { sp = spw_locate (pw->pw_name); if (sp) { /* do we need to update this entry? */ if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) continue; /* update existing shadow entry */ spent = *sp; } else { /* add new shadow entry */ memset (&spent, 0, sizeof spent); spent.sp_namp = pw->pw_name; spent.sp_min = getdef_num ("PASS_MIN_DAYS", -1); spent.sp_max = getdef_num ("PASS_MAX_DAYS", -1); spent.sp_warn = getdef_num ("PASS_WARN_AGE", -1); spent.sp_inact = -1; spent.sp_expire = -1; spent.sp_flag = -1; } spent.sp_pwdp = pw->pw_passwd; spent.sp_lstchg = time ((time_t *) 0) / (24L * 3600L); if (!spw_update (&spent)) { fprintf (stderr, _ ("%s: can't update shadow entry for %s\n"), Prog, spent.sp_namp); fail_exit (E_FAILURE); } /* remove password from /etc/passwd */ pwent = *pw; pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */ if (!pw_update (&pwent)) { fprintf (stderr, _ ("%s: can't update passwd entry for %s\n"), Prog, pwent.pw_name); fail_exit (E_FAILURE); } } if (!spw_close ()) { fprintf (stderr, _("%s: can't update shadow file\n"), Prog); fail_exit (E_FAILURE); } if (!pw_close ()) { fprintf (stderr, _("%s: can't update passwd file\n"), Prog); fail_exit (E_FAILURE); } chmod (PASSWD_FILE "-", 0600); /* /etc/passwd- (backup file) */ spw_unlock (); pw_unlock (); exit (E_SUCCESS); } #else /* !SHADOWPWD */ int main (int argc, char **argv) { fprintf (stderr, "%s: not configured for shadow password support.\n", argv[0]); exit (1); } #endif /* !SHADOWPWD */