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

« back to all changes in this revision

Viewing changes to etc/afpd/status.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: status.c,v 1.7.4.2 2003/06/09 14:53:16 srittau Exp $
 
3
 *
 
4
 * Copyright (c) 1990,1993 Regents of The University of Michigan.
 
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 <unistd.h>
 
15
#include <string.h>
 
16
#include <sys/types.h>
 
17
 
 
18
#ifdef BSD4_4
 
19
#include <sys/param.h>
 
20
#ifndef USE_GETHOSTID
 
21
#include <sys/sysctl.h>
 
22
#endif /* USE_GETHOSTID */
 
23
#endif /* BSD4_4 */
 
24
 
 
25
#include <netatalk/at.h>
 
26
#include <netatalk/endian.h>
 
27
#include <atalk/dsi.h>
 
28
#include <atalk/atp.h>
 
29
#include <atalk/asp.h>
 
30
#include <atalk/nbp.h>
 
31
 
 
32
#include "globals.h"  /* includes <netdb.h> */
 
33
#include "status.h"
 
34
#include "afp_config.h"
 
35
#include "icon.h"
 
36
 
 
37
static void status_flags(char *data, const int notif, const int ipok,
 
38
                         const unsigned char passwdbits, const int dirsrvcs)
 
39
{
 
40
    u_int16_t           status;
 
41
 
 
42
    status = AFPSRVRINFO_COPY;
 
43
    if (passwdbits & PASSWD_SET) /* some uams may not allow this. */
 
44
        status |= AFPSRVRINFO_PASSWD;
 
45
    if (passwdbits & PASSWD_NOSAVE)
 
46
        status |= AFPSRVRINFO_NOSAVEPASSWD;
 
47
    status |= AFPSRVRINFO_SRVSIGNATURE;
 
48
    /* only advertise tcp/ip if we have a valid address */
 
49
    if (ipok)
 
50
        status |= AFPSRVRINFO_TCPIP;
 
51
    status |= AFPSRVRINFO_SRVMSGS;
 
52
    /* Allow the user to decide if we should support server notifications.
 
53
     * With this turned off, the clients will poll for directory changes every
 
54
     * 10 seconds.  This might be too costly to network resources, so make
 
55
     * this an optional thing.  Default will be to _not_ support server
 
56
     * notifications. */
 
57
    if (notif) {
 
58
        status |= AFPSRVRINFO_SRVNOTIFY;
 
59
    }
 
60
    status |= AFPSRVRINFO_FASTBOZO;
 
61
    if (dirsrvcs)
 
62
        status |= AFPSRVRINFO_SRVRDIR;
 
63
    status = htons(status);
 
64
    memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status));
 
65
}
 
66
 
 
67
static int status_server(char *data, const char *server)
 
68
{
 
69
    char                *start = data;
 
70
    char                *Obj, *Type, *Zone;
 
71
    u_int16_t           status;
 
72
    int                 len;
 
73
 
 
74
    /* make room for all offsets before server name */
 
75
    data += AFPSTATUS_PRELEN;
 
76
 
 
77
    /* extract the obj part of the server */
 
78
    Obj = (char *) server;
 
79
    nbp_name(server, &Obj, &Type, &Zone);
 
80
    len = strlen(Obj);
 
81
    *data++ = len;
 
82
    memcpy( data, Obj, len );
 
83
    if ((len + 1) & 1) /* pad server name and length byte to even boundary */
 
84
        len++;
 
85
    data += len;
 
86
 
 
87
    /* Make room for signature and net address offset. Save location of
 
88
     * signature offset. We're also making room for directory names offset
 
89
     * and the utf-8 server name offset.
 
90
     *
 
91
     * NOTE: Technically, we don't need to reserve space for the
 
92
     * signature and net address offsets if they're not going to be
 
93
     * used. As there are no offsets after them, it doesn't hurt to
 
94
     * have them specified though. So, we just do that to simplify
 
95
     * things.
 
96
     *
 
97
     * NOTE2: AFP3.1 Documentation states that the directory names offset
 
98
     * is a required feature, even though it can be set to zero.
 
99
     */
 
100
    len = data - start;
 
101
    status = htons(len + AFPSTATUS_POSTLEN);
 
102
    memcpy(start + AFPSTATUS_MACHOFF, &status, sizeof(status));
 
103
    return len; /* return the offset to beginning of signature offset */
 
104
}
 
