~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to etc/afpd/afp_config.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: afp_config.c,v 1.21 2002/09/12 17:33:03 srittau Exp $
 
3
 *
 
4
 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
 
5
 * All Rights Reserved.  See COPYRIGHT.
 
6
 */
 
7
 
 
8
#ifdef HAVE_CONFIG_H
 
9
#include "config.h"
 
10
#endif /* HAVE_CONFIG_H */
 
11
 
 
12
#include <stdio.h>
 
13
#include <stdlib.h>
 
14
#include <string.h>
 
15
#include <errno.h>
 
16
 
 
17
/* STDC check */
 
18
#if STDC_HEADERS
 
19
#include <string.h>
 
20
#else /* STDC_HEADERS */
 
21
#ifndef HAVE_STRCHR
 
22
#define strchr index
 
23
#define strrchr index
 
24
#endif /* HAVE_STRCHR */
 
25
char *strchr (), *strrchr ();
 
26
#ifndef HAVE_MEMCPY
 
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 */
 
31
 
 
32
#ifdef HAVE_UNISTD_H
 
33
#include <unistd.h>
 
34
#endif /* HAVE_UNISTD_H */
 
35
#include <ctype.h>
 
36
#include <atalk/logger.h>
 
37
 
 
38
#include <sys/socket.h>
 
39
#include <netinet/in.h>
 
40
#include <arpa/inet.h>
 
41
 
 
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>
 
49
#ifdef USE_SRVLOC
 
50
#include <slp.h>
 
51
static char srvloc_url[512];
 
52
#endif /* USE_SRVLOC */
 
53
 
 
54
#include "globals.h"
 
55
#include "afp_config.h"
 
56
#include "uam_auth.h"
 
57
#include "status.h"
 
58
 
 
59
#define LINESIZE 1024  
 
60
 
 
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)
 
65
{
 
66
    AFPConfig *p, *q;
 
67
 
 
68
    for (p = configs; p; p = q) {
 
69
        q = p->next;
 
70
        if (p == config)
 
71
            continue;
 
72
 
 
73
        /* do a little reference counting */
 
74
        if (--(*p->optcount) < 1) {
 
75
            afp_options_free(&p->obj.options, p->defoptions);
 
76
            free(p->optcount);
 
77
        }
 
78
 
 
79
        switch (p->obj.proto) {
 
80
#ifndef NO_DDP
 
81
        case AFPPROTO_ASP:
 
82
            free(p->obj.Obj);
 
83
            free(p->obj.Type);
 
84
            free(p->obj.Zone);
 
85
            atp_close(((ASP) p->obj.handle)->asp_atp);
 
86
            free(p->obj.handle);
 
87
            break;
 
88
#endif /* no afp/asp */
 
89
        case AFPPROTO_DSI:
 
90
            close(p->fd);
 
91
            free(p->obj.handle);
 
92
            break;
 
93
        }
 
94
        free(p);
 
95
    }
 
96
}
 
97
 
 
98
#ifdef USE_SRVLOC
 
99
static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
 
100
    *(SLPError*)cookie = errcode;
 
101
}
 
102
#endif /* USE_SRVLOC */
 
103
 
 
104
#ifdef USE_SRVLOC
 
105
static void dsi_cleanup(const AFPConfig *config)
 
106
{
 
107
    SLPError err;
 
108
    SLPError callbackerr;
 
109
    SLPHandle hslp;
 
110
 
 
111
    /*  Do nothing if we didn't register.  */
 
112
    if (srvloc_url[0] == '\0')
 
113
        return;
 
114
 
 
115
    err = SLPOpen("en", SLP_FALSE, &hslp);
 
116
    if (err != SLP_OK) {
 
117
        LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
 
118
        goto srvloc_dereg_err;
 
119
    }
 
120
 
 
121
    err = SLPDereg(hslp,
 
122
                   srvloc_url,
 
123
                   SRVLOC_callback,
 
124
                   &callbackerr);
 
125
    if (err != SLP_OK) {
 
126
        LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
 
127
        goto srvloc_dereg_err;
 
128
    }
 
129
 
 
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;
 
133
    }
 
134
 
 
135
srvloc_dereg_err:
 
136
    SLPClose(hslp);
 
137
}
 
138
#endif /* USE_SRVLOC */
 
139
 
 
140
#ifndef NO_DDP
 
141
static void asp_cleanup(const AFPConfig *config)
 
142
{
 
143
    nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
 
144
                &config->obj.options.ddpaddr);
 
145
}
 
146
 
 
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)
 
151
{
 
152
    ASP asp;
 
153
 
 
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) );
 
157
        exit( 1 );
 
158
    }
 
