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
usage(void)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
to64(register char * s,register long v,register int n)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
terminate(void)87 static void terminate(void)
88 {
89 if (tmp)
90 unlink(tmp);
91 exit(1);
92 }
93
catchintr(void)94 static void catchintr(void)
95 {
96 fprintf(stderr, "Interrupted.\n");
97 terminate();
98 }
99
savit(char * s)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
confirmed(char * accessgroup)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
getgroup(char * msg)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
addrecord(char * accessgroup,char * sysgroup,char * msg,FILE * f)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
list_privatefile(char * privatefile)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
main(int argc,char ** argv)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