105
 
 
106
static void status_machine(char *data)
 
107
{
 
108
    char                *start = data;
 
109
    u_int16_t           status;
 
110
    int                 len;
 
111
#ifdef AFS
 
112
    const char          *machine = "afs";
 
113
#else /* !AFS */
 
114
    const char          *machine = "unix";
 
115
#endif /* AFS */
 
116
 
 
117
    memcpy(&status, start + AFPSTATUS_MACHOFF, sizeof(status));
 
118
    data += ntohs( status );
 
119
    len = strlen( machine );
 
120
    *data++ = len;
 
121
    memcpy( data, machine, len );
 
122
    data += len;
 
123
    status = htons(data - start);
 
124
    memcpy(start + AFPSTATUS_VERSOFF, &status, sizeof(status));
 
125
}
 
126
 
 
127
 
 
128
/* server signature is a 16-byte quantity */
 
129
static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi,
 
130
                                  const char *hostname)
 
131
{
 
132
    char                 *status;
 
133
    int                  i;
 
134
    u_int16_t            offset, sigoff;
 
135
    long                 hostid;
 
136
    static int           id = 0;
 
137
#ifdef BSD4_4
 
138
    int                  mib[2];
 
139
    size_t               len;
 
140
#endif /* BSD4_4 */
 
141
 
 
142
    status = data;
 
143
 
 
144
    /* get server signature offset */
 
145
    memcpy(&offset, data + *servoffset, sizeof(offset));
 
146
    sigoff = offset = ntohs(offset);
 
147
 
 
148
    /* jump to server signature offset */
 
149
    data += offset;
 
150
 
 
151
    /* 16-byte signature consists of copies of the hostid */
 
152
#if defined(BSD4_4) && defined(USE_GETHOSTID)
 
153
    mib[0] = CTL_KERN;
 
154
    mib[1] = KERN_HOSTID;
 
155
    len = sizeof(hostid);
 
156
    sysctl(mib, 2, &hostid, &len, NULL, 0);
 
157
#else /* BSD4_4 && USE_GETHOSTID */
 
158
    hostid = gethostid();
 
159
#endif /* BSD4_4 && USE_GETHOSTID */
 
160
    if (!hostid) {
 
161
        if (dsi)
 
162
            hostid = dsi->server.sin_addr.s_addr;
 
163
        else {
 
164
            struct hostent *host;
 
165
 
 
166
            if ((host = gethostbyname(hostname)))
 
167
                hostid = ((struct in_addr *) host->h_addr)->s_addr;
 
168
        }
 
169
    }
 
170
 
 
171
    /* it turns out that a server signature screws up separate
 
172
     * servers running on the same machine. to work around that, 
 
173
     * i add in an increment */
 
174
    hostid += id;
 
175
    id++;
 
176
    for (i = 0; i < 16; i += sizeof(hostid)) {
 
177
        memcpy(data, &hostid, sizeof(hostid));
 
178
        data += sizeof(hostid);
 
179
    }
 
180
 
 
181
    /* calculate net address offset */
 
182
    *servoffset += sizeof(offset);
 
183
    offset = htons(data - status);
 
184
    memcpy(status + *servoffset, &offset, sizeof(offset));
 
185
    return sigoff;
 
186
}
 
187
 
 
188
static int status_netaddress(char *data, int *servoffset,
 
189
                             const ASP asp, const DSI *dsi,
 
190
                             const char *fqdn)
 