159
 
 
160
    if (asp->child) {
 
161
        configfree(configs, config); /* free a bunch of stuff */
 
162
        afp_over_asp(&config->obj);
 
163
        exit (0);
 
164
    }
 
165
 
 
166
    return 0;
 
167
}
 
168
#endif /* no afp/asp */
 
169
 
 
170
static int dsi_start(AFPConfig *config, AFPConfig *configs,
 
171
                     server_child *server_children)
 
172
{
 
173
    DSI *dsi;
 
174
 
 
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) );
 
178
        exit( 1 );
 
179
    }
 
180
 
 
181
    /* we've forked. */
 
182
    if (dsi->child) {
 
183
        configfree(configs, config);
 
184
        afp_over_dsi(&config->obj); /* start a session */
 
185
        exit (0);
 
186
    }
 
187
 
 
188
    return 0;
 
189
}
 
190
 
 
191
#ifndef NO_DDP
 
192
static AFPConfig *ASPConfigInit(const struct afp_options *options,
 
193
                                unsigned char *refcount)
 
194
{
 
195
    AFPConfig *config;
 
196
    ATP atp;
 
197
    ASP asp;
 
198
    char *Obj, *Type = "AFPServer", *Zone = "*";
 
199
 
 
200
    if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
 
201
        return NULL;
 
202
 
 
203
    if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL)  {
 
204
        LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
 
205
        free(config);
 
206
        return NULL;
 
207
    }
 
208
 
 
209
    if ((asp = asp_init( atp )) == NULL) {
 
210
        LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
 
211
        atp_close(atp);
 
212
        free(config);
 
213
        return NULL;
 
214
    }
 
215
 
 
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;
 
221
    }
 
222
 
 
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;
 
227
 
 
228
    if ((config->obj.Type = strdup(Type)) == NULL) {
 
229
        free(config->obj.Obj);
 
230
        goto serv_free_return;
 
231
    }
 
232
 
 
233
    if ((config->obj.Zone = strdup(Zone)) == NULL) {
 
234
        free(config->obj.Obj);
 
235
        free(config->obj.Type);
 
236
        goto serv_free_return;
 
237
    }
 
238
 
 
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;
 
247
    }
 
248
 
 
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 );
 
253
 
 
254
    config->fd = atp_fileno(atp);
 
255
    config->obj.handle = asp;
 
256
    config->obj.config = config;
 
257
    config->obj.proto = AFPPROTO_ASP;
 
258
 
 
259
    memcpy(&config->obj.options, options, sizeof(struct afp_options));
 
260
    config->optcount = refcount;
 
261
    (*refcount)++;
 
262
 
 
263
    config->server_start = asp_start;
 
264
    config->server_cleanup = asp_cleanup;
 
265
 
 
266
    return config;
 
267
 
 
268
serv_free_return:
 
269
                    asp_close(asp);
 
270
    free(config);
 
271
    return NULL;
 
272
}
 
273
#endif /* no afp/asp */
 
274
 
 
275
 
 
276
static AFPConfig *DSIConfigInit(const struct afp_options *options,
 
277
                                unsigned char *refcount,
 
278
                                const dsi_proto protocol)
 
279
{
 
280
    AFPConfig *config;
 
281
    DSI *dsi;
 
282
    char *p, *q;
 
283
#ifdef USE_SRVLOC
 
284
    SLPError err;
 
285
    SLPError callbackerr;
 
286
    SLPHandle hslp;
 
287
    struct servent *afpovertcp;
 
288
    int afp_port = 548;
 
289
    const char *srvloc_hostname;
 
290
#endif /* USE_SRVLOC */
 
291
 
 
292
    if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
 
293
        LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
 
294
        return NULL;
 
295
    }
 
296
 
 
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) );
 
302
        free(config);
 
303
        return NULL;
 
304
    }
 
305
 
 
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),
 
309
            VERSION);
 
310
    } else {
 
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);
 
314
    }
 
315
 
 
316
#ifdef USE_SRVLOC
 
317
    srvloc_url[0] = '\0';       /*  Mark that we haven't registered.  */
 
318
    if (!(options->flags & OPTION_NOSLP)) {
 
319
        err = SLPOpen("en", SLP_FALSE, &hslp);
 
320
        if (err != SLP_OK) {
 
321
            LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
 
322
            goto srvloc_reg_err;
 
323
        }
 
324
 
 
325
        /* XXX We don't want to tack on the port number if we don't have to.
 
326
         * Why?
 
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.
 
330
         */
 
331
        afpovertcp = getservbyname("afpovertcp", "tcp");
 
332
        srvloc_hostname = (options->server ? options->server : options->hostname);
 
333
        if (afpovertcp != NULL) {
 
334
            afp_port = afpovertcp->s_port;
 
335
        }
 
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';
 
339
            goto srvloc_reg_err;
 
340
        }
 
