Home | History | Annotate | Download | only in in.ftpd
      1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      2 
      3 /****************************************************************************
      4 
      5    Copyright (c) 1999,2000 WU-FTPD Development Group.
      6    All rights reserved.
      7 
      8    Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
      9    The Regents of the University of California.  Portions Copyright (c)
     10    1993, 1994 Washington University in Saint Louis.  Portions Copyright
     11    (c) 1996, 1998 Berkeley Software Design, Inc.  Portions Copyright (c)
     12    1998 Sendmail, Inc.  Portions Copyright (c) 1983, 1995, 1996, 1997 Eric
     13    P. Allman.  Portions Copyright (c) 1989 Massachusetts Institute of
     14    Technology.  Portions Copyright (c) 1997 by Stan Barber.  Portions
     15    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software
     16    Foundation, Inc.  Portions Copyright (c) 1997 by Kent Landfield.
     17 
     18    Use and distribution of this software and its source code are governed
     19    by the terms and conditions of the WU-FTPD Software License ("LICENSE").
     20 
     21    $Id: privatepw.c,v 1.10 2000/07/01 18:43:59 wuftpd Exp $
     22 
     23 ****************************************************************************/
     24 /*
     25    Subsystem:  WU-FTPD FTP Server
     26    Purpose:    Change WU-FTPD Guest Passwords
     27    File Name:  privatepw.c
     28 
     29    usage: privatepw [-c] [-f passwordfile] [-g group] accessgroup
     30    privatepw [-d] [-f passwordfile] accessgroup
     31    privatepw [-l] [-f passwordfile]
     32    -c:           creates a new file.
     33    -d:           deletes specified accessgroup.
     34    -l:           list contents of ftpgroups file.
     35    -f ftpgroups: updates the specified file.
     36    -g group:     set real group to the specified group.
     37 
     38    This software was initially written by Kent Landfield (kent (at) landfield.com)
     39  */
     40 
     41 #include <sys/types.h>
     42 #include <sys/signal.h>
     43 #include <sys/stat.h>
     44 #include <string.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <time.h>
     48 #include <grp.h>
     49 #include <unistd.h>
     50 #include "config.h"
     51 #include "pathnames.h"
     52 
     53 #define BUFLEN 256
     54 #define GROUPLEN 8
     55 
     56 char *tmp;
     57 char line[BUFLEN];
     58 FILE *fp;
     59 int verbose = 0;
     60 
     61 static unsigned char itoa64[] =	/* 0 ... 63 => ascii - 64 */
     62 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     63 
     64 void print_copyright(void);
     65 
     66 static void usage(void)
     67 {
     68     fprintf(stderr, "usage: privatepw [-c] [-f ftpgroups] [-g group] accessgroup\n");
     69     fprintf(stderr, "       privatepw [-d] [-f ftpgroups] accessgroup\n");
     70     fprintf(stderr, "       privatepw [-l] [-f ftpgroups]\n");
     71     fprintf(stderr, "\t\t-c:           creates a new file.\n");
     72     fprintf(stderr, "\t\t-d:           deletes specified accessgroup.\n");
     73     fprintf(stderr, "\t\t-l:           list contents of ftpgroups file.\n");
     74     fprintf(stderr, "\t\t-f ftpgroups: updates the specified file.\n");
     75     fprintf(stderr, "\t\t-g group:     set real group to the specified group.\n");
     76     exit(1);
     77 }
     78 
     79 static void to64(register char *s, register long v, register int n)
     80 {
     81     while (--n >= 0) {
     82 	*s++ = itoa64[v & 0x3f];
     83 	v >>= 6;
     84     }
     85 }
     86 
     87 static void terminate(void)
     88 {
     89     if (tmp)
     90 	unlink(tmp);
     91     exit(1);
     92 }
     93 
     94 static void catchintr(void)
     95 {
     96     fprintf(stderr, "Interrupted.\n");
     97     terminate();
     98 }
     99 
    100 static char *savit(char *s)
    101 {
    102     char *d;
    103 
    104     if ((d = (char *) malloc(strlen(s) + 1)) == NULL) {
    105 	fprintf(stderr, "Whoa... Malloc failed.\n");
    106 	terminate();
    107     }
    108     strcpy(d, s);
    109     return (d);
    110 }
    111 
    112 static int confirmed(char *accessgroup)
    113 {
    114     register int ch;
    115 
    116     printf("Delete %s: Are your sure ? (y/n) ", accessgroup);
    117     ch = getc(stdin);
    118     if (ch == 'y')
    119 	return (1);
    120     return (0);
    121 }
    122 
    123 static char *getgroup(char *msg)
    124 {
    125     register int ch;
    126     register char *p;
    127     static char buf[GROUPLEN + 1];
    128 
    129     fputs(msg, stderr);
    130     rewind(stderr);		/* implied flush */
    131     for (p = buf; (ch = getc(stdin)) != EOF && ch != '\n';)
    132 	if (p < buf + GROUPLEN)
    133 	    *p++ = ch;
    134     *p = '\0';
    135 
    136     if (getgrnam(buf) == NULL) {
    137 	fprintf(stderr, "Invalid group \'%s\' specified\n", buf);
    138 	terminate();
    139     }
    140     return (buf);
    141 }
    142 
    143 static void addrecord(char *accessgroup, char *sysgroup, char *msg, FILE *f)
    144 {
    145     char *pw, *cpw, salt[3];
    146 #ifndef NO_CRYPT_PROTO
    147     extern char *crypt(const char *, const char *);
    148 #endif
    149     char *getpass(const char *prompt);
    150 
    151     printf("%s %s\n", msg, accessgroup);
    152 
    153     if (sysgroup[0] == '\0')
    154 	strcpy(sysgroup, getgroup("Real System Group to use: "));
    155 
    156     pw = savit((char *) getpass("New password: "));
    157     if (strcmp(pw, (char *) getpass("Re-type new password: "))) {
    158 	fprintf(stderr, "They don't match, sorry.\n");
    159 	if (tmp)
    160 	    unlink(tmp);
    161 	exit(1);
    162     }
    163 
    164     srand((int) time((time_t *) NULL));
    165     to64(&salt[0], rand(), 2);
    166     cpw = crypt(pw, salt);
    167     free(pw);
    168     fprintf(f, "%s:%s:%s\n", accessgroup, cpw, sysgroup);
    169 }
    170 
    171 static void list_privatefile(char *privatefile)
    172 {
    173     if (verbose)
    174 	fprintf(stderr, "Private File: %s file.\n", privatefile);
    175 
    176     if ((fp = fopen(privatefile, "r")) == NULL) {
    177 	fprintf(stderr, "Could not open %s file.\n", privatefile);
    178 	exit(1);
    179     }
    180 
    181     printf("\nWU-FTPD Private file: %s\n", privatefile);
    182     printf("accessgroup : password : system group\n");
    183     printf("-------\n");
    184 
    185     while (fgets(line, BUFLEN, fp) != NULL)
    186 	fputs(line, stdout);
    187     printf("-------\n");
    188 }
    189 
    190 int main(int argc, char **argv)
    191 {
    192     extern void (*signal(int sig, void (*disp) (int))) (int);
    193     extern int getopt(int argc, char *const *argv, const char *optstring);
    194     extern char *optarg;
    195     extern int optind;
    196     extern int opterr;
    197 
    198     struct stat stbuf;
    199 
    200     char realgroup[BUFLEN];
    201     char *passwdpath;
    202     char *cp;
    203 
    204     char accessgroup[BUFLEN];
    205     char w[BUFLEN];
    206     char command[BUFLEN];
    207 
    208     int create;
    209     int delete;
    210     int list;
    211     int found;
    212     int lineno;
    213     int c;
    214 
    215     FILE *tfp;
    216 
    217 #ifdef HAVE_MKSTEMP
    218     char tmpname[BUFLEN];
    219     int tfd;
    220 #endif
    221 
    222     opterr = 0;
    223     create = 0;
    224     delete = 0;
    225     list = 0;
    226 
    227     tmp = NULL;
    228     realgroup[0] = '\0';
    229 
    230     passwdpath = _PATH_PRIVATE;
    231 
    232     if (argc == 1)
    233 	usage();
    234 
    235     while ((c = getopt(argc, argv, "Vvcdf:g:l")) != EOF) {
    236 	switch (c) {
    237 	case 'd':
    238 	    delete++;
    239 	    break;
    240 	case 'c':
    241 	    create++;
    242 	    break;
    243 	case 'f':
    244 	    passwdpath = optarg;
    245 	    break;
    246 	case 'g':
    247 	    strcpy(realgroup, optarg);
    248 	    if (getgrnam(realgroup) == NULL) {
    249 		fprintf(stderr, "Invalid group \'%s\' specified\n", realgroup);
    250 		return (1);
    251 	    }
    252 	    break;
    253 	case 'l':
    254 	    list++;
    255 	    break;
    256 	case 'v':
    257 	    verbose++;
    258 	    break;
    259 	case 'V':
    260 	    print_copyright();
    261 	    return (0);
    262 	    /* NOTREACHED */
    263 	default:
    264 	    usage();
    265 	}
    266     }
    267 
    268     if (list) {
    269 	list_privatefile(passwdpath);
    270 	return (0);
    271     }
    272 
    273     if (optind >= argc) {
    274 	fprintf(stderr, "Need to specify an accessgroup name.\n");
    275 	usage();
    276     }
    277 
    278     signal(SIGINT, (void (*)()) catchintr);
    279 
    280     strcpy(accessgroup, argv[optind]);
    281 
    282     if (create) {
    283 	if (stat(passwdpath, &stbuf) == 0) {
    284 	    fprintf(stderr, "%s exists, cannot create it.\n", passwdpath);
    285 	    fprintf(stderr, "Remove -c option or use the -f option to specify another.\n");
    286 	    return (1);
    287 	}
    288 
    289 	if ((tfp = fopen(passwdpath, "w")) == NULL) {
    290 	    fprintf(stderr, "Could not open \"%s\" for writing.\n", passwdpath);
    291 	    perror("fopen");
    292 	    return (1);
    293 	}
    294 
    295 	tmp = passwdpath;
    296 
    297 	printf("Creating WU-FTPD Private file: %s\n", passwdpath);
    298 	addrecord(accessgroup, realgroup, "Adding accessgroup", tfp);
    299 
    300 	fclose(tfp);
    301 	return (0);
    302     }
    303 
    304 #ifdef HAVE_MKSTEMP
    305     strcpy (tmpname, "/tmp/privatepwXXXXXX");
    306     tmp = tmpname;
    307     if ((tfd = mkstemp(tmp)) < 0) {
    308 	fprintf(stderr, "Could not open temp file.\n");
    309 	return (1);
    310     }
    311 
    312     if ((tfp = fdopen(tfd, "w")) == NULL) {
    313 	unlink(tmp);
    314 	fprintf(stderr, "Could not open temp file.\n");
    315 	return (1);
    316     }
    317 #else
    318     tmp = tmpnam(NULL);
    319 
    320     if ((tfp = fopen(tmp, "w")) == NULL) {
    321 	fprintf(stderr, "Could not open temp file.\n");
    322 	return (1);
    323     }
    324 #endif
    325 
    326     if ((fp = fopen(passwdpath, "r")) == NULL) {
    327 	fprintf(stderr, "Could not open %s file.\n", passwdpath);
    328 	fprintf(stderr, "Use -c option to create new one.\n");
    329 	return (1);
    330     }
    331 
    332     lineno = 0;
    333     found = 0;
    334 
    335     while (fgets(line, BUFLEN, fp) != NULL) {
    336 	lineno++;
    337 
    338 	if (found || (line[0] == '#') || (!line[0])) {
    339 	    fputs(line, tfp);
    340 	    continue;
    341 	}
    342 
    343 	strcpy(w, line);
    344 
    345 	if ((cp = strchr(w, ':')) == NULL) {
    346 	    fprintf(stderr, "%s: line %d: invalid record format.\n", passwdpath, lineno);
    347 	    continue;
    348 	}
    349 	*cp++ = '\0';
    350 
    351 	if ((cp = strchr(cp, ':')) == NULL) {
    352 	    fprintf(stderr, "%s: line %d: invalid record format.\n", passwdpath, lineno);
    353 	    continue;
    354 	}
    355 	*cp++ = '\0';
    356 
    357 	if (strcmp(accessgroup, w)) {
    358 	    fputs(line, tfp);
    359 	    continue;
    360 	}
    361 	else {
    362 	    if (delete) {
    363 		if (!confirmed(accessgroup))
    364 		    terminate();
    365 	    }
    366 	    else {
    367 		if (realgroup[0] == '\0') {
    368 		    strcpy(realgroup, cp);
    369 		    if ((cp = strchr(realgroup, '\n')) != NULL)
    370 			*cp = '\0';
    371 		}
    372 		addrecord(accessgroup, realgroup, "Updating accessgroup", tfp);
    373 	    }
    374 	    found = 1;
    375 	}
    376     }
    377 
    378     if (!found && !delete)
    379 	addrecord(accessgroup, realgroup, "Adding accessgroup", tfp);
    380     else if (!found && delete) {
    381 	fprintf(stderr, "%s not found in %s.\n", accessgroup, passwdpath);
    382 	terminate();
    383     }
    384 
    385     fclose(fp);
    386     fclose(tfp);
    387 
    388     sprintf(command, "cp %s %s", tmp, passwdpath);
    389     system(command);
    390     unlink(tmp);
    391     return (0);
    392 }
    393