191
{
 
192
    char               *begin;
 
193
    u_int16_t          offset;
 
194
 
 
195
    begin = data;
 
196
 
 
197
    /* get net address offset */
 
198
    memcpy(&offset, data + *servoffset, sizeof(offset));
 
199
    data += ntohs(offset);
 
200
 
 
201
    /* format:
 
202
       Address count (byte) 
 
203
       len (byte = sizeof(length + address type + address) 
 
204
       address type (byte, ip address = 0x01, ip + port = 0x02,
 
205
                           ddp address = 0x03, fqdn = 0x04) 
 
206
       address (up to 254 bytes, ip = 4, ip + port = 6, ddp = 4)
 
207
       */
 
208
 
 
209
    /* number of addresses. this currently screws up if we have a dsi
 
210
       connection, but we don't have the ip address. to get around this,
 
211
       we turn off the status flag for tcp/ip. */
 
212
    *data++ = ((fqdn && dsi) ? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0);
 
213
 
 
214
    /* handle DNS names */
 
215
    if (fqdn && dsi) {
 
216
        int len = strlen(fqdn);
 
217
        *data++ = len + 2;
 
218
        *data++ = 0x04;
 
219
        memcpy(data, fqdn, len);
 
220
        data += len;
 
221
    }
 
222
 
 
223
    /* ip address */
 
224
    if (dsi) {
 
225
        const struct sockaddr_in *inaddr = &dsi->server;
 
226
 
 
227
        if (inaddr->sin_port == htons(DSI_AFPOVERTCP_PORT)) {
 
228
            *data++ = 6; /* length */
 
229
            *data++ = 0x01; /* basic ip address */
 
230
            memcpy(data, &inaddr->sin_addr.s_addr,
 
231
                   sizeof(inaddr->sin_addr.s_addr));
 
232
            data += sizeof(inaddr->sin_addr.s_addr);
 
233
        } else {
 
234
            /* ip address + port */
 
235
            *data++ = 8;
 
236
            *data++ = 0x02; /* ip address with port */
 
237
            memcpy(data, &inaddr->sin_addr.s_addr,
 
238
                   sizeof(inaddr->sin_addr.s_addr));
 
239
            data += sizeof(inaddr->sin_addr.s_addr);
 
240
            memcpy(data, &inaddr->sin_port, sizeof(inaddr->sin_port));
 
241
            data += sizeof(inaddr->sin_port);
 
242
        }
 
243
    }
 
244
 
 
245
#ifndef NO_DDP
 
246
    if (asp) {
 
247
        const struct sockaddr_at *ddpaddr = atp_sockaddr(asp->asp_atp);
 
248
 
 
249
        /* ddp address */
 
250
        *data++ = 6;
 
251
        *data++ = 0x03; /* ddp address */
 
252
        memcpy(data, &ddpaddr->sat_addr.s_net, sizeof(ddpaddr->sat_addr.s_net));
 
253
        data += sizeof(ddpaddr->sat_addr.s_net);
 
254
        memcpy(data, &ddpaddr->sat_addr.s_node,
 
255
               sizeof(ddpaddr->sat_addr.s_node));
 
256
        data += sizeof(ddpaddr->sat_addr.s_node);
 
257
        memcpy(data, &ddpaddr->sat_port, sizeof(ddpaddr->sat_port));
 
258
        data += sizeof(ddpaddr->sat_port);
 
259
    }
 
260
#endif /* ! NO_DDP */
 
261
 
 
262
    /* calculate/store Directory Services Names offset */
 
263
    offset = htons(data - begin);
 
264
    *servoffset += sizeof(offset);
 
265
    memcpy(begin + *servoffset, &offset, sizeof(offset));
 
266
 
 
267
    /* return length of buffer */
 
268
    return (data - begin);
 
269
}
 
270
 
 
271
static int status_directorynames(char *data, int *diroffset,
 
272
                                 const DSI *dsi,
 
273
                                 const struct afp_options *options)
 
