1/*
2 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
3 * Copyright (c) 1990,1993 Regents of The University of Michigan.
4 * All Rights Reserved.  See COPYRIGHT.
5 *
6 * modified from main.c. this handles afp options.
7 */
8
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif /* HAVE_CONFIG_H */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <ctype.h>
17#include <unistd.h>
18#include <sys/param.h>
19#include <sys/socket.h>
20#include <atalk/logger.h>
21
22#include <netinet/in.h>
23#include <arpa/inet.h>
24
25#ifdef HAVE_NETDB_H
26#include <netdb.h>
27#endif /* HAVE_NETDB_H */
28
29#ifdef ADMIN_GRP
30#include <grp.h>
31#include <sys/types.h>
32#endif /* ADMIN_GRP */
33
34#include <atalk/paths.h>
35#include <atalk/util.h>
36#include <atalk/compat.h>
37#include <atalk/globals.h>
38#include <atalk/fce_api.h>
39
40#include "status.h"
41#include "auth.h"
42#include "dircache.h"
43
44#ifndef MIN
45#define MIN(a, b)  ((a) < (b) ? (a) : (b))
46#endif /* MIN */
47
48/* FIXME CNID */
49const char *Cnid_srv = "localhost";
50const char *Cnid_port = "4700";
51
52#define OPTIONS "dn:f:s:uc:g:P:ptDS:TL:F:U:hIvVm:"
53#define LENGTH 512
54
55/* return an option. this uses an internal array, so it's necessary
56 * to duplicate it if you want to hold it for long. this is probably
57 * non-optimal. */
58static char *getoption(char *buf, const char *option)
59{
60    static char string[LENGTH + 1];
61    char *end;
62    int len;
63
64    if (option && (buf = strstr(buf, option)))
65        buf = strpbrk(buf, " \t");
66
67    while (buf && isspace(*buf))
68        buf++;
69
70    if (!buf)
71        return NULL;
72
73    /* search for any quoted stuff */
74    if (*buf == '"' && (end = strchr(buf + 1, '"'))) {
75        buf++;
76        len = MIN(end - buf, LENGTH);
77    } else if ((end = strpbrk(buf, " \t\n"))) /* option or eoln */
78        len = MIN(end - buf, LENGTH);
79    else
80        len = MIN(strlen(buf), LENGTH);
81
82    strncpy(string, buf, len);
83    string[len] = '\0';
84    return string;
85}
86
87/* get rid of any allocated afp_option buffers. */
88void afp_options_free(struct afp_options *opt,
89                      const struct afp_options *save)
90{
91    if (opt->defaultvol.name && (opt->defaultvol.name != save->defaultvol.name))
92        free(opt->defaultvol.name);
93    if (opt->defaultvol.full_name && (opt->defaultvol.full_name != save->defaultvol.full_name))
94        free(opt->defaultvol.full_name);
95
96    if (opt->systemvol.name && (opt->systemvol.name != save->systemvol.name))
97        free(opt->systemvol.name);
98    if (opt->systemvol.full_name && (opt->systemvol.full_name != save->systemvol.full_name))
99        free(opt->systemvol.full_name);
100
101    if (opt->uservol.name && (opt->uservol.name != save->uservol.name))
102        free(opt->uservol.name);
103    if (opt->uservol.full_name && (opt->uservol.full_name != save->uservol.full_name))
104        free(opt->uservol.full_name);
105
106    if (opt->loginmesg && (opt->loginmesg != save->loginmesg))
107        free(opt->loginmesg);
108    if (opt->guest && (opt->guest != save->guest))
109        free(opt->guest);
110    if (opt->server && (opt->server != save->server))
111        free(opt->server);
112    if (opt->ipaddr && (opt->ipaddr != save->ipaddr))
113        free(opt->ipaddr);
114    if (opt->port && (opt->port != save->port))
115        free(opt->port);
116    if (opt->fqdn && (opt->fqdn != save->fqdn))
117        free(opt->fqdn);
118    if (opt->uampath && (opt->uampath != save->uampath))
119        free(opt->uampath);
120    if (opt->uamlist && (opt->uamlist != save->uamlist))
121        free(opt->uamlist);
122    if (opt->passwdfile && (opt->passwdfile != save->passwdfile))
123        free(opt->passwdfile);
124    if (opt->signatureopt && (opt->signatureopt != save->signatureopt))
125	free(opt->signatureopt);
126    if (opt->k5service && (opt->k5service != save->k5service))
127	free(opt->k5service);
128    if (opt->k5realm && (opt->k5realm != save->k5realm))
129	free(opt->k5realm);
130    if (opt->k5keytab && (opt->k5keytab != save->k5keytab))
131	free(opt->k5keytab);
132    if (opt->unixcodepage && (opt->unixcodepage != save->unixcodepage))
133	free(opt->unixcodepage);
134    if (opt->maccodepage && (opt->maccodepage != save->maccodepage))
135	free(opt->maccodepage);
136
137    if (opt->ntdomain && (opt->ntdomain != save->ntdomain))
138	free(opt->ntdomain);
139    if (opt->ntseparator && (opt->ntseparator != save->ntseparator))
140	free(opt->ntseparator);
141    if (opt->logconfig && (opt->logconfig != save->logconfig))
142	free(opt->logconfig);
143	if (opt->mimicmodel && (opt->mimicmodel != save->mimicmodel))
144	free(opt->mimicmodel);
145	if (opt->adminauthuser && (opt->adminauthuser != save->adminauthuser))
146	free(opt->adminauthuser);
147}
148
149/* initialize options */
150void afp_options_init(struct afp_options *options)
151{
152    memset(options, 0, sizeof(struct afp_options));
153    options->connections = 20;
154    options->pidfile = _PATH_AFPDLOCK;
155    options->defaultvol.name = _PATH_AFPDDEFVOL;
156    options->systemvol.name = _PATH_AFPDSYSVOL;
157    options->configfile = _PATH_AFPDCONF;
158    options->sigconffile = _PATH_AFPDSIGCONF;
159    options->uuidconf = _PATH_AFPDUUIDCONF;
160    options->uampath = _PATH_AFPDUAMPATH;
161    options->uamlist = "uams_dhx.so,uams_dhx2.so";
162    options->guest = "nobody";
163    options->loginmesg = "";
164    options->transports = AFPTRANS_TCP; /*  TCP only */
165    options->passwdfile = _PATH_AFPDPWFILE;
166    options->tickleval = 30;
167    options->timeout = 4;       /* 4 tickles = 2 minutes */
168    options->sleep = 10 * 60 * 2; /* 10 h in 30 seconds tick */
169    options->disconnected = 10 * 60 * 2; /* 10 h in 30 seconds tick */
170    options->server_notif = 1;
171    options->authprintdir = NULL;
172    options->signatureopt = "auto";
173    options->umask = 0;
174#ifdef ADMIN_GRP
175    options->admingid = 0;
176#endif /* ADMIN_GRP */
177    options->k5service = NULL;
178    options->k5realm = NULL;
179    options->k5keytab = NULL;
180    options->unixcharset = CH_UNIX;
181    options->unixcodepage = "LOCALE";
182    options->maccharset = CH_MAC;
183    options->maccodepage = "MAC_ROMAN";
184    options->volnamelen = 80; /* spec: 255, 10.1: 73, 10.4/10.5: 80 */
185    options->ntdomain = NULL;
186    options->ntseparator = NULL;
187#ifdef USE_SRVLOC
188    /* don't advertize slp by default */
189    options->flags |= OPTION_NOSLP;
190#endif
191    options->dircachesize = DEFAULT_MAX_DIRCACHE_SIZE;
192    options->flags |= OPTION_ACL2MACCESS;
193    options->flags |= OPTION_UUID;
194    options->tcp_sndbuf = 0;    /* 0 means don't change OS default */
195    options->tcp_rcvbuf = 0;    /* 0 means don't change OS default */
196    options->dsireadbuf = 12;
197	options->mimicmodel = NULL;
198    options->fce_fmodwait = 60; /* put fmod events 60 seconds on hold */
199    options->adminauthuser = NULL;
200}
201
202/* parse an afpd.conf line. i'm doing it this way because it's
203 * easy. it is, however, massively hokey. sample afpd.conf:
204 * server:AFPServer@zone -loginmesg "blah blah blah" -nodsi
205 * "private machine"@zone2 -noguest -port 11012
206 * server2 -nocleartxt -nodsi
207 *
208 * NOTE: this ignores unknown options
209 */
210int afp_options_parseline(char *buf, struct afp_options *options)
211{
212    char *c, *opt;
213
214    /* handle server */
215    if (*buf != '-' && (c = getoption(buf, NULL)) && (opt = strdup(c)))
216        options->server = opt;
217
218    /* parse toggles */
219    if (strstr(buf, " -nodebug"))
220        options->flags &= ~OPTION_DEBUG;
221#ifdef USE_SRVLOC
222    if (strstr(buf, " -slp"))
223        options->flags &= ~OPTION_NOSLP;
224#endif
225#ifdef USE_ZEROCONF
226    if (strstr(buf, " -nozeroconf"))
227        options->flags |= OPTION_NOZEROCONF;
228#endif
229    if (strstr(buf, " -nouservolfirst"))
230        options->flags &= ~OPTION_USERVOLFIRST;
231    if (strstr(buf, " -uservolfirst"))
232        options->flags |= OPTION_USERVOLFIRST;
233    if (strstr(buf, " -nouservol"))
234        options->flags |= OPTION_NOUSERVOL;
235    if (strstr(buf, " -uservol"))
236        options->flags &= ~OPTION_NOUSERVOL;
237    if (strstr(buf, " -proxy"))
238        options->flags |= OPTION_PROXY;
239    if (strstr(buf, " -noicon"))
240        options->flags &= ~OPTION_CUSTOMICON;
241    if (strstr(buf, " -icon"))
242        options->flags |= OPTION_CUSTOMICON;
243    if (strstr(buf, " -advertise_ssh"))
244        options->flags |= OPTION_ANNOUNCESSH;
245    if (strstr(buf, " -noacl2maccess"))
246        options->flags &= ~OPTION_ACL2MACCESS;
247    if (strstr(buf, " -keepsessions")) {
248        default_options.flags |= OPTION_KEEPSESSIONS;
249        options->flags |= OPTION_KEEPSESSIONS;
250    }
251
252    /* passwd bits */
253    if (strstr(buf, " -nosavepassword"))
254        options->passwdbits |= PASSWD_NOSAVE;
255    if (strstr(buf, " -savepassword"))
256        options->passwdbits &= ~PASSWD_NOSAVE;
257    if (strstr(buf, " -nosetpassword"))
258        options->passwdbits &= ~PASSWD_SET;
259    if (strstr(buf, " -setpassword"))
260        options->passwdbits |= PASSWD_SET;
261
262    /* transports */
263    if (strstr(buf, " -transall"))
264        options->transports = AFPTRANS_ALL;
265    if (strstr(buf, " -notransall"))
266        options->transports = AFPTRANS_NONE;
267    if (strstr(buf, " -tcp"))
268        options->transports |= AFPTRANS_TCP;
269    if (strstr(buf, " -notcp"))
270        options->transports &= ~AFPTRANS_TCP;
271    if (strstr(buf, " -ddp"))
272        options->transports |= AFPTRANS_DDP;
273    if (strstr(buf, " -noddp"))
274        options->transports &= ~AFPTRANS_DDP;
275    if (strstr(buf, "-client_polling"))
276        options->server_notif = 0;
277
278    /* figure out options w/ values. currently, this will ignore the setting
279     * if memory is lacking. */
280
281    if ((c = getoption(buf, "-hostname"))) {
282        int len = strlen (c);
283        if (len <= MAXHOSTNAMELEN) {
284            memcpy(options->hostname, c, len);
285            options->hostname[len] = 0;
286        }
287        else
288            LOG(log_info, logtype_afpd, "WARNING: hostname %s is too long (%d)",c,len);
289    }
290
291    if ((c = getoption(buf, "-defaultvol")) && (opt = strdup(c)))
292        options->defaultvol.name = opt;
293    if ((c = getoption(buf, "-systemvol")) && (opt = strdup(c)))
294        options->systemvol.name = opt;
295    if ((c = getoption(buf, "-loginmesg")) && (opt = strdup(c))) {
296        int i = 0, j = 0;
297        while (c[i]) {
298            if (c[i] != '\\') {
299                opt[j++] = c[i];
300            } else {
301                i++;
302                if (c[i] == 'n')
303                    opt[j++] = '\n';
304            }
305            i++;
306        }
307        opt[j] = 0;
308        options->loginmesg = opt;
309
310    }
311    if ((c = getoption(buf, "-guestname")) && (opt = strdup(c)))
312        options->guest = opt;
313    if ((c = getoption(buf, "-passwdfile")) && (opt = strdup(c)))
314        options->passwdfile = opt;
315    if ((c = getoption(buf, "-passwdminlen")))
316        options->passwdminlen = MIN(1, atoi(c));
317    if ((c = getoption(buf, "-loginmaxfail")))
318        options->loginmaxfail = atoi(c);
319    if ((c = getoption(buf, "-tickleval"))) {
320        options->tickleval = atoi(c);
321        if (options->tickleval <= 0) {
322            options->tickleval = 30;
323        }
324    }
325    if ((c = getoption(buf, "-timeout"))) {
326        options->timeout = atoi(c);
327        if (options->timeout <= 0) {
328            options->timeout = 4;
329        }
330    }
331
332    if ((c = getoption(buf, "-sleep"))) {
333        options->disconnected = options->sleep = atoi(c) * 120;
334        if (options->sleep <= 4) {
335            options->disconnected = options->sleep = 4;
336        }
337    }
338
339    if ((c = getoption(buf, "-dsireadbuf"))) {
340        options->dsireadbuf = atoi(c);
341        if (options->dsireadbuf < 6)
342            options->dsireadbuf = 6;
343    }
344
345    if ((c = getoption(buf, "-server_quantum")))
346        options->server_quantum = strtoul(c, NULL, 0);
347
348    if ((c = getoption(buf, "-volnamelen"))) {
349        options->volnamelen = atoi(c);
350        if (options->volnamelen < 8) {
351            options->volnamelen = 8; /* max mangled volname "???#FFFF" */
352        }
353        if (options->volnamelen > 255) {
354	    options->volnamelen = 255; /* AFP3 spec */
355        }
356    }
357
358    /* -[no]setuplog <logtype> <loglevel> [<filename>]*/
359    c = buf;
360    /* Now THIS is hokey! Multiple occurrences are not supported by our current code, */
361    /* so I have to loop myself. */
362    while (NULL != (c = strstr(c, "-setuplog"))) {
363        char *optstr;
364        if ((optstr = getoption(c, "-setuplog"))) {
365            /* hokey2: options->logconfig must be converted to store an array of logstrings */
366            if (options->logconfig)
367                free(options->logconfig);
368            options->logconfig = strdup(optstr);
369            setuplog(optstr);
370            c += sizeof("-setuplog");
371        }
372    }
373
374    if ((c = getoption(buf, "-unsetuplog")))
375      unsetuplog(c);
376
377#ifdef ADMIN_GRP
378    if ((c = getoption(buf, "-admingroup"))) {
379        struct group *gr = getgrnam(c);
380        if (gr != NULL) {
381            options->admingid = gr->gr_gid;
382        }
383    }
384#endif /* ADMIN_GRP */
385
386    if ((c = getoption(buf, "-k5service")) && (opt = strdup(c)))
387	options->k5service = opt;
388    if ((c = getoption(buf, "-k5realm")) && (opt = strdup(c)))
389	options->k5realm = opt;
390    if ((c = getoption(buf, "-k5keytab"))) {
391	if ( NULL == (options->k5keytab = (char *) malloc(sizeof(char)*(strlen(c)+14)) )) {
392		LOG(log_error, logtype_afpd, "malloc failed");
393		exit(-1);
394	}
395	snprintf(options->k5keytab, strlen(c)+14, "KRB5_KTNAME=%s", c);
396	putenv(options->k5keytab);
397	/* setenv( "KRB5_KTNAME", c, 1 ); */
398    }
399    if ((c = getoption(buf, "-authprintdir")) && (opt = strdup(c)))
400        options->authprintdir = opt;
401    if ((c = getoption(buf, "-uampath")) && (opt = strdup(c)))
402        options->uampath = opt;
403    if ((c = getoption(buf, "-uamlist")) && (opt = strdup(c)))
404        options->uamlist = opt;
405
406    if ((c = getoption(buf, "-ipaddr"))) {
407#if 0
408        struct in_addr inaddr;
409        if (inet_aton(c, &inaddr) && (opt = strdup(c))) {
410            if (!gethostbyaddr((const char *) &inaddr, sizeof(inaddr), AF_INET))
411                LOG(log_info, logtype_afpd, "WARNING: can't find %s", opt);
412            options->ipaddr = opt;
413        }
414        else {
415            LOG(log_error, logtype_afpd, "Error parsing -ipaddr, is %s in numbers-and-dots notation?", c);
416        }
417#endif
418        options->ipaddr = strdup(c);
419    }
420
421    /* FIXME CNID Cnid_srv is a server attribute */
422    if ((c = getoption(buf, "-cnidserver"))) {
423        char *p = strrchr(c, ':');
424        if (p)
425            *p = 0;
426        Cnid_srv = strdup(c);
427        if (p)
428            Cnid_port = strdup(p + 1);
429        LOG(log_debug, logtype_afpd, "CNID Server: %s:%s", Cnid_srv, Cnid_port);
430    }
431
432    if ((c = getoption(buf, "-port")))
433        options->port = strdup(c);
434#ifndef NO_DDP
435    if ((c = getoption(buf, "-ddpaddr")))
436        atalk_aton(c, &options->ddpaddr);
437#endif
438    if ((c = getoption(buf, "-signature")) && (opt = strdup(c)))
439        options->signatureopt = opt;
440
441    /* do a little checking for the domain name. */
442    if ((c = getoption(buf, "-fqdn"))) {
443        char *p = strchr(c, ':');
444        if (p)
445            *p = '\0';
446        if (gethostbyname(c)) {
447            if (p)
448                *p = ':';
449            if ((opt = strdup(c)))
450                options->fqdn = opt;
451        }
452	else {
453            LOG(log_error, logtype_afpd, "error parsing -fqdn, gethostbyname failed for: %s", c);
454	}
455    }
456
457    if ((c = getoption(buf, "-unixcodepage"))) {
458    	if ((charset_t)-1  == ( options->unixcharset = add_charset(c)) ) {
459            options->unixcharset = CH_UNIX;
460            LOG(log_warning, logtype_afpd, "setting Unix codepage to '%s' failed", c);
461    	}
462	else {
463            if ((opt = strdup(c)))
464                options->unixcodepage = opt;
465	}
466    }
467
468    if ((c = getoption(buf, "-maccodepage"))) {
469    	if ((charset_t)-1 == ( options->maccharset = add_charset(c)) ) {
470            options->maccharset = CH_MAC;
471            LOG(log_warning, logtype_afpd, "setting Mac codepage to '%s' failed", c);
472    	}
473	else {
474            if ((opt = strdup(c)))
475                options->maccodepage = opt;
476	}
477    }
478
479    if ((c = strstr(buf, "-closevol"))) {
480        options->closevol= 1;
481    }
482
483    if ((c = getoption(buf, "-ntdomain")) && (opt = strdup(c)))
484       options->ntdomain = opt;
485
486    if ((c = getoption(buf, "-ntseparator")) && (opt = strdup(c)))
487       options->ntseparator = opt;
488
489    if ((c = getoption(buf, "-dircachesize")))
490        options->dircachesize = atoi(c);
491
492    if ((c = getoption(buf, "-tcpsndbuf")))
493        options->tcp_sndbuf = atoi(c);
494
495    if ((c = getoption(buf, "-tcprcvbuf")))
496        options->tcp_rcvbuf = atoi(c);
497
498	if ((c = getoption(buf, "-fcelistener"))) {
499		LOG(log_note, logtype_afpd, "Adding fce listener \"%s\"", c);
500		fce_add_udp_socket(c);
501	}
502	if ((c = getoption(buf, "-fcecoalesce"))) {
503		LOG(log_note, logtype_afpd, "Fce coalesce: %s", c);
504		fce_set_coalesce(c);
505	}
506	if ((c = getoption(buf, "-fceevents"))) {
507		LOG(log_note, logtype_afpd, "Fce events: %s", c);
508		fce_set_events(c);
509	}
510
511    if ((c = getoption(buf, "-fceholdfmod")))
512        options->fce_fmodwait = atoi(c);
513
514    if ((c = getoption(buf, "-mimicmodel")) && (opt = strdup(c)))
515       options->mimicmodel = opt;
516
517    if ((c = getoption(buf, "-adminauthuser")) && (opt = strdup(c)))
518       options->adminauthuser = opt;
519
520    return 1;
521}
522
523/*
524 * Show version information about afpd.
525 * Used by "afp -v".
526 */
527static void show_version( void )
528{
529	int num, i;
530
531	printf( "afpd %s - Apple Filing Protocol (AFP) daemon of Netatalk\n\n", VERSION );
532
533	puts( "This program is free software; you can redistribute it and/or modify it under" );
534	puts( "the terms of the GNU General Public License as published by the Free Software" );
535	puts( "Foundation; either version 2 of the License, or (at your option) any later" );
536	puts( "version. Please see the file COPYING for further information and details.\n" );
537
538	puts( "afpd has been compiled with support for these features:\n" );
539
540	num = sizeof( afp_versions ) / sizeof( afp_versions[ 0 ] );
541	printf( "          AFP versions:\t" );
542	for ( i = 0; i < num; i++ ) {
543		printf( "%d.%d ", afp_versions[ i ].av_number/10, afp_versions[ i ].av_number%10);
544	}
545	puts( "" );
546
547	printf( "DDP(AppleTalk) Support:\t" );
548#ifdef NO_DDP
549	puts( "No" );
550#else
551	puts( "Yes" );
552#endif
553
554	printf( "         CNID backends:\t" );
555#ifdef CNID_BACKEND_CDB
556	printf( "cdb ");
557#endif
558#ifdef CNID_BACKEND_DB3
559	printf( "db3 " );
560#endif
561#ifdef CNID_BACKEND_DBD
562#ifdef CNID_BACKEND_DBD_TXN
563	printf( "dbd-txn " );
564#else
565	printf( "dbd " );
566#endif
567#endif
568#ifdef CNID_BACKEND_HASH
569	printf( "hash " );
570#endif
571#ifdef CNID_BACKEND_LAST
572	printf( "last " );
573#endif
574#ifdef CNID_BACKEND_MTAB
575	printf( "mtab " );
576#endif
577#ifdef CNID_BACKEND_TDB
578	printf( "tdb " );
579#endif
580	puts( "" );
581}
582
583/*
584 * Show extended version information about afpd and Netatalk.
585 * Used by "afp -V".
586 */
587static void show_version_extended(void )
588{
589	show_version( );
590
591	printf( "           SLP support:\t" );
592#ifdef USE_SRVLOC
593	puts( "Yes" );
594#else
595	puts( "No" );
596#endif
597
598	printf( "      Zeroconf support:\t" );
599#if defined (HAVE_MDNS)
600	puts( "mDNSResponder" );
601#elif defined (HAVE_AVAHI)
602	puts( "Avahi" );
603#else
604	puts( "No" );
605#endif
606
607	printf( "  TCP wrappers support:\t" );
608#ifdef TCPWRAP
609	puts( "Yes" );
610#else
611	puts( "No" );
612#endif
613
614	printf( "         Quota support:\t" );
615#ifndef NO_QUOTA_SUPPORT
616	puts( "Yes" );
617#else
618	puts( "No" );
619#endif
620
621	printf( "   Admin group support:\t" );
622#ifdef ADMIN_GRP
623	puts( "Yes" );
624#else
625	puts( "No" );
626#endif
627
628	printf( "    Valid shell checks:\t" );
629#ifndef DISABLE_SHELLCHECK
630	puts( "Yes" );
631#else
632	puts( "No" );
633#endif
634
635	printf( "      cracklib support:\t" );
636#ifdef USE_CRACKLIB
637	puts( "Yes" );
638#else
639	puts( "No" );
640#endif
641
642	printf( "        Dropbox kludge:\t" );
643#ifdef DROPKLUDGE
644	puts( "Yes" );
645#else
646	puts( "No" );
647#endif
648
649	printf( "  Force volume uid/gid:\t" );
650#ifdef FORCE_UIDGID
651	puts( "Yes" );
652#else
653	puts( "No" );
654#endif
655
656	printf( "            EA support:\t" );
657	puts( EA_MODULES );
658
659	printf( "           ACL support:\t" );
660#ifdef HAVE_ACLS
661	puts( "Yes" );
662#else
663	puts( "No" );
664#endif
665
666	printf( "          LDAP support:\t" );
667#ifdef HAVE_LDAP
668	puts( "Yes" );
669#else
670	puts( "No" );
671#endif
672}
673
674/*
675 * Display compiled-in default paths
676 */
677static void show_paths( void )
678{
679	printf( "             afpd.conf:\t%s\n", _PATH_AFPDCONF );
680	printf( "   AppleVolumes.system:\t%s\n", _PATH_AFPDSYSVOL );
681	printf( "  AppleVolumes.default:\t%s\n", _PATH_AFPDDEFVOL );
682	printf( "    afp_signature.conf:\t%s\n", _PATH_AFPDSIGCONF );
683	printf( "      afp_voluuid.conf:\t%s\n", _PATH_AFPDUUIDCONF );
684#ifdef HAVE_LDAP
685	printf( "         afp_ldap.conf:\t%s\n", _PATH_ACL_LDAPCONF );
686#else
687	printf( "         afp_ldap.conf:\tnot supported\n");
688#endif
689	printf( "       UAM search path:\t%s\n", _PATH_AFPDUAMPATH );
690	printf( "  Server messages path:\t%s\n", SERVERTEXT);
691	printf( "              lockfile:\t%s\n", _PATH_AFPDLOCK);
692}
693
694/*
695 * Display usage information about afpd.
696 */
697static void show_usage( char *name )
698{
699	fprintf( stderr, "Usage:\t%s [-duptDTI] [-f defaultvolumes] [-s systemvolumes] [-n nbpname]\n", name );
700	fprintf( stderr, "\t     [-c maxconnections] [-g guest] [-P pidfile] [-S port] [-L message]\n" );
701	fprintf( stderr, "\t     [-F configfile] [-U uams] [-m umask]\n" );
702	fprintf( stderr, "\t%s -h|-v|-V\n", name );
703}
704
705int afp_options_parse(int ac, char **av, struct afp_options *options)
706{
707    extern char *optarg;
708    extern int optind;
709
710    char *p;
711    char *tmp;	/* Used for error checking the result of strtol */
712    int c, err = 0;
713
714    if (gethostname(options->hostname, sizeof(options->hostname )) < 0 ) {
715        perror( "gethostname" );
716        return 0;
717    }
718    if (NULL != ( p = strchr(options->hostname, '.' )) ) {
719        *p = '\0';
720    }
721
722#ifdef ultrix
723    if (NULL == ( p = strrchr( av[ 0 ], '/' )) ) {
724        p = av[ 0 ];
725    } else {
726        p++;
727    }
728    openlog( p, LOG_PID ); /* ultrix only */
729#endif /* ultrix */
730
731    while (EOF != ( c = getopt( ac, av, OPTIONS )) ) {
732        switch ( c ) {
733        case 'd' :
734            options->flags |= OPTION_DEBUG;
735            break;
736        case 'n' :
737            options->server = optarg;
738            break;
739        case 'f' :
740            options->defaultvol.name = optarg;
741            break;
742        case 's' :
743            options->systemvol.name = optarg;
744            break;
745        case 'u' :
746            options->flags |= OPTION_USERVOLFIRST;
747            break;
748        case 'c' :
749            options->connections = atoi( optarg );
750            break;
751        case 'g' :
752            options->guest = optarg;
753            break;
754
755        case 'P' :
756            options->pidfile = optarg;
757            break;
758
759        case 'p':
760            options->passwdbits |= PASSWD_NOSAVE;
761            break;
762        case 't':
763            options->passwdbits |= PASSWD_SET;
764            break;
765
766        case 'D':
767            options->transports &= ~AFPTRANS_DDP;
768            break;
769        case 'S':
770            options->port = optarg;
771            break;
772        case 'T':
773            options->transports &= ~AFPTRANS_TCP;
774            break;
775        case 'L':
776            options->loginmesg = optarg;
777            break;
778        case 'F':
779            options->configfile = optarg;
780            break;
781        case 'U':
782            options->uamlist = optarg;
783            break;
784        case 'v':	/* version */
785            show_version( ); puts( "" );
786	    show_paths( ); puts( "" );
787            exit( 0 );
788            break;
789        case 'V':	/* extended version */
790            show_version_extended( ); puts( "" );
791	    show_paths( ); puts( "" );
792            exit( 0 );
793            break;
794        case 'h':	/* usage */
795            show_usage("afpd");
796            exit( 0 );
797            break;
798        case 'I':
799            options->flags |= OPTION_CUSTOMICON;
800            break;
801        case 'm':
802            options->umask = strtoul(optarg, &tmp, 8);
803            if ((options->umask > 0777)) {
804                fprintf(stderr, "%s: out of range umask setting provided\n", p);
805                err++;
806            }
807            if (tmp[0] != '\0') {
808                fprintf(stderr, "%s: invalid characters in umask setting provided\n", p);
809                err++;
810            }
811            break;
812        default :
813            err++;
814        }
815    }
816    if ( err || optind != ac ) {
817        show_usage( p );
818        exit( 2 );
819    }
820
821    return 1;
822}
823