341
        if (dsi->server.sin_port == afp_port) {
 
342
            sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), srvloc_hostname);
 
343
        }
 
344
        else {
 
345
            sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), srvloc_hostname);
 
346
        }
 
347
 
 
348
        err = SLPReg(hslp,
 
349
                     srvloc_url,
 
350
                     SLP_LIFETIME_MAXIMUM,
 
351
                     "",
 
352
                     "",
 
353
                     SLP_TRUE,
 
354
                     SRVLOC_callback,
 
355
                     &callbackerr);
 
356
        if (err != SLP_OK) {
 
357
            LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
 
358
            srvloc_url[0] = '\0';
 
359
            goto srvloc_reg_err;
 
360
        }
 
361
 
 
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';
 
365
            goto srvloc_reg_err;
 
366
        }
 
367
 
 
368
        LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
 
369
 
 
370
srvloc_reg_err:
 
371
        SLPClose(hslp);
 
372
    }
 
373
#endif /* USE_SRVLOC */
 
374
 
 
375
 
 
376
    config->fd = dsi->serversock;
 
377
    config->obj.handle = dsi;
 
378
    config->obj.config = config;
 
379
    config->obj.proto = AFPPROTO_DSI;
 
380
 
 
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, ':')))
 
386
        *q = '\0';
 
387
 
 
388
    config->optcount = refcount;
 
389
    (*refcount)++;
 
390
 
 
391
    config->server_start = dsi_start;
 
392
#ifdef USE_SRVLOC
 
393
    config->server_cleanup = dsi_cleanup;
 
394
#endif /* USE_SRVLOC */
 
395
    return config;
 
396
}
 
397
 
 
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)
 
403
{
 
404
    AFPConfig *config = NULL, *next = NULL;
 
405
    unsigned char *refcount;
 
406
 
 
407
    if ((refcount = (unsigned char *)
 
408
                    calloc(1, sizeof(unsigned char))) == NULL) {
 
409
        LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
 
410
        return NULL;
 
411
    }
 
412
 
 
413
#ifndef NO_DDP
 
414
    /* handle asp transports */
 
415
    if ((options->transports & AFPTRANS_DDP) &&
 
416
            (config = ASPConfigInit(options, refcount)))
 
417
        config->defoptions = defoptions;
 
418
#endif /* NO_DDP */
 
419
 
 
420
    /* handle dsi transports and dsi proxies. we only proxy
 
421
     * for DSI connections. */
 
422
 
 
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;
 
428
     */
 
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;
 
434
 
 
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.
 
439
    */
 
440
    auth_load(options->uampath, options->uamlist);
 
441
 
 
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);
 
445
 
 
446
    /* attach dsi config to tail of asp config */
 
447
    if (config) {
 
448
        config->next = next;
 
449
        return config;
 
450
    }
 
451
 
 
452
    return next;
 
453
}
 
454
 
 
455
/* fill in the appropriate bits for each interface */
 
456
AFPConfig *configinit(struct afp_options *cmdline)
 
457
{
 
458
    FILE *fp;
 
459
    char buf[LINESIZE + 1], *p, have_option = 0;
 
460
    struct afp_options options;
 
461
    AFPConfig *config, *first = NULL;
 
462
 
 
463
    /* if config file doesn't exist, load defaults */
 
464
    if ((fp = fopen(cmdline->configfile, "r")) == NULL)
 
465
    {
 
466
        LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
 
467
            cmdline->configfile);
 
468
        return AFPConfigInit(cmdline, cmdline);
 
469
    }
 
470
 
 
471
    LOG(log_debug, logtype_afpd, "Loading ConfigFile"); 
 
472
 
 
473
    /* scan in the configuration file */
 
474
    while (!feof(fp)) {
 
475
        if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
 
476
            continue;
 
477
 
 
478
        /* a little pre-processing to get rid of spaces and end-of-lines */
 
479
        p = buf;
 
480
        while (p && isspace(*p))
 
481
            p++;
 
482
        if (!p || (*p == '\0'))
 
483
            continue;
 
484
 
 
485
        have_option = 1;
 
486
 
 
487
        memcpy(&options, cmdline, sizeof(options));
 
488
        if (!afp_options_parseline(p, &options))
 
489
            continue;
 
490
 
 
491
        /* this should really get a head and a tail to simplify things. */
 
492
        if (!first) {
 
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;
 
497
        }
 
498
    }
 
499
 
 
500
    LOG(log_debug, logtype_afpd, "Finished parsing Config File");
 
501
    fclose(fp);
 
502
 
 
503
    if (!have_option)
 
504
        return AFPConfigInit(cmdline, cmdline);
 
505
 
 
506
    return first;
 
507
}