274
{
 
275
    char *begin = data;
 
276
    u_int16_t offset;
 
277
    memcpy(&offset, data + *diroffset, sizeof(offset));
 
278
    offset = ntohs(offset);
 
279
    data += offset;
 
280
                                                                                
 
281
    /* I can not find documentation of any other purpose for the
 
282
     * DirectoryNames field.
 
283
     */
 
284
    /*
 
285
     * Try to synthesize a principal:
 
286
     * service '/' fqdn '@' realm
 
287
     */
 
288
    if (options->k5service && options->k5realm && options->fqdn) {
 
289
        /* should k5princ be utf8 encoded? */
 
290
        u_int8_t len;
 
291
        char *p = strchr( options->fqdn, ':' );
 
292
        if (p)
 
293
            *p = '\0';
 
294
        len = strlen( options->k5service )
 
295
                        + strlen( options->fqdn )
 
296
                        + strlen( options->k5realm );
 
297
        len+=2; /* '/' and '@' */
 
298
        *data++ = 1; /* DirectoryNamesCount */
 
299
        *data++ = len;
 
300
        snprintf( data, len + 1, "%s/%s@%s", options->k5service,
 
301
                                options->fqdn, options->k5realm );
 
302
        data += len;
 
303
        if (p)
 
304
            *p = ':';
 
305
    } else {
 
306
        memset(begin + *diroffset, 0, sizeof(offset));
 
307
    }
 
308
 
 
309
    /* Calculate and store offset for UTF8ServerName */
 
310
    *diroffset += sizeof(u_int16_t);
 
311
    offset = htons(data - begin);
 
312
    memcpy(begin + *diroffset, &offset, sizeof(u_int16_t));
 
313
                                                                                
 
314
    /* return length of buffer */
 
315
    return (data - begin);
 
316
}
 
317
 
 
318
static int status_utf8servername(char *data, int *nameoffset,
 
319
                                 const DSI *dsi,
 
320
                                 const struct afp_options *options)
 
321
{
 
322
    char *begin = data;
 
323
    u_int16_t offset;
 
324
    memcpy(&offset, data + *nameoffset, sizeof(offset));
 
325
    offset = ntohs(offset);
 
326
    data += offset;
 
327
                                                                                
 
328
    /* FIXME: For now we set the UTF-8 ServerName offset to 0
 
329
     * It's irrelevent anyway until we set the appropriate Flags value.
 
330
     * Later this can be set to something meaningful.
 
331
     *
 
332
     * What is the valid character range for an nbpname?
 
333
     *
 
334
     * Apple's server likes to use the non-qualified hostname
 
335
     * This obviously won't work very well if multiple servers are running
 
336
     * on the box.
 
337
     */
 
338
    memset(begin + *nameoffset, 0, sizeof(offset));
 
339
                                                                                
 
340
    /* return length of buffer */
 
341
    return (data - begin);
 
342
}
 
343
 
 
344
/* returns actual offset to signature */
 
345
static void status_icon(char *data, const unsigned char *icondata,
 
346
                        const int iconlen, const int sigoffset)
 
347
{
 
348
    char                *start = data;
 
349
    char                *sigdata = data + sigoffset;
 
350
    u_int16_t           ret, status;
 
351
 
 
352
    memcpy(&status, start + AFPSTATUS_ICONOFF, sizeof(status));
 
353
    if ( icondata == NULL ) {
 
354
        ret = status;
 
355
        memset(start + AFPSTATUS_ICONOFF, 0, sizeof(status));
 
356
    } else {
 
357
        data += ntohs( status );
 
358
        memcpy( data, icondata, iconlen);
 
359
        data += iconlen;
 
360
        ret = htons(data - start);
 
361
    }
 
362
 
 
363
    /* put in signature offset */
 
364
    if (sigoffset)
 
365
        memcpy(sigdata, &ret, sizeof(ret));
 
366
}
 
367
 
 
368
void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
 
369
                 const struct afp_options *options)
 
