]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_options.c
Sam's bug fix in the AFP connection negotiation stage and his preliminary
[netatalk.git] / etc / afpd / afp_options.c
1 /*
2  * $Id: afp_options.c,v 1.27.2.1 2003-06-09 14:30:43 srittau Exp $
3  *
4  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5  * Copyright (c) 1990,1993 Regents of The University of Michigan.
6  * All Rights Reserved.  See COPYRIGHT.
7  *
8  * modified from main.c. this handles afp options.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif /* HAVE_CONFIG_H */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 /* STDC check */
19 #if STDC_HEADERS
20 #include <string.h>
21 #else /* STDC_HEADERS */
22 #ifndef HAVE_STRCHR
23 #define strchr index
24 #define strrchr index
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
27 #ifndef HAVE_MEMCPY
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
32
33 #include <ctype.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <atalk/logger.h>
40
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #ifdef HAVE_NETDB_H
44 #include <netdb.h>
45 #endif /* HAVE_NETDB_H */
46
47 #include <atalk/paths.h>
48 #include <atalk/util.h>
49 #include "globals.h"
50 #include "status.h"
51 #include "auth.h"
52
53 #include <atalk/compat.h>
54
55 #ifdef ADMIN_GRP
56 #include <grp.h>
57 #include <sys/types.h>
58 #endif /* ADMIN_GRP */
59
60 #ifndef MIN
61 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
62 #endif /* MIN */
63
64 #define OPTIONS "dn:f:s:uc:g:P:ptDS:TL:F:U:Ivm:"
65 #define LENGTH 512
66
67 /* return an option. this uses an internal array, so it's necessary
68  * to duplicate it if you want to hold it for long. this is probably
69  * non-optimal. */
70 static char *getoption(char *buf, const char *option)
71 {
72     static char string[LENGTH + 1];
73     char *end;
74     int len;
75
76     if (option && (buf = strstr(buf, option)))
77         buf = strpbrk(buf, " \t");
78
79     while (buf && isspace(*buf))
80         buf++;
81
82     if (!buf)
83         return NULL;
84
85     /* search for any quoted stuff */
86     if (*buf == '"' && (end = strchr(buf + 1, '"'))) {
87         buf++;
88         len = MIN(end - buf, LENGTH);
89     } else if ((end = strpbrk(buf, " \t\n"))) /* option or eoln */
90         len = MIN(end - buf, LENGTH);
91     else
92         len = MIN(strlen(buf), LENGTH);
93
94     strncpy(string, buf, len);
95     string[len] = '\0';
96     return string;
97 }
98
99 /* get rid of any allocated afp_option buffers. */
100 void afp_options_free(struct afp_options *opt,
101                       const struct afp_options *save)
102 {
103     if (opt->defaultvol && (opt->defaultvol != save->defaultvol))
104         free(opt->defaultvol);
105     if (opt->systemvol && (opt->systemvol != save->systemvol))
106         free(opt->systemvol);
107     if (opt->loginmesg && (opt->loginmesg != save->loginmesg))
108         free(opt->loginmesg);
109     if (opt->guest && (opt->guest != save->guest))
110         free(opt->guest);
111     if (opt->server && (opt->server != save->server))
112         free(opt->server);
113     if (opt->ipaddr && (opt->ipaddr != save->ipaddr))
114         free(opt->ipaddr);
115     if (opt->fqdn && (opt->fqdn != save->fqdn))
116         free(opt->fqdn);
117     if (opt->uampath && (opt->uampath != save->uampath))
118         free(opt->uampath);
119     if (opt->uamlist && (opt->uamlist != save->uamlist))
120         free(opt->uamlist);
121     if (opt->nlspath && (opt->nlspath != save->nlspath))
122         free(opt->nlspath);
123     if (opt->passwdfile && (opt->passwdfile != save->passwdfile))
124         free(opt->passwdfile);
125     if (opt->k5service && (opt->k5service != save->k5service))
126         free(opt->k5service);
127     if (opt->k5realm && (opt->k5realm != save->k5realm))
128         free(opt->k5realm);
129 }
130
131 /* initialize options */
132 void afp_options_init(struct afp_options *options)
133 {
134     memset(options, 0, sizeof(struct afp_options));
135     options->connections = 20;
136     options->pidfile = _PATH_AFPDLOCK;
137     options->defaultvol = _PATH_AFPDDEFVOL;
138     options->systemvol = _PATH_AFPDSYSVOL;
139     options->configfile = _PATH_AFPDCONF;
140     options->nlspath = _PATH_AFPDNLSPATH;
141     options->uampath = _PATH_AFPDUAMPATH;
142     options->uamlist = "uams_clrtxt.so,uams_dhx.so";
143     options->guest = "nobody";
144     options->loginmesg = "";
145     options->transports = AFPTRANS_ALL;
146     options->passwdfile = _PATH_AFPDPWFILE;
147     options->tickleval = 30;
148     options->timeout = 4;
149     options->server_notif = 1;
150     options->authprintdir = NULL;
151     options->umask = 0;
152 #ifdef ADMIN_GRP
153     options->admingid = 0;
154 #endif /* ADMIN_GRP */
155     options->k5service = NULL;
156     options->k5realm = NULL;
157 }
158
159 /* parse an afpd.conf line. i'm doing it this way because it's
160  * easy. it is, however, massively hokey. sample afpd.conf:
161  * server:AFPServer@zone -loginmesg "blah blah blah" -nodsi 
162  * "private machine"@zone2 -noguest -port 11012
163  * server2 -nocleartxt -nodsi
164  *
165  * NOTE: this ignores unknown options 
166  */
167 int afp_options_parseline(char *buf, struct afp_options *options)
168 {
169     char *c, *opt;
170
171     /* handle server */
172     if (*buf != '-' && (c = getoption(buf, NULL)) && (opt = strdup(c)))
173         options->server = opt;
174
175     /* parse toggles */
176     if (strstr(buf, " -nodebug"))
177         options->flags &= ~OPTION_DEBUG;
178 #ifdef USE_SRVLOC
179     if (strstr(buf, " -noslp"))
180         options->flags |= OPTION_NOSLP;
181 #endif /* USE_SRVLOC */
182
183     if (strstr(buf, " -nouservolfirst"))
184         options->flags &= ~OPTION_USERVOLFIRST;
185     if (strstr(buf, " -uservolfirst"))
186         options->flags |= OPTION_USERVOLFIRST;
187     if (strstr(buf, " -nouservol"))
188         options->flags |= OPTION_NOUSERVOL;
189     if (strstr(buf, " -uservol"))
190         options->flags &= ~OPTION_NOUSERVOL;
191     if (strstr(buf, " -proxy"))
192         options->flags |= OPTION_PROXY;
193     if (strstr(buf, " -noicon"))
194         options->flags &= ~OPTION_CUSTOMICON;
195     if (strstr(buf, " -icon"))
196         options->flags |= OPTION_CUSTOMICON;
197
198     /* passwd bits */
199     if (strstr(buf, " -nosavepassword"))
200         options->passwdbits |= PASSWD_NOSAVE;
201     if (strstr(buf, " -savepassword"))
202         options->passwdbits &= ~PASSWD_NOSAVE;
203     if (strstr(buf, " -nosetpassword"))
204         options->passwdbits &= ~PASSWD_SET;
205     if (strstr(buf, " -setpassword"))
206         options->passwdbits |= PASSWD_SET;
207
208     /* transports */
209     if (strstr(buf, " -transall"))
210         options->transports = AFPTRANS_ALL;
211     if (strstr(buf, " -notransall"))
212         options->transports = AFPTRANS_NONE;
213     if (strstr(buf, " -tcp"))
214         options->transports |= AFPTRANS_TCP;
215     if (strstr(buf, " -notcp"))
216         options->transports &= ~AFPTRANS_TCP;
217     if (strstr(buf, " -ddp"))
218         options->transports |= AFPTRANS_DDP;
219     if (strstr(buf, " -noddp"))
220         options->transports &= ~AFPTRANS_DDP;
221     if (strstr(buf, "-client_polling"))
222         options->server_notif = 0;
223
224     /* figure out options w/ values. currently, this will ignore the setting
225      * if memory is lacking. */
226     if ((c = getoption(buf, "-defaultvol")) && (opt = strdup(c)))
227         options->defaultvol = opt;
228     if ((c = getoption(buf, "-systemvol")) && (opt = strdup(c)))
229         options->systemvol = opt;
230     if ((c = getoption(buf, "-loginmesg")) && (opt = strdup(c)))
231         options->loginmesg = opt;
232     if ((c = getoption(buf, "-guestname")) && (opt = strdup(c)))
233         options->guest = opt;
234     if ((c = getoption(buf, "-passwdfile")) && (opt = strdup(c)))
235         options->passwdfile = opt;
236     if ((c = getoption(buf, "-passwdminlen")))
237         options->passwdminlen = MIN(1, atoi(c));
238     if ((c = getoption(buf, "-loginmaxfail")))
239         options->loginmaxfail = atoi(c);
240     if ((c = getoption(buf, "-tickleval"))) {
241         options->tickleval = atoi(c);
242         if (options->tickleval <= 0) {
243             options->tickleval = 30;
244         }
245     }
246     if ((c = getoption(buf, "-timeout"))) {
247         options->timeout = atoi(c);
248         if (options->timeout <= 0) {
249             options->timeout = 4;
250         }
251     }
252
253     if ((c = getoption(buf, "-server_quantum")))
254         options->server_quantum = strtoul(c, NULL, 0);
255
256 #ifndef DISABLE_LOGGER
257     /* -setuplogtype <syslog|filelog> <logtype> <loglevel> <filename>*/
258     /* -[no]setuplog <logtype> <loglevel> [<filename>]*/
259     if ((c = getoption(buf, "-setuplog")))
260     {
261       char *ptr, *logsource, *logtype, *loglevel, *filename;
262
263       LOG(log_debug6, logtype_afpd, "setting up logtype, c is %s", c);
264       ptr = c;
265       
266       /* 
267       logsource = ptr = c;
268       if (ptr)
269       {
270         ptr = strpbrk(ptr, " \t");
271         if (ptr) 
272         {
273           *ptr++ = 0;
274           while (*ptr && isspace(*ptr))
275             ptr++;
276         }
277       }
278       */
279
280       logtype = ptr; 
281       if (ptr)
282       {
283         ptr = strpbrk(ptr, " \t");
284         if (ptr) 
285         {
286           *ptr++ = 0;
287           while (*ptr && isspace(*ptr))
288             ptr++;
289         }
290       }
291
292       loglevel = ptr;
293       if (ptr)
294       {
295         ptr = strpbrk(ptr, " \t");
296         if (ptr) 
297         {
298           *ptr++ = 0;
299           while (*ptr && isspace(*ptr))
300             ptr++;
301         }
302       }
303
304       filename = ptr;
305       if (ptr)
306       {
307         ptr = strpbrk(ptr, " \t");
308         if (ptr) 
309         {
310           *ptr++ = 0;
311           while (*ptr && isspace(*ptr))
312             ptr++;
313         }
314       }
315
316       LOG(log_debug7, logtype_afpd, "calling setuplog %s %s %s", 
317           logtype, loglevel, filename);
318
319       setuplog(logtype, loglevel, filename);
320     }
321
322     if ((c = getoption(buf, "-unsetuplog")))
323     {
324       char *ptr, *logtype, *loglevel, *filename;
325
326       LOG(log_debug6, logtype_afpd, "unsetting up logtype, c is %s", c);
327
328       ptr = c;
329       logtype = ptr;
330       if (ptr)
331       {
332         ptr = strpbrk(ptr, " \t");
333         if (ptr)
334         {
335           *ptr++ = 0;
336           while (*ptr && isspace(*ptr))
337             ptr++;
338         }
339       }
340
341       loglevel = ptr;
342       if (ptr)
343       {
344         ptr = strpbrk(ptr, " \t");
345         if (ptr)
346         {
347           *ptr++ = 0;
348            while (*ptr && isspace(*ptr))
349              ptr++;
350         }
351       }
352
353       filename = ptr;
354       if (ptr)
355       {
356         ptr = strpbrk(ptr, " \t");
357         if (ptr)
358         {
359           *ptr++ = 0;
360           while (*ptr && isspace(*ptr))
361             ptr++;
362         }
363       }
364       
365       LOG(log_debug7, logtype_afpd, "calling setuplog %s %s %s",
366               logtype, NULL, filename);
367
368       setuplog(logtype, NULL, filename);
369     }
370 #endif /* DISABLE_LOGGER */
371 #ifdef ADMIN_GRP
372     if ((c = getoption(buf, "-admingroup"))) {
373         struct group *gr = getgrnam(c);
374         if (gr != NULL) {
375             options->admingid = gr->gr_gid;
376         }
377     }
378 #endif /* ADMIN_GRP */
379
380     if ((c = getoption(buf, "-k5service")) && (opt = strdup(c)))
381         options->k5service = opt;
382     if ((c = getoption(buf, "-k5realm")) && (opt = strdup(c)))
383         options->k5realm = opt;
384     if ((c = getoption(buf, "-k5keytab")))
385         setenv( "KRB5_KTNAME", c, 1 );
386     if ((c = getoption(buf, "-authprintdir")) && (opt = strdup(c)))
387         options->authprintdir = opt;
388     if ((c = getoption(buf, "-uampath")) && (opt = strdup(c)))
389         options->uampath = opt;
390     if ((c = getoption(buf, "-uamlist")) && (opt = strdup(c)))
391         options->uamlist = opt;
392     if ((c = getoption(buf, "-nlspath")) && (opt = strdup(c)))
393         options->nlspath = opt;
394
395     if ((c = getoption(buf, "-ipaddr"))) {
396         struct in_addr inaddr;
397         if (inet_aton(c, &inaddr) && (opt = strdup(c))) {
398             if (!gethostbyaddr((const char *) &inaddr, sizeof(inaddr), AF_INET))
399                 LOG(log_info, logtype_afpd, "WARNING: can't find %s\n", opt);
400             options->ipaddr = opt;
401         }
402     }
403
404     if ((c = getoption(buf, "-port")))
405         options->port = atoi(c);
406     if ((c = getoption(buf, "-ddpaddr")))
407         atalk_aton(c, &options->ddpaddr);
408
409     /* do a little checking for the domain name. */
410     if ((c = getoption(buf, "-fqdn"))) {
411         char *p = strchr(c, ':');
412         if (p)
413             *p = '\0';
414         if (gethostbyname(c)) {
415             if (p)
416                 *p = ':';
417             if ((opt = strdup(c)))
418                 options->fqdn = opt;
419         }
420     }
421
422     return 1;
423 }
424
425 int afp_options_parse(int ac, char **av, struct afp_options *options)
426 {
427     extern char *optarg;
428     extern int optind;
429
430     char *p;
431     char *tmp;  /* Used for error checking the result of strtol */
432     int c, err = 0;
433
434     if (gethostname(options->hostname, sizeof(options->hostname )) < 0 ) {
435         perror( "gethostname" );
436         return 0;
437     }
438     if (( p = strchr(options->hostname, '.' )) != 0 ) {
439         *p = '\0';
440     }
441
442     if (( p = strrchr( av[ 0 ], '/' )) == NULL ) {
443         p = av[ 0 ];
444     } else {
445         p++;
446     }
447
448     while (( c = getopt( ac, av, OPTIONS )) != EOF ) {
449         switch ( c ) {
450         case 'd' :
451             options->flags |= OPTION_DEBUG;
452             break;
453         case 'n' :
454             options->server = optarg;
455             break;
456         case 'f' :
457             options->defaultvol = optarg;
458             break;
459         case 's' :
460             options->systemvol = optarg;
461             break;
462         case 'u' :
463             options->flags |= OPTION_USERVOLFIRST;
464             break;
465         case 'c' :
466             options->connections = atoi( optarg );
467             break;
468         case 'g' :
469             options->guest = optarg;
470             break;
471
472         case 'P' :
473             options->pidfile = optarg;
474             break;
475
476         case 'p':
477             options->passwdbits |= PASSWD_NOSAVE;
478             break;
479         case 't':
480             options->passwdbits |= PASSWD_SET;
481             break;
482
483         case 'D':
484             options->transports &= ~AFPTRANS_DDP;
485             break;
486         case 'S':
487             options->port = atoi(optarg);
488             break;
489         case 'T':
490             options->transports &= ~AFPTRANS_TCP;
491             break;
492         case 'L':
493             options->loginmesg = optarg;
494             break;
495         case 'F':
496             options->configfile = optarg;
497             break;
498         case 'U':
499             options->uamlist = optarg;
500             break;
501         case 'v':       /* version */
502             printf( "afpd (version %s)\n", VERSION );
503             exit ( 1 );
504             break;
505         case 'I':
506             options->flags |= OPTION_CUSTOMICON;
507             break;
508         case 'm':
509             options->umask = strtoul(optarg, &tmp, 8);
510             if ((options->umask > 0777)) {
511                 fprintf(stderr, "%s: out of range umask setting provided\n", p);
512                 err++;
513             }
514             if (tmp[0] != '\0') {
515                 fprintf(stderr, "%s: invalid characters in umask setting provided\n", p);
516                 err++;
517             }
518             break;
519         default :
520             err++;
521         }
522     }
523     if ( err || optind != ac ) {
524         fprintf( stderr,
525                  "Usage:\t%s [ -dpDTIt ] [ -n nbpname ] [ -f defvols ] \
526                  [ -P pidfile ] [ -s sysvols ] \n", p );
527         fprintf( stderr,
528                  "\t[ -u ] [ -c maxconn ] [ -g guest ] \
529                  [ -S port ] [ -L loginmesg ] [ -F configfile ] [ -U uamlist ]\n" );
530         return 0;
531     }
532
533 #ifdef ultrix
534     openlog( p, LOG_PID ); /* ultrix only */
535 #else /* ultrix */
536     set_processname(p);
537     syslog_setup(log_debug, logtype_default, logoption_ndelay|logoption_pid, logfacility_daemon);
538 #endif /* ultrix */
539
540     return 1;
541 }