/* * Copyright 1990 - 1993, Julianne Frances Haugh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Julianne F. Haugh nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "rcsid.h" RCSID(PKG_VER "$Id: dpasswd.c,v 1.11 2000/08/26 18:27:18 marekm Exp $") #include #include #include #include #include #include "prototypes.h" #include "defines.h" #include "dialup.h" #define DTMP "/etc/d_passwd.tmp" /* * Prompts and messages go here. */ #define DIALCHG "changed password for %s\n" #define DIALADD "added password for %s\n" #define DIALREM "removed password for %s\n" static int aflg = 0; static int dflg = 0; static char *Prog; extern int optind; extern char *optarg; extern char *getpass(); /* local function prototypes */ static void usage(void); static void usage(void) { fprintf(stderr, _("Usage: %s [ -(a|d) ] shell\n"), Prog); exit(1); } int main(int argc, char **argv) { struct dialup *dial; struct dialup dent; struct stat sb; FILE *fp; char *sh = 0; char *cp; char pass[BUFSIZ]; int fd; int found = 0; int opt; Prog = Basename(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); while ((opt = getopt (argc, argv, "a:d:")) != EOF) { switch (opt) { case 'a': aflg++; sh = optarg; break; case 'd': dflg++; sh = optarg; break; default: usage (); } } if (! aflg && ! dflg) aflg++; if (! sh) { if (optind >= argc) usage (); else sh = argv[optind]; } if (aflg + dflg != 1) usage (); /* * Add a new shell to the password file, or update an existing * entry. Begin by getting an encrypted password for this * shell. */ if (aflg) { int tries = 3; dent.du_shell = sh; dent.du_passwd = ""; /* XXX warning: const */ again: if (! (cp = getpass(_("Shell password: ")))) exit (1); STRFCPY(pass, cp); strzero(cp); if (! (cp = getpass(_("re-enter Shell password: ")))) exit (1); if (strcmp (pass, cp)) { strzero(pass); strzero(cp); fprintf(stderr, _("%s: Passwords do not match, try again.\n"), Prog); if (--tries) goto again; exit(1); } strzero(cp); dent.du_passwd = pw_encrypt(pass, crypt_make_salt()); strzero(pass); } /* * Create the temporary file for the updated dialup password * information to be placed into. Turn it into a (FILE *) * for use by putduent(). */ if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) { snprintf(pass, sizeof pass, _("%s: can't create %s"), Prog, DTMP); perror (pass); exit (1); } if (! (fp = fdopen (fd, "r+"))) { snprintf(pass, sizeof pass, _("%s: can't open %s"), Prog, DTMP); perror (pass); unlink (DTMP); exit (1); } /* * Scan the dialup password file for the named entry, * copying out other entries along the way. Copying * stops when a match is found or the file runs out. */ while ((dial = getduent ())) { if (strcmp (dial->du_shell, sh) == 0) { found = 1; break; } if (putduent (dial, fp)) goto failure; } /* * To delete the entry, just don't copy it. To update * the entry, output the modified version - works with * new entries as well. */ if (dflg && ! found) { fprintf(stderr, _("%s: Shell %s not found.\n"), Prog, sh); goto failure; } if (aflg) if (putduent (&dent, fp)) goto failure; /* * Now copy out the remaining entries. Flush and close the * new file before doing anything nasty to the existing * file. */ while ((dial = getduent ())) if (putduent (dial, fp)) goto failure; if (fflush (fp)) goto failure; fclose (fp); /* * If the original file did not exist, we must create a new * file with owner "root" and mode 400. Otherwise we copy * the modes from the existing file to the new file. * * After this is done the new file will replace the old file. */ pwd_init(); if (! stat (DIALPWD, &sb)) { chown (DTMP, sb.st_uid, sb.st_gid); chmod (DTMP, sb.st_mode); unlink (DIALPWD); } else { chown (DTMP, 0, 0); chmod (DTMP, 0400); } if (! link (DTMP, DIALPWD)) unlink (DTMP); if (aflg && ! found) SYSLOG((LOG_INFO, DIALADD, sh)); else if (aflg && found) SYSLOG((LOG_INFO, DIALCHG, sh)); else if (dflg) SYSLOG((LOG_INFO, DIALREM, sh)); closelog(); sync (); exit (0); failure: unlink (DTMP); closelog(); exit (1); }