370
{
 
371
    ASP asp;
 
372
    DSI *dsi;
 
373
    char *status;
 
374
    int statuslen, c, sigoff;
 
375
 
 
376
    if (!(aspconfig || dsiconfig) || !options)
 
377
        return;
 
378
 
 
379
    if (aspconfig) {
 
380
        asp = aspconfig->obj.handle;
 
381
        status = aspconfig->status;
 
382
    } else
 
383
        asp = NULL;
 
384
 
 
385
    if (dsiconfig) {
 
386
        dsi = dsiconfig->obj.handle;
 
387
        if (!aspconfig)
 
388
            status = dsiconfig->status;
 
389
    } else
 
390
        dsi = NULL;
 
391
 
 
392
    /*
 
393
     * These routines must be called in order -- earlier calls
 
394
     * set the offsets for later calls.
 
395
     *
 
396
     * using structs is a bad idea, but that's what the original code
 
397
     * does. solaris, in fact, will segfault with them. so, now
 
398
     * we just use the powers of #defines and memcpy.
 
399
     *
 
400
     * reply block layout (offsets are 16-bit quantities):
 
401
     * machine type offset -> AFP version count offset ->
 
402
     * UAM count offset -> vol icon/mask offset -> flags ->
 
403
     *
 
404
     * server name [padded to even boundary] -> signature offset ->
 
405
     * network address offset ->
 
406
     *
 
407
     * at the appropriate offsets:
 
408
     * machine type, afp versions, uams, server signature
 
409
     * (16-bytes), network addresses, volume icon/mask 
 
410
     */
 
411
 
 
412
    status_flags(status, options->server_notif, options->fqdn ||
 
413
                 (dsiconfig && dsi->server.sin_addr.s_addr),
 
414
                 options->passwdbits,
 
415
                 (options->k5service && options->k5realm && options->fqdn));
 
416
    /* returns offset to signature offset */
 
417
    c = status_server(status, options->server ? options->server :
 
418
                      options->hostname);
 
419
    status_machine(status);
 
420
    status_versions(status);
 
421
    status_uams(status, options->uamlist);
 
422
    if (options->flags & OPTION_CUSTOMICON)
 
423
        status_icon(status, icon, sizeof(icon), c);
 
424
    else
 
425
        status_icon(status, apple_atalk_icon, sizeof(apple_atalk_icon), c);
 
426
 
 
427
    sigoff = status_signature(status, &c, dsi, options->hostname);
 
428
    /* c now contains the offset where the netaddress offset lives */
 
429
                                                                                
 
430
    status_netaddress(status, &c, asp, dsi, options->fqdn);
 
431
    /* c now contains the offset where the Directory Names Count offset lives */                                                                                
 
432
    status_directorynames(status, &c, dsi, options);
 
433
    /* c now contains the offset where the UTF-8 ServerName offset lives */
 
434
 
 
435
    statuslen = status_utf8servername(status, &c, dsi, options);
 
436
 
 
437
 
 
438
#ifndef NO_DDP
 
439
    if (aspconfig) {
 
440
        asp_setstatus(asp, status, statuslen);
 
441
        aspconfig->signature = status + sigoff;
 
442
        aspconfig->statuslen = statuslen;
 
443
    }
 
444
#endif /* ! NO_DDP */
 
445
 
 
446
    if (dsiconfig) {
 
447
        if (aspconfig) { /* copy to dsiconfig */
 
448
            memcpy(dsiconfig->status, status, ATP_MAXDATA);
 
449
            status = dsiconfig->status;
 
450
        }
 
451
 
 
452
        if ((options->flags & OPTION_CUSTOMICON) == 0) {
 
453
            status_icon(status, apple_tcp_icon, sizeof(apple_tcp_icon), 0);
 
454
        }
 
455
        dsi_setstatus(dsi, status, statuslen);
 
456
        dsiconfig->signature = status + sigoff;
 
457
        dsiconfig->statuslen = statuslen;
 
458
    }
 
459
}
 
460
 
 
461
/* this is the same as asp/dsi_getstatus */
 
462
int afp_getsrvrinfo(obj, ibuf, ibuflen, rbuf, rbuflen )
 
463
AFPObj      *obj;
 
464
char    *ibuf, *rbuf;
 
465
int             ibuflen, *rbuflen;
 
466
{
 
467
    AFPConfig *config = obj->config;
 
468
 
 
469
    memcpy(rbuf, config->status, config->statuslen);
 
470
    *rbuflen = config->statuslen;
 
471
    return AFP_OK;
 
472
}