2
* $Id: afp_config.c,v 1.21 2002/09/12 17:33:03 srittau Exp $
4
* Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5
* All Rights Reserved. See COPYRIGHT.
10
#endif /* HAVE_CONFIG_H */
20
#else /* STDC_HEADERS */
24
#endif /* HAVE_STRCHR */
25
char *strchr (), *strrchr ();
27
#define memcpy(d,s,n) bcopy ((s), (d), (n))
28
#define memmove(d,s,n) bcopy ((s), (d), (n))
29
#endif /* ! HAVE_MEMCPY */
30
#endif /* STDC_HEADERS */
34
#endif /* HAVE_UNISTD_H */
36
#include <atalk/logger.h>
38
#include <sys/socket.h>
39
#include <netinet/in.h>
40
#include <arpa/inet.h>
42
#include <atalk/dsi.h>
43
#include <atalk/atp.h>
44
#include <atalk/asp.h>
45
#include <atalk/nbp.h>
46
#include <atalk/afp.h>
47
#include <atalk/compat.h>
48
#include <atalk/server_child.h>
51
static char srvloc_url[512];
52
#endif /* USE_SRVLOC */
55
#include "afp_config.h"
61
/* get rid of unneeded configurations. i use reference counts to deal
62
* w/ multiple configs sharing the same afp_options. oh, to dream of
63
* garbage collection ... */
64
void configfree(AFPConfig *configs, const AFPConfig *config)
68
for (p = configs; p; p = q) {
73
/* do a little reference counting */
74
if (--(*p->optcount) < 1) {
75
afp_options_free(&p->obj.options, p->defoptions);
79
switch (p->obj.proto) {
85
atp_close(((ASP) p->obj.handle)->asp_atp);
88
#endif /* no afp/asp */
99
static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
100
*(SLPError*)cookie = errcode;
102
#endif /* USE_SRVLOC */
105
static void dsi_cleanup(const AFPConfig *config)
108
SLPError callbackerr;
111
/* Do nothing if we didn't register. */
112
if (srvloc_url[0] == '\0')
115
err = SLPOpen("en", SLP_FALSE, &hslp);
117
LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
118
goto srvloc_dereg_err;
126
LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
127
goto srvloc_dereg_err;
130
if (callbackerr != SLP_OK) {
131
LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", srvloc_url, callbackerr);
132
goto srvloc_dereg_err;
138
#endif /* USE_SRVLOC */
141
static void asp_cleanup(const AFPConfig *config)
143
nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
144
&config->obj.options.ddpaddr);
147
/* these two are almost identical. it should be possible to collapse them
148
* into one with minimal junk. */
149
static int asp_start(AFPConfig *config, AFPConfig *configs,
150
server_child *server_children)
154
if (!(asp = asp_getsession(config->obj.handle, server_children,
155
config->obj.options.tickleval))) {
156
LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
161
configfree(configs, config); /* free a bunch of stuff */
162
afp_over_asp(&config->obj);
168
#endif /* no afp/asp */
170
static int dsi_start(AFPConfig *config, AFPConfig *configs,
171
server_child *server_children)
175
if (!(dsi = dsi_getsession(config->obj.handle, server_children,
176
config->obj.options.tickleval))) {
177
LOG(log_error, logtype_afpd, "main: dsi_getsession: %s", strerror(errno) );
183
configfree(configs, config);
184
afp_over_dsi(&config->obj); /* start a session */
192
static AFPConfig *ASPConfigInit(const struct afp_options *options,
193
unsigned char *refcount)
198
char *Obj, *Type = "AFPServer", *Zone = "*";
200
if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
203
if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
204
LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
209
if ((asp = asp_init( atp )) == NULL) {
210
LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
216
/* register asp server */
217
Obj = (char *) options->hostname;
218
if (nbp_name(options->server, &Obj, &Type, &Zone )) {
219
LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
220
goto serv_free_return;
223
/* dup Obj, Type and Zone as they get assigned to a single internal
224
* buffer by nbp_name */
225
if ((config->obj.Obj = strdup(Obj)) == NULL)
226
goto serv_free_return;
228
if ((config->obj.Type = strdup(Type)) == NULL) {
229
free(config->obj.Obj);
230
goto serv_free_return;
233
if ((config->obj.Zone = strdup(Zone)) == NULL) {
234
free(config->obj.Obj);
235
free(config->obj.Type);
236
goto serv_free_return;
239
/* make sure we're not registered */
240
nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
241
if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
242
LOG(log_error, logtype_afpd, "Can't register %s:%s@%s", Obj, Type, Zone );
243
free(config->obj.Obj);
244
free(config->obj.Type);
245
free(config->obj.Zone);
246
goto serv_free_return;
249
LOG(log_info, logtype_afpd, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
250
ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
251
atp_sockaddr( atp )->sat_addr.s_node,
252
atp_sockaddr( atp )->sat_port, VERSION );
254
config->fd = atp_fileno(atp);
255
config->obj.handle = asp;
256
config->obj.config = config;
257
config->obj.proto = AFPPROTO_ASP;
259
memcpy(&config->obj.options, options, sizeof(struct afp_options));
260
config->optcount = refcount;
263
config->server_start = asp_start;
264
config->server_cleanup = asp_cleanup;
273
#endif /* no afp/asp */
276
static AFPConfig *DSIConfigInit(const struct afp_options *options,
277
unsigned char *refcount,
278
const dsi_proto protocol)
285
SLPError callbackerr;
287
struct servent *afpovertcp;
289
const char *srvloc_hostname;
290
#endif /* USE_SRVLOC */
292
if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
293
LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
297
if ((dsi = dsi_init(protocol, "afpd", options->hostname,
298
options->ipaddr, options->port,
299
options->flags & OPTION_PROXY,
300
options->server_quantum)) == NULL) {
301
LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
306
if (options->flags & OPTION_PROXY) {
307
LOG(log_info, logtype_afpd, "ASIP proxy initialized for %s:%d (%s)",
308
inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
311
LOG(log_info, logtype_afpd, "ASIP started on %s:%d(%d) (%s)",
312
inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
313
dsi->serversock, VERSION);
317
srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
318
if (!(options->flags & OPTION_NOSLP)) {
319
err = SLPOpen("en", SLP_FALSE, &hslp);
321
LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
325
/* XXX We don't want to tack on the port number if we don't have to.
327
* Well, this seems to break MacOS < 10. If the user _really_ wants to
328
* use a non-default port, they can, but be aware, this server might
329
* not show up int the Network Browser.
331
afpovertcp = getservbyname("afpovertcp", "tcp");
332
srvloc_hostname = (options->server ? options->server : options->hostname);
333
if (afpovertcp != NULL) {
334
afp_port = afpovertcp->s_port;
336
if (strlen(srvloc_hostname) > (sizeof(srvloc_url) - strlen(inet_ntoa(dsi->server.sin_addr)) - 21)) {
337
LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
338
srvloc_url[0] = '\0';
341
if (dsi->server.sin_port == afp_port) {
342
sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), srvloc_hostname);
345
sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), srvloc_hostname);
350
SLP_LIFETIME_MAXIMUM,
357
LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
358
srvloc_url[0] = '\0';
362
if (callbackerr != SLP_OK) {
363
LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
364
srvloc_url[0] = '\0';
368
LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
373
#endif /* USE_SRVLOC */
376
config->fd = dsi->serversock;
377
config->obj.handle = dsi;
378
config->obj.config = config;
379
config->obj.proto = AFPPROTO_DSI;
381
memcpy(&config->obj.options, options, sizeof(struct afp_options));
382
/* get rid of any appletalk info. we use the fact that the DSI
383
* stuff is done after the ASP stuff. */
384
p = config->obj.options.server;
385
if (p && (q = strchr(p, ':')))
388
config->optcount = refcount;
391
config->server_start = dsi_start;
393
config->server_cleanup = dsi_cleanup;
394
#endif /* USE_SRVLOC */
398
/* allocate server configurations. this should really store the last
399
* entry in config->last or something like that. that would make
400
* supporting multiple dsi transports easier. */
401
static AFPConfig *AFPConfigInit(const struct afp_options *options,
402
const struct afp_options *defoptions)
404
AFPConfig *config = NULL, *next = NULL;
405
unsigned char *refcount;
407
if ((refcount = (unsigned char *)
408
calloc(1, sizeof(unsigned char))) == NULL) {
409
LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
414
/* handle asp transports */
415
if ((options->transports & AFPTRANS_DDP) &&
416
(config = ASPConfigInit(options, refcount)))
417
config->defoptions = defoptions;
420
/* handle dsi transports and dsi proxies. we only proxy
421
* for DSI connections. */
423
/* this should have something like the following:
424
* for (i=mindsi; i < maxdsi; i++)
425
* if (options->transports & (1 << i) &&
426
* (next = DSIConfigInit(options, refcount, i)))
427
* next->defoptions = defoptions;
429
if ((options->transports & AFPTRANS_TCP) &&
430
(((options->flags & OPTION_PROXY) == 0) ||
431
((options->flags & OPTION_PROXY) && config))
432
&& (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
433
next->defoptions = defoptions;
435
/* load in all the authentication modules. we can load the same
436
things multiple times if necessary. however, loading different
437
things with the same names will cause complaints. by not loading
438
in any uams with proxies, we prevent ddp connections from succeeding.
440
auth_load(options->uampath, options->uamlist);
442
/* this should be able to accept multiple dsi transports. i think
443
* the only thing that gets affected is the net addresses. */
444
status_init(config, next, options);
446
/* attach dsi config to tail of asp config */
455
/* fill in the appropriate bits for each interface */
456
AFPConfig *configinit(struct afp_options *cmdline)
459
char buf[LINESIZE + 1], *p, have_option = 0;
460
struct afp_options options;
461
AFPConfig *config, *first = NULL;
463
/* if config file doesn't exist, load defaults */
464
if ((fp = fopen(cmdline->configfile, "r")) == NULL)
466
LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
467
cmdline->configfile);
468
return AFPConfigInit(cmdline, cmdline);
471
LOG(log_debug, logtype_afpd, "Loading ConfigFile");
473
/* scan in the configuration file */
475
if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
478
/* a little pre-processing to get rid of spaces and end-of-lines */
480
while (p && isspace(*p))
482
if (!p || (*p == '\0'))
487
memcpy(&options, cmdline, sizeof(options));
488
if (!afp_options_parseline(p, &options))
491
/* this should really get a head and a tail to simplify things. */
493
if ((first = AFPConfigInit(&options, cmdline)))
494
config = first->next ? first->next : first;
495
} else if ((config->next = AFPConfigInit(&options, cmdline))) {
496
config = config->next->next ? config->next->next : config->next;
500
LOG(log_debug, logtype_afpd, "Finished parsing Config File");
504
return AFPConfigInit(cmdline, cmdline);