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@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 }