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

« back to all changes in this revision

Viewing changes to etc/afpd/volume.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: volume.c,v 1.36.2.7 2003/11/18 21:49:41 bfernhomberg 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 <sys/time.h>
 
13
#include <atalk/logger.h>
 
14
#include <sys/types.h>
 
15
#include <sys/stat.h>
 
16
#include <sys/param.h>
 
17
#include <sys/socket.h>
 
18
#include <netinet/in.h>
 
19
#include <arpa/inet.h>
 
20
#include <netatalk/endian.h>
 
21
#include <atalk/asp.h>
 
22
#include <atalk/dsi.h>
 
23
#include <atalk/adouble.h>
 
24
#include <atalk/afp.h>
 
25
#include <atalk/util.h>
 
26
#ifdef CNID_DB
 
27
#include <atalk/cnid.h>
 
28
#endif /* CNID_DB*/
 
29
#include <dirent.h>
 
30
#ifdef HAVE_FCNTL_H
 
31
#include <fcntl.h>
 
32
#endif /* HAVE_FCNTL_H */
 
33
#include <stdio.h>
 
34
#include <stdlib.h>
 
35
#include <ctype.h>
 
36
 
 
37
/* STDC check */
 
38
#if STDC_HEADERS
 
39
#include <string.h>
 
40
#else /* STDC_HEADERS */
 
41
#ifndef HAVE_STRCHR
 
42
#define strchr index
 
43
#define strrchr index
 
44
#endif /* HAVE_STRCHR */
 
45
char *strchr (), *strrchr ();
 
46
#ifndef HAVE_MEMCPY
 
47
#define memcpy(d,s,n) bcopy ((s), (d), (n))
 
48
#define memmove(d,s,n) bcopy ((s), (d), (n))
 
49
#endif /* ! HAVE_MEMCPY */
 
50
#endif /* STDC_HEADERS */
 
51
 
 
52
#include <pwd.h>
 
53
#include <grp.h>
 
54
#include <utime.h>
 
55
#include <errno.h>
 
56
 
 
57
#include "directory.h"
 
58
#include "file.h"
 
59
#include "volume.h"
 
60
#include "globals.h"
 
61
#include "unix.h"
 
62
 
 
63
#ifndef MIN
 
64
#define MIN(a, b) ((a) < (b) ? (a) : (b))
 
65
#endif /* ! MIN */
 
66
 
 
67
#ifndef NO_LARGE_VOL_SUPPORT
 
68
#if BYTE_ORDER == BIG_ENDIAN
 
69
#define hton64(x)       (x)
 
70
#define ntoh64(x)       (x)
 
71
#else /* BYTE_ORDER == BIG_ENDIAN */
 
72
#define hton64(x)       ((u_int64_t) (htonl(((x) >> 32) & 0xffffffffLL)) | \
 
73
                         (u_int64_t) ((htonl(x) & 0xffffffffLL) << 32))
 
74
#define ntoh64(x)       (hton64(x))
 
75
#endif /* BYTE_ORDER == BIG_ENDIAN */
 
76
#endif /* ! NO_LARGE_VOL_SUPPORT */
 
77
 
 
78
static struct vol *volumes = NULL;
 
79
static int              lastvid = 0;
 
80
#ifndef CNID_DB
 
81
static char             *Trash = "\02\024Network Trash Folder";
 
82
#endif /* CNID_DB */
 
83
static struct extmap    *extmap = NULL, *defextmap = NULL;
 
84
static int              extmap_cnt;
 
85
 
 
86
#define VOLOPT_ALLOW      0  /* user allow list */
 
87
#define VOLOPT_DENY       1  /* user deny list */
 
88
#define VOLOPT_RWLIST     2  /* user rw list */
 
89
#define VOLOPT_ROLIST     3  /* user ro list */
 
90
#define VOLOPT_CODEPAGE   4  /* codepage */
 
91
#define VOLOPT_PASSWORD   5  /* volume password */
 
92
#define VOLOPT_CASEFOLD   6  /* character case mangling */
 
93
#define VOLOPT_FLAGS      7  /* various flags */
 
94
#define VOLOPT_DBPATH     8  /* path to database */
 
95
#define VOLOPT_MAPCHARS   9  /* does mtou and utom mappings. syntax:
 
96
m and u can be double-byte hex
 
97
strings if necessary.
 
98
m=u -> map both ways
 
99
  m>u -> map m to u
 
100
  m<u -> map u to m
 
101
  !u  -> make u illegal always
 
102
  ~u  -> make u illegal only as the first
 
103
  part of a double-byte character.
 
104
  */
 
105
#define VOLOPT_VETO      10  /* list of veto filespec */
 
106
 
 
107
#ifdef FORCE_UIDGID
 
108
#warning UIDGID
 
109
#include "uid.h"
 
110
 
 
111
#define VOLOPT_FORCEUID  11  /* force uid for username x */
 
112
#define VOLOPT_FORCEGID  12  /* force gid for group x */
 
113
#define VOLOPT_UMASK     13
 
114
#define VOLOPT_MAX       13
 
115
#else /* normally, there are only 9 possible options */
 
116
#define VOLOPT_UMASK     11
 
117
#define VOLOPT_MAX       11
 
118
#endif /* FORCE_UIDGID */
 
119
 
 
120
#define VOLOPT_NUM        (VOLOPT_MAX + 1)
 
121
 
 
122
#define VOLPASSLEN  8
 
123
#define VOLOPT_DEFAULT     ":DEFAULT:"
 
124
#define VOLOPT_DEFAULT_LEN 9
 
125
  struct vol_option {
 
126
      char *c_value;
 
127
      int i_value;
 
128
  };
 
129
 
 
130
static __inline__ void volfree(struct vol_option *options,
 
131
                               const struct vol_option *save)
 
132
{
 
133
    int i;
 
134
 
 
135
    if (save) {
 
136
        for (i = 0; i < VOLOPT_MAX; i++) {
 
137
            if (options[i].c_value && (options[i].c_value != save[i].c_value))
 
138
                free(options[i].c_value);
 
139
        }
 
140
    } else {
 
141
        for (i = 0; i < VOLOPT_MAX; i++) {
 
142
            if (options[i].c_value)
 
143
                free(options[i].c_value);
 
144
        }
 
145
    }
 
146
}
 
147
 
 
148
 
 
149
/* handle variable substitutions. here's what we understand:
 
150
 * $c   -> client ip/appletalk address
 
151
 * $f   -> full name (whatever's in the gecos field)
 
152
 * $g   -> group
 
153
 * $h   -> hostname 
 
154
 * $s   -> server name (hostname if it doesn't exist)
 
155
 * $u   -> username (guest is usually nobody)
 
156
 * $v   -> volume name (ADEID_NAME or basename)
 
157
 * $z   -> zone (may not exist)
 
158
 * $$   -> $
 
159
 */
 
160
#define is_var(a, b) (strncmp((a), (b), 2) == 0)
 
161
static void volxlate(AFPObj *obj, char *dest, int destlen,
 
162
                     char *src, struct passwd *pwd, char *path)
 
163
{
 
164
    char *p, *q;
 
165
    int len;
 
166
 
 
167
    strncpy(dest, src, destlen);
 
168
    if ((p = strchr(src, '$')) == NULL) /* nothing to do */
 
169
        return;
 
170
 
 
171
    /* first part of the path. just forward to the next variable. */
 
172
    len = MIN(p - src, destlen);
 
173
    if (len > 0) {
 
174
        destlen -= len;
 
175
        dest += len;
 
176
    }
 
177
 
 
178
    while (p && destlen > 0) {
 
179
        /* now figure out what the variable is */
 
180
        q = NULL;
 
181
        if (is_var(p, "$c")) {
 
182
            if (obj->proto == AFPPROTO_ASP) {
 
183
                ASP asp = obj->handle;
 
184
 
 
185
                len = sprintf(dest, "%u.%u", ntohs(asp->asp_sat.sat_addr.s_net),
 
186
                              asp->asp_sat.sat_addr.s_node);
 
187
                dest += len;
 
188
                destlen -= len;
 
189
 
 
190
            } else if (obj->proto == AFPPROTO_DSI) {
 
191
                DSI *dsi = obj->handle;
 
192
 
 
193
                len = sprintf(dest, "%s:%u", inet_ntoa(dsi->client.sin_addr),
 
194
                              ntohs(dsi->client.sin_port));
 
195
                dest += len;
 
196
                destlen -= len;
 
197
            }
 
198
        } else if (is_var(p, "$f")) {
 
199
            if ((q = strchr(pwd->pw_gecos, ',')))
 
200
                *q = '\0';
 
201
            q = pwd->pw_gecos;
 
202
        } else if (is_var(p, "$g")) {
 
203
            struct group *grp = getgrgid(pwd->pw_gid);
 
204
            if (grp)
 
205
                q = grp->gr_name;
 
206
        } else if (is_var(p, "$h")) {
 
207
            q = obj->options.hostname;
 
208
        } else if (is_var(p, "$s")) {
 
209
            if (obj->Obj)
 
210
                q = obj->Obj;
 
211
            else if (obj->options.server) {
 
212
                q = obj->options.server;
 
213
            } else
 
214
                q = obj->options.hostname;
 
215
        } else if (is_var(p, "$u")) {
 
216
            q = obj->username;
 
217
        } else if (is_var(p, "$v")) {
 
218
            if (path) {
 
219
                struct adouble ad;
 
220
 
 
221
                memset(&ad, 0, sizeof(ad));
 
222
                if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0, &ad) < 0)
 
223
                    goto no_volname;
 
224
 
 
225
                if ((len = MIN(ad_getentrylen(&ad, ADEID_NAME), destlen)) > 0) {
 
226
                    memcpy(dest, ad_entry(&ad, ADEID_NAME), len);
 
227
                    ad_close(&ad, ADFLAGS_HF);
 
228
                    dest += len;
 
229
                    destlen -= len;
 
230
                } else {
 
231
                    ad_close(&ad, ADFLAGS_HF);
 
232
no_volname: /* simple basename */
 
233
                    if ((q = strrchr(path, '/')) == NULL)
 
234
                        q = path;
 
235
                    else if (*(q + 1) != '\0')
 
236
                        q++;
 
237
                }
 
238
            }
 
239
        } else if (is_var(p, "$z")) {
 
240
            q = obj->Zone;
 
241
        } else if (is_var(p, "$$")) {
 
242
            q = "$";
 
243
        } else
 
244
            q = p;
 
245
 
 
246
        /* copy the stuff over. if we don't understand something that we
 
247
         * should, just skip it over. */
 
248
        if (q) {
 
249
            len = MIN(p == q ? 2 : strlen(q), destlen);
 
250
            strncpy(dest, q, len);
 
251
            dest += len;
 
252
            destlen -= len;
 
253
        }
 
254
 
 
255
        /* stuff up to next $ */
 
256
        src = p + 2;
 
257
        p = strchr(src, '$');
 
258
        len = p ? MIN(p - src, destlen) : destlen;
 
259
        if (len > 0) {
 
260
            strncpy(dest, src, len);
 
261
            dest += len;
 
262
            destlen -= len;
 
263
        }
 
264
    }
 
265
}
 
266
 
 
267
/* to make sure that val is valid, make sure to select an opt that
 
268
   includes val */
 
269
#define optionok(buf,opt,val) (strstr((buf),(opt)) && ((val)[1] != '\0'))
 
270
 
 
271
static __inline__ char *get_codepage_path(const char *path, const char *name)
 
272
{
 
273
    char *page;
 
274
    int len;
 
275
 
 
276
    if (path) {
 
277
        page = (char *) malloc((len = strlen(path)) + strlen(name) + 2);
 
278
        if (page) {
 
279
            strcpy(page, path);
 
280
            if (path[len - 1] != '/') /* add a / */
 
281
                strcat(page, "/");
 
282
            strcat(page, name);
 
283
        }
 
284
    } else {
 
285
        page = strdup(name);
 
286
    }
 
287
 
 
288
    /* debug: show which codepage directory we are using */
 
289
    LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
 
290
 
 
291
    return page;
 
292
}
 
293
 
 
294
/* handle all the options. tmp can't be NULL. */
 
295
static void volset(struct vol_option *options, char *volname, int vlen,
 
296
                   const char *nlspath, const char *tmp, AFPObj *obj,
 
297
                   struct passwd *pwd)
 
298
{
 
299
    char *val;
 
300
 
 
301
    LOG(log_debug, logtype_afpd, "Parsing volset %s", tmp);
 
302
 
 
303
    val = strchr(tmp, ':');
 
304
    if (!val) {
 
305
        /* we'll assume it's a volume name. */
 
306
        strncpy(volname, tmp, vlen);
 
307
 
 
308
    } else if (optionok(tmp, "allow:", val)) {
 
309
        if (options[VOLOPT_ALLOW].c_value)
 
310
            free(options[VOLOPT_ALLOW].c_value);
 
311
        options[VOLOPT_ALLOW].c_value = strdup(val + 1);
 
312
 
 
313
    } else if (optionok(tmp, "deny:", val)) {
 
314
        if (options[VOLOPT_DENY].c_value)
 
315
            free(options[VOLOPT_DENY].c_value);
 
316
        options[VOLOPT_DENY].c_value = strdup(val + 1);
 
317
 
 
318
    } else if (optionok(tmp, "rwlist:", val)) {
 
319
        if (options[VOLOPT_RWLIST].c_value)
 
320
            free(options[VOLOPT_RWLIST].c_value);
 
321
        options[VOLOPT_RWLIST].c_value = strdup(val + 1);
 
322
 
 
323
    } else if (optionok(tmp, "rolist:", val)) {
 
324
        if (options[VOLOPT_ROLIST].c_value)
 
325
            free(options[VOLOPT_ROLIST].c_value);
 
326
        options[VOLOPT_ROLIST].c_value = strdup(val + 1);
 
327
 
 
328
    } else if (optionok(tmp, "codepage:", val)) {
 
329
        if (options[VOLOPT_CODEPAGE].c_value)
 
330
            free(options[VOLOPT_CODEPAGE].c_value);
 
331
        options[VOLOPT_CODEPAGE].c_value = get_codepage_path(nlspath, val + 1);
 
332
 
 
333
    } else if (optionok(tmp, "veto:", val)) {
 
334
        if (options[VOLOPT_VETO].c_value)
 
335
            free(options[VOLOPT_VETO].c_value);
 
336
        options[VOLOPT_VETO].c_value = strdup(val + 1);
 
337
 
 
338
    } else if (optionok(tmp, "casefold:", val)) {
 
339
        if (strcasecmp(val + 1, "tolower") == 0)
 
340
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER;
 
341
        else if (strcasecmp(val + 1, "toupper") == 0)
 
342
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMUPPER;
 
343
        else if (strcasecmp(val + 1, "xlatelower") == 0)
 
344
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER;
 
345
        else if (strcasecmp(val + 1, "xlateupper") == 0)
 
346
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
 
347
 
 
348
    } else if (optionok(tmp, "options:", val)) {
 
349
        char *p;
 
350
 
 
351
        if ((p = strtok(val + 1, ",")) == NULL) /* nothing */
 
352
            return;
 
353
 
 
354
        while (p) {
 
355
            if (strcasecmp(p, "prodos") == 0)
 
356
                options[VOLOPT_FLAGS].i_value |= AFPVOL_A2VOL;
 
357
            else if (strcasecmp(p, "mswindows") == 0) {
 
358
                options[VOLOPT_FLAGS].i_value |= (AFPVOL_MSWINDOWS | AFPVOL_USEDOTS);
 
359
                if (!options[VOLOPT_CODEPAGE].c_value)
 
360
                    options[VOLOPT_CODEPAGE].c_value =
 
361
                        get_codepage_path(nlspath, MSWINDOWS_CODEPAGE);
 
362
 
 
363
            } else if (strcasecmp(p, "crlf") == 0)
 
364
                options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF;
 
365
            else if (strcasecmp(p, "noadouble") == 0)
 
366
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOADOUBLE;
 
367
            else if (strcasecmp(p, "ro") == 0)
 
368
                options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
 
369
            else if (strcasecmp(p, "nohex") == 0)
 
370
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX;
 
371
            else if (strcasecmp(p, "usedots") == 0)
 
372
                options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS;
 
373
            else if (strcasecmp(p, "limitsize") == 0)
 
374
                options[VOLOPT_FLAGS].i_value |= AFPVOL_LIMITSIZE;
 
375
            /* support for either "dropbox" or "dropkludge" */
 
376
            else if (strcasecmp(p, "dropbox") == 0)
 
377
                options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
 
378
            else if (strcasecmp(p, "dropkludge") == 0)
 
379
                options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
 
380
            else if (strcasecmp(p, "nofileid") == 0)
 
381
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID;
 
382
 
 
383
            p = strtok(NULL, ",");
 
384
        }
 
385
 
 
386
#ifdef CNID_DB
 
387
    } else if (optionok(tmp, "dbpath:", val)) {
 
388
        char t[MAXPATHLEN + 1];
 
389
        if (options[VOLOPT_DBPATH].c_value)
 
390
            free(options[VOLOPT_DBPATH].c_value);
 
391
 
 
392
        volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
 
393
        options[VOLOPT_DBPATH].c_value = strdup(t + 1);
 
394
#endif /* CNID_DB */
 
395
    } else if (optionok(tmp, "umask:", val)) {
 
396
        options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
 
397
    } else if (optionok(tmp, "mapchars:",val)) {
 
398
        if (options[VOLOPT_MAPCHARS].c_value)
 
399
            free(options[VOLOPT_MAPCHARS].c_value);
 
400
        options[VOLOPT_MAPCHARS].c_value = strdup(val + 1);
 
401
 
 
402
    } else if (optionok(tmp, "password:", val)) {
 
403
        if (options[VOLOPT_PASSWORD].c_value)
 
404
            free(options[VOLOPT_PASSWORD].c_value);
 
405
        options[VOLOPT_PASSWORD].c_value = strdup(val + 1);
 
406
 
 
407
#ifdef FORCE_UIDGID
 
408
 
 
409
        /* this code allows forced uid/gid per volume settings */
 
410
    } else if (optionok(tmp, "forceuid:", val)) {
 
411
        if (options[VOLOPT_FORCEUID].c_value)
 
412
            free(options[VOLOPT_FORCEUID].c_value);
 
413
        options[VOLOPT_FORCEUID].c_value = strdup(val + 1);
 
414
    } else if (optionok(tmp, "forcegid:", val)) {
 
415
        if (options[VOLOPT_FORCEGID].c_value)
 
416
            free(options[VOLOPT_FORCEGID].c_value);
 
417
        options[VOLOPT_FORCEGID].c_value = strdup(val + 1);
 
418
 
 
419
#endif /* FORCE_UIDGID */
 
420
 
 
421
    } else {
 
422
        /* ignore unknown options */
 
423
        LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
 
424
 
 
425
    }
 
426
}
 
427
 
 
428
static int creatvol(const char *path, char *name, struct vol_option *options)
 
429
{
 
430
    struct vol  *volume;
 
431
    int         vlen;
 
432
 
 
433
    if ( name == NULL || *name == '\0' ) {
 
434
        if ((name = strrchr( path, '/' )) == NULL) {
 
435
            return -1;  /* Obviously not a fully qualified path */
 
436
        }
 
437
 
 
438
        /* if you wish to share /, you need to specify a name. */
 
439
        if (*++name == '\0')
 
440
            return -1;
 
441
    }
 
442
 
 
443
    for ( volume = volumes; volume; volume = volume->v_next ) {
 
444
        if ( strcasecmp( volume->v_name, name ) == 0 ) {
 
445
            return -1;  /* Won't be able to access it, anyway... */
 
446
        }
 
447
    }
 
448
 
 
449
    vlen = strlen( name );
 
450
    if ( vlen > AFPVOL_NAMELEN ) {
 
451
        vlen = AFPVOL_NAMELEN;
 
452
        name[AFPVOL_NAMELEN] = '\0';
 
453
    }
 
454
 
 
455
    if (( volume =
 
456
                (struct vol *)calloc(1, sizeof( struct vol ))) == NULL ) {
 
457
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
 
458
        return -1;
 
459
    }
 
460
    if (( volume->v_name =
 
461
                (char *)malloc( vlen + 1 )) == NULL ) {
 
462
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
 
463
        free(volume);
 
464
        return -1;
 
465
    }
 
466
    if (( volume->v_path =
 
467
                (char *)malloc( strlen( path ) + 1 )) == NULL ) {
 
468
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
 
469
        free(volume->v_name);
 
470
        free(volume);
 
471
        return -1;
 
472
    }
 
473
 
 
474
    strcpy( volume->v_name, name);
 
475
    strcpy( volume->v_path, path );
 
476
 
 
477
#ifdef __svr4__
 
478
    volume->v_qfd = -1;
 
479
#endif /* __svr4__ */
 
480
    volume->v_vid = lastvid++;
 
481
    volume->v_lastdid = 17;
 
482
 
 
483
    /* handle options */
 
484
    if (options) {
 
485
        /* should we casefold? */
 
486
        volume->v_casefold = options[VOLOPT_CASEFOLD].i_value;
 
487
 
 
488
        /* shift in some flags */
 
489
        volume->v_flags = options[VOLOPT_FLAGS].i_value;
 
490
 
 
491
        /* read in the code pages */
 
492
        if (options[VOLOPT_CODEPAGE].c_value)
 
493
            codepage_read(volume, options[VOLOPT_CODEPAGE].c_value);
 
494
 
 
495
        if (options[VOLOPT_PASSWORD].c_value)
 
496
            volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
 
497
 
 
498
        if (options[VOLOPT_VETO].c_value)
 
499
            volume->v_veto = strdup(options[VOLOPT_VETO].c_value);
 
500
 
 
501
#ifdef CNID_DB
 
502
        if (options[VOLOPT_DBPATH].c_value)
 
503
            volume->v_dbpath = strdup(options[VOLOPT_DBPATH].c_value);
 
504
#endif /* CNID_DB */
 
505
 
 
506
        if (options[VOLOPT_UMASK].i_value)
 
507
            volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
 
508
 
 
509
#ifdef FORCE_UIDGID
 
510
 
 
511
        if (options[VOLOPT_FORCEUID].c_value) {
 
512
            volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
 
513
        } else {
 
514
            volume->v_forceuid = NULL; /* set as null so as to return 0 later on */
 
515
        }
 
516
 
 
517
        if (options[VOLOPT_FORCEGID].c_value) {
 
518
            volume->v_forcegid = strdup(options[VOLOPT_FORCEGID].c_value);
 
519
        } else {
 
520
            volume->v_forcegid = NULL; /* set as null so as to return 0 later on */
 
521
        }
 
522
 
 
523
#endif /* FORCE_UIDGID */
 
524
 
 
525
    }
 
526
 
 
527
    volume->v_next = volumes;
 
528
    volumes = volume;
 
529
    return 0;
 
530
}
 
531
 
 
532
static char *myfgets( buf, size, fp )
 
533
char    *buf;
 
534
int             size;
 
535
FILE    *fp;
 
536
{
 
537
    char        *p;
 
538
    int         c;
 
539
 
 
540
    p = buf;
 
541
    while ((EOF != ( c = getc( fp )) ) && ( size > 0 )) {
 
542
        if ( c == '\n' || c == '\r' ) {
 
543
            *p++ = '\n';
 
544
            break;
 
545
        } else {
 
546
            *p++ = c;
 
547
        }
 
548
        size--;
 
549
    }
 
550
 
 
551
    if ( p == buf ) {
 
552
        return( NULL );
 
553
    } else {
 
554
        *p = '\0';
 
555
        return( buf );
 
556
    }
 
557
}
 
558
 
 
559
 
 
560
/* check access list. this function wants something of the following
 
561
 * form:
 
562
 *        @group,name,name2,@group2,name3
 
563
 *
 
564
 * a NULL argument allows everybody to have access.
 
565
 * we return three things:
 
566
 *     -1: no list
 
567
 *      0: list exists, but name isn't in it
 
568
 *      1: in list
 
569
 */
 
570
static int accessvol(args, name)
 
571
const char *args;
 
572
const char *name;
 
573
{
 
574
    char buf[MAXPATHLEN + 1], *p;
 
575
    struct group *gr;
 
576
 
 
577
    if (!args)
 
578
        return -1;
 
579
 
 
580
    strncpy(buf, args, sizeof(buf));
 
581
    if ((p = strtok(buf, ",")) == NULL) /* nothing, return okay */
 
582
        return -1;
 
583
 
 
584
    while (p) {
 
585
        if (*p == '@') { /* it's a group */
 
586
            if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid))
 
587
                return 1;
 
588
        } else if (strcmp(p, name) == 0) /* it's a user name */
 
589
            return 1;
 
590
        p = strtok(NULL, ",");
 
591
    }
 
592
 
 
593
    return 0;
 
594
}
 
595
 
 
596
static void setextmap( ext, type, creator, user)
 
597
char            *ext, *type, *creator;
 
598
int                     user;
 
599
{
 
600
    struct extmap       *em;
 
601
    int                 cnt;
 
602
 
 
603
    if (extmap == NULL) {
 
604
        if (( extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
 
605
            LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
 
606
            return;
 
607
        }
 
608
    }
 
609
    ext++;
 
610
    for ( em = extmap, cnt = 0; em->em_ext; em++, cnt++) {
 
611
        if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
 
612
            break;
 
613
        }
 
614
    }
 
615
 
 
616
    if ( em->em_ext == NULL ) {
 
617
        if (!(extmap  = realloc( extmap, sizeof( struct extmap ) * (cnt +2))) ) {
 
618
            LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
 
619
            return;
 
620
        }
 
621
        (extmap +cnt +1)->em_ext = NULL;
 
622
        em = extmap +cnt;
 
623
    } else if ( !user ) {
 
624
        return;
 
625
    }
 
626
    if (em->em_ext)
 
627
        free(em->em_ext);
 
628
 
 
629
    if (!(em->em_ext = strdup(  ext))) {
 
630
        LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) );
 
631
        return;
 
632
    }
 
633
 
 
634
    if ( *type == '\0' ) {
 
635
        memcpy(em->em_type, "????", sizeof( em->em_type ));
 
636
    } else {
 
637
        memcpy(em->em_type, type, sizeof( em->em_type ));
 
638
    }
 
639
    if ( *creator == '\0' ) {
 
640
        memcpy(em->em_creator, "UNIX", sizeof( em->em_creator ));
 
641
    } else {
 
642
        memcpy(em->em_creator, creator, sizeof( em->em_creator ));
 
643
    }
 
644
}
 
645
 
 
646
/* -------------------------- */
 
647
static int extmap_cmp(const void *map1, const void *map2)
 
648
{
 
649
    const struct extmap *em1 = map1;
 
650
    const struct extmap *em2 = map2;
 
651
    return strdiacasecmp(em1->em_ext, em2->em_ext);
 
652
}
 
653
 
 
654
static void sortextmap( void)
 
655
{
 
656
    struct extmap       *em;
 
657
 
 
658
    extmap_cnt = 0;
 
659
    if ((em = extmap) == NULL) {
 
660
        return;
 
661
    }
 
662
    while (em->em_ext) {
 
663
        em++;
 
664
        extmap_cnt++;
 
665
    }
 
666
    if (extmap_cnt) {
 
667
        qsort(extmap, extmap_cnt, sizeof(struct extmap), extmap_cmp);
 
668
        defextmap = extmap;
 
669
    }
 
670
}
 
671
 
 
672
 
 
673
/*
 
674
 * Read a volume configuration file and add the volumes contained within to
 
675
 * the global volume list.  If p2 is non-NULL, the file that is opened is
 
676
 * p1/p2
 
677
 *
 
678
 * Lines that begin with # and blank lines are ignored.
 
679
 * Volume lines are of the form:
 
680
 *              <unix path> [<volume name>] [allow:<user>,<@group>,...] \
 
681
 *                           [codepage:<file>] [casefold:<num>]
 
682
 *              <extension> TYPE [CREATOR]
 
683
 */
 
684
static int readvolfile(obj, p1, p2, user, pwent)
 
685
AFPObj      *obj;
 
686
char    *p1, *p2;
 
687
int             user;
 
688
struct passwd *pwent;
 
689
{
 
690
    FILE                *fp;
 
691
    char                path[ MAXPATHLEN + 1], tmp[ MAXPATHLEN + 1],
 
692
    volname[ AFPVOL_NAMELEN + 1 ], buf[ BUFSIZ ],
 
693
    type[ 5 ], creator[ 5 ];
 
694
    char                *u, *p;
 
695
    struct passwd       *pw;
 
696
    struct vol_option   options[VOLOPT_NUM], save_options[VOLOPT_NUM];
 
697
    int                 i;
 
698
 
 
699
    if (!p1)
 
700
        return -1;
 
701
 
 
702
    strcpy( path, p1 );
 
703
    if ( p2 != NULL ) {
 
704
        strcat( path, "/" );
 
705
        strcat( path, p2 );
 
706
    }
 
707
 
 
708
    if (NULL == ( fp = fopen( path, "r" )) ) {
 
709
        return( -1 );
 
710
    }
 
711
 
 
712
    memset(save_options, 0, sizeof(save_options));
 
713
    while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
 
714
        initline( strlen( buf ), buf );
 
715
        parseline( sizeof( path ) - 1, path );
 
716
        switch ( *path ) {
 
717
        case '\0' :
 
718
        case '#' :
 
719
            continue;
 
720
 
 
721
        case ':':
 
722
            /* change the default options for this file */
 
723
            if (strncmp(path, VOLOPT_DEFAULT, VOLOPT_DEFAULT_LEN) == 0) {
 
724
                *tmp = '\0';
 
725
                for (i = 0; i < VOLOPT_NUM; i++) {
 
726
                    if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1,
 
727
                                   path + VOLOPT_DEFAULT_LEN) < 0)
 
728
                        break;
 
729
                    volset(save_options, tmp, sizeof(tmp) - 1,
 
730
                           obj->options.nlspath, path + VOLOPT_DEFAULT_LEN,
 
731
                           obj, pwent);
 
732
                }
 
733
            }
 
734
            break;
 
735
 
 
736
        case '~' :
 
737
            if (( p = strchr( path, '/' )) != NULL ) {
 
738
                *p++ = '\0';
 
739
            }
 
740
            u = path;
 
741
            u++;
 
742
            if ( *u == '\0' ) {
 
743
                u = obj->username;
 
744
            }
 
745
            if ( u == NULL || *u == '\0' || ( pw = getpwnam( u )) == NULL ) {
 
746
                continue;
 
747
            }
 
748
            strcpy( tmp, pw->pw_dir );
 
749
            if ( p != NULL && *p != '\0' ) {
 
750
                strcat( tmp, "/" );
 
751
                strcat( tmp, p );
 
752
            }
 
753
            /* Tag a user's home directory with their umask.  Note, this will
 
754
             * be overwritten if the user actually specifies a umask: option
 
755
             * for a '~' volume. */
 
756
            save_options[VOLOPT_UMASK].i_value = obj->options.save_mask;
 
757
            /* fall through */
 
758
 
 
759
        case '/' :
 
760
            /* send path through variable substitution */
 
761
            if (*path != '~') /* need to copy path to tmp */
 
762
                strcpy(tmp, path);
 
763
            if (!pwent)
 
764
                pwent = getpwnam(obj->username);
 
765
            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL);
 
766
 
 
767
            /* this is sort of braindead. basically, i want to be
 
768
             * able to specify things in any order, but i don't want to 
 
769
             * re-write everything. 
 
770
             *
 
771
             * currently we have 11 options: 
 
772
             *   volname
 
773
             *   codepage:x
 
774
             *   casefold:x
 
775
             *   allow:x,y,@z
 
776
             *   deny:x,y,@z
 
777
             *   rwlist:x,y,@z
 
778
             *   rolist:x,y,@z
 
779
             *   options:prodos,crlf,noadouble,ro
 
780
             *   dbpath:x
 
781
             *   password:x
 
782
             *   namemask:x,y,!z  (not implemented yet)
 
783
             */
 
784
            memcpy(options, save_options, sizeof(options));
 
785
            *volname = '\0';
 
786
 
 
787
            /* read in up to 11 possible options */
 
788
            for (i = 0; i < VOLOPT_NUM; i++) {
 
789
                if (parseline( sizeof( tmp ) - 1, tmp ) < 0)
 
790
                    break;
 
791
 
 
792
                volset(options, volname, sizeof(volname) - 1,
 
793
                       obj->options.nlspath, tmp, obj, pwent);
 
794
            }
 
795
 
 
796
            /* check allow/deny lists:
 
797
               allow -> either no list (-1), or in list (1)
 
798
               deny -> either no list (-1), or not in list (0) */
 
799
            if (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) &&
 
800
                    (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1)) {
 
801
 
 
802
                /* handle read-only behaviour. semantics:
 
803
                 * 1) neither the rolist nor the rwlist exist -> rw
 
804
                 * 2) rolist exists -> ro if user is in it.
 
805
                 * 3) rwlist exists -> ro unless user is in it. */
 
806
                if (((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0) &&
 
807
                        ((accessvol(options[VOLOPT_ROLIST].c_value,
 
808
                                    obj->username) == 1) ||
 
809
                         !accessvol(options[VOLOPT_RWLIST].c_value,
 
810
                                    obj->username)))
 
811
                    options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
 
812
 
 
813
                /* do variable substitution */
 
814
                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path);
 
815
                creatvol(path, tmp, options);
 
816
            }
 
817
            volfree(options, save_options);
 
818
            break;
 
819
 
 
820
        case '.' :
 
821
            parseline( sizeof( type ) - 1, type );
 
822
            parseline( sizeof( creator ) - 1, creator );
 
823
            setextmap( path, type, creator, user);
 
824
            break;
 
825
 
 
826
        default :
 
827
            break;
 
828
        }
 
829
    }
 
830
    volfree(save_options, NULL);
 
831
    sortextmap();
 
832
    if ( fclose( fp ) != 0 ) {
 
833
        LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
 
834
    }
 
835
    return( 0 );
 
836
}
 
837
 
 
838
 
 
839
static void load_volumes(AFPObj *obj)
 
840
{
 
841
    struct passwd       *pwent = getpwnam(obj->username);
 
842
 
 
843
    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
 
844
        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent);
 
845
    }
 
846
 
 
847
    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
 
848
        readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent);
 
849
    } else if (pwent) {
 
850
        /*
 
851
        * Read user's AppleVolumes or .AppleVolumes file
 
852
        * If neither are readable, read the default volumes file. if
 
853
        * that doesn't work, create a user share.
 
854
        */
 
855
        if ( readvolfile(obj, pwent->pw_dir, "AppleVolumes", 1, pwent) < 0 &&
 
856
                readvolfile(obj, pwent->pw_dir, ".AppleVolumes", 1, pwent) < 0 &&
 
857
                readvolfile(obj, pwent->pw_dir, "applevolumes", 1, pwent) < 0 &&
 
858
                readvolfile(obj, pwent->pw_dir, ".applevolumes", 1, pwent) < 0 &&
 
859
                obj->options.defaultvol != NULL ) {
 
860
            if (readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent) < 0)
 
861
                creatvol(pwent->pw_dir, NULL, NULL);
 
862
        }
 
863
    }
 
864
    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
 
865
        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent );
 
866
    }
 
867
}
 
868
 
 
869
static int getvolspace( vol, bfree, btotal, xbfree, xbtotal, bsize )
 
870
struct vol      *vol;
 
871
u_int32_t       *bfree, *btotal, *bsize;
 
872
VolSpace    *xbfree, *xbtotal;
 
873
{
 
874
    int         spaceflag, rc;
 
875
    u_int32_t   maxsize;
 
876
#ifndef NO_QUOTA_SUPPORT
 
877
    VolSpace    qfree, qtotal;
 
878
#endif /* ! NO_QUOTA_SUPPORT */
 
879
 
 
880
    spaceflag = AFPVOL_GVSMASK & vol->v_flags;
 
881
    /* report up to 2GB if afp version is < 2.2 (4GB if not) */
 
882
    maxsize = (vol->v_flags & AFPVOL_A2VOL) ? 0x01fffe00 :
 
883
              (((afp_version < 22) || (vol->v_flags & AFPVOL_LIMITSIZE))
 
884
               ? 0x7fffffffL : 0xffffffffL);
 
885
 
 
886
#ifdef AFS
 
887
    if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) {
 
888
        if ( afs_getvolspace( vol, xbfree, xbtotal, bsize ) == AFP_OK ) {
 
889
            vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_AFSGVS;
 
890
            goto getvolspace_done;
 
891
        }
 
892
    }
 
893
#endif /* AFS */
 
894
 
 
895
    if (( rc = ustatfs_getvolspace( vol, xbfree, xbtotal,
 
896
                                    bsize)) != AFP_OK ) {
 
897
        return( rc );
 
898
    }
 
899
 
 
900
#define min(a,b)        ((a)<(b)?(a):(b))
 
901
#ifndef NO_QUOTA_SUPPORT
 
902
    if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_UQUOTA ) {
 
903
        if ( uquota_getvolspace( vol, &qfree, &qtotal, *bsize ) == AFP_OK ) {
 
904
            vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_UQUOTA;
 
905
            *xbfree = min(*xbfree, qfree);
 
906
            *xbtotal = min( *xbtotal, qtotal);
 
907
            goto getvolspace_done;
 
908
        }
 
909
    }
 
910
#endif /* ! NO_QUOTA_SUPPORT */
 
911
    vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_USTATFS;
 
912
 
 
913
getvolspace_done:
 
914
    *bfree = min( *xbfree, maxsize);
 
915
    *btotal = min( *xbtotal, maxsize);
 
916
    return( AFP_OK );
 
917
}
 
918
 
 
919
static int getvolparams( bitmap, vol, st, buf, buflen )
 
920
u_int16_t       bitmap;
 
921
struct vol      *vol;
 
922
struct stat     *st;
 
923
char    *buf;
 
924
int             *buflen;
 
925
{
 
926
    struct adouble      ad;
 
927
    int                 bit = 0, isad = 1;
 
928
    u_int32_t           aint;
 
929
    u_short             ashort;
 
930
    u_int32_t           bfree, btotal, bsize;
 
931
    VolSpace            xbfree, xbtotal; /* extended bytes */
 
932
    char                *data, *nameoff = NULL;
 
933
    char                *slash;
 
934
 
 
935
    /* courtesy of jallison@whistle.com:
 
936
     * For MacOS8.x support we need to create the
 
937
     * .Parent file here if it doesn't exist. */
 
938
 
 
939
    memset(&ad, 0, sizeof(ad));
 
940
    if ( ad_open( vol->v_path, vol_noadouble(vol) |
 
941
                  ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT,
 
942
                  0666, &ad) < 0 ) {
 
943
        isad = 0;
 
944
 
 
945
    } else if (ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT) {
 
946
        slash = strrchr( vol->v_path, '/' );
 
947
        if(slash)
 
948
            slash++;
 
949
        else
 
950
            slash = vol->v_path;
 
951
 
 
952
        ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
 
953
        memcpy(ad_entry( &ad, ADEID_NAME ), slash,
 
954
               ad_getentrylen( &ad, ADEID_NAME ));
 
955
        ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st->st_mtime);
 
956
        ad_flush(&ad, ADFLAGS_HF);
 
957
    }
 
958
 
 
959
    if (( bitmap & ( (1<<VOLPBIT_BFREE)|(1<<VOLPBIT_BTOTAL) |
 
960
                     (1<<VOLPBIT_XBFREE)|(1<<VOLPBIT_XBTOTAL) |
 
961
                     (1<<VOLPBIT_BSIZE)) ) != 0 ) {
 
962
        if ( getvolspace( vol, &bfree, &btotal, &xbfree, &xbtotal,
 
963
                          &bsize) < 0 ) {
 
964
            if ( isad ) {
 
965
                ad_close( &ad, ADFLAGS_HF );
 
966
            }
 
967
            return( AFPERR_PARAM );
 
968
        }
 
969
    }
 
970
 
 
971
    data = buf;
 
972
    while ( bitmap != 0 ) {
 
973
        while (( bitmap & 1 ) == 0 ) {
 
974
            bitmap = bitmap>>1;
 
975
            bit++;
 
976
        }
 
977
 
 
978
        switch ( bit ) {
 
979
        case VOLPBIT_ATTR :
 
980
            ashort = 0;
 
981
#ifdef CNID_DB
 
982
            if (0 == (vol->v_flags & AFPVOL_NOFILEID)) {
 
983
                ashort = VOLPBIT_ATTR_FILEID;
 
984
            }
 
985
#endif /* CNID_DB */
 
986
            /* check for read-only.
 
987
             * NOTE: we don't actually set the read-only flag unless
 
988
             *       it's passed in that way as it's possible to mount
 
989
             *       a read-write filesystem under a read-only one. */
 
990
            if ((vol->v_flags & AFPVOL_RO) ||
 
991
                    ((utime(vol->v_path, NULL) < 0) && (errno == EROFS)))
 
992
                ashort |= VOLPBIT_ATTR_RO;
 
993
                ashort |= VOLPBIT_ATTR_CATSEARCH;
 
994
            ashort = htons(ashort);
 
995
            memcpy(data, &ashort, sizeof( ashort ));
 
996
            data += sizeof( ashort );
 
997
            break;
 
998
 
 
999
        case VOLPBIT_SIG :
 
1000
            ashort = htons( AFPVOLSIG_DEFAULT );
 
1001
            memcpy(data, &ashort, sizeof( ashort ));
 
1002
            data += sizeof( ashort );
 
1003
            break;
 
1004
 
 
1005
        case VOLPBIT_CDATE :
 
1006
            if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
 
1007
                aint = AD_DATE_FROM_UNIX(st->st_mtime);
 
1008
            memcpy(data, &aint, sizeof( aint ));
 
1009
            data += sizeof( aint );
 
1010
            break;
 
1011
 
 
1012
        case VOLPBIT_MDATE :
 
1013
            if ( st->st_mtime > vol->v_time ) {
 
1014
                vol->v_time = st->st_mtime;
 
1015
                aint = AD_DATE_FROM_UNIX(st->st_mtime);
 
1016
            } else {
 
1017
                aint = AD_DATE_FROM_UNIX(vol->v_time);
 
1018
            }
 
1019
            memcpy(data, &aint, sizeof( aint ));
 
1020
            data += sizeof( aint );
 
1021
            break;
 
1022
 
 
1023
        case VOLPBIT_BDATE :
 
1024
            if (!isad ||  (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
 
1025
                aint = AD_DATE_START;
 
1026
            memcpy(data, &aint, sizeof( aint ));
 
1027
            data += sizeof( aint );
 
1028
            break;
 
1029
 
 
1030
        case VOLPBIT_VID :
 
1031
            memcpy(data, &vol->v_vid, sizeof( vol->v_vid ));
 
1032
            data += sizeof( vol->v_vid );
 
1033
            break;
 
1034
 
 
1035
        case VOLPBIT_BFREE :
 
1036
            bfree = htonl( bfree );
 
1037
            memcpy(data, &bfree, sizeof( bfree ));
 
1038
            data += sizeof( bfree );
 
1039
            break;
 
1040
 
 
1041
        case VOLPBIT_BTOTAL :
 
1042
            btotal = htonl( btotal );
 
1043
            memcpy(data, &btotal, sizeof( btotal ));
 
1044
            data += sizeof( btotal );
 
1045
            break;
 
1046
 
 
1047
#ifndef NO_LARGE_VOL_SUPPORT
 
1048
        case VOLPBIT_XBFREE :
 
1049
            xbfree = hton64( xbfree );
 
1050
#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
 
1051
            bcopy(&xbfree, data, sizeof(xbfree));
 
1052
#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1053
            memcpy(data, &xbfree, sizeof( xbfree ));
 
1054
#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1055
            data += sizeof( xbfree );
 
1056
            break;
 
1057
 
 
1058
        case VOLPBIT_XBTOTAL :
 
1059
            xbtotal = hton64( xbtotal );
 
1060
#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
 
1061
            bcopy(&xbtotal, data, sizeof(xbtotal));
 
1062
#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1063
            memcpy(data, &xbtotal, sizeof( xbtotal ));
 
1064
#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1065
            data += sizeof( xbfree );
 
1066
            break;
 
1067
#endif /* ! NO_LARGE_VOL_SUPPORT */
 
1068
 
 
1069
        case VOLPBIT_NAME :
 
1070
            nameoff = data;
 
1071
            data += sizeof( u_int16_t );
 
1072
            break;
 
1073
 
 
1074
        case VOLPBIT_BSIZE:  /* block size */
 
1075
            bsize = htonl(bsize);
 
1076
            memcpy(data, &bsize, sizeof(bsize));
 
1077
            data += sizeof(bsize);
 
1078
            break;
 
1079
 
 
1080
        default :
 
1081
            if ( isad ) {
 
1082
                ad_close( &ad, ADFLAGS_HF );
 
1083
            }
 
1084
            return( AFPERR_BITMAP );
 
1085
        }
 
1086
        bitmap = bitmap>>1;
 
1087
        bit++;
 
1088
    }
 
1089
    if ( nameoff ) {
 
1090
        ashort = htons( data - buf );
 
1091
        memcpy(nameoff, &ashort, sizeof( ashort ));
 
1092
        aint = strlen( vol->v_name );
 
1093
        *data++ = aint;
 
1094
        memcpy(data, vol->v_name, aint );
 
1095
        data += aint;
 
1096
    }
 
1097
    if ( isad ) {
 
1098
        ad_close( &ad, ADFLAGS_HF );
 
1099
    }
 
1100
    *buflen = data - buf;
 
1101
    return( AFP_OK );
 
1102
}
 
1103
 
 
1104
 
 
1105
 
 
1106
int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1107
AFPObj      *obj;
 
1108
char    *ibuf, *rbuf;
 
1109
int     ibuflen, *rbuflen;
 
1110
{
 
1111
    struct timeval      tv;
 
1112
    struct stat         st;
 
1113
    struct vol          *volume;
 
1114
    char        *data;
 
1115
    int                 vcnt, len;
 
1116
 
 
1117
 
 
1118
    if (!volumes)
 
1119
        load_volumes(obj);
 
1120
 
 
1121
    data = rbuf + 5;
 
1122
    for ( vcnt = 0, volume = volumes; volume; volume = volume->v_next ) {
 
1123
        if ( stat( volume->v_path, &st ) < 0 ) {
 
1124
            LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
 
1125
                volume->v_path, strerror(errno) );
 
1126
            continue;           /* can't access directory */
 
1127
        }
 
1128
        if (!S_ISDIR(st.st_mode)) {
 
1129
            continue;           /* not a dir */
 
1130
        }
 
1131
 
 
1132
        /* set password bit if there's a volume password */
 
1133
        *data = (volume->v_password) ? AFPSRVR_PASSWD : 0;
 
1134
 
 
1135
        /* Apple 2 clients running ProDOS-8 expect one volume to have
 
1136
           bit 0 of this byte set.  They will not recognize anything
 
1137
           on the server unless this is the case.  I have not
 
1138
           completely worked this out, but it's related to booting
 
1139
           from the server.  Support for that function is a ways
 
1140
           off.. <shirsch@ibm.net> */
 
1141
        *data++ |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0;
 
1142
        len = strlen( volume->v_name );
 
1143
        *data++ = len;
 
1144
        memcpy(data, volume->v_name, len );
 
1145
        data += len;
 
1146
        vcnt++;
 
1147
    }
 
1148
 
 
1149
    *rbuflen = data - rbuf;
 
1150
    data = rbuf;
 
1151
    if ( gettimeofday( &tv, 0 ) < 0 ) {
 
1152
        LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
 
1153
        *rbuflen = 0;
 
1154
        return AFPERR_PARAM;
 
1155
    }
 
1156
    tv.tv_sec = AD_DATE_FROM_UNIX(tv.tv_sec);
 
1157
    memcpy(data, &tv.tv_sec, sizeof( u_int32_t));
 
1158
    data += sizeof( u_int32_t);
 
1159
    *data = vcnt;
 
1160
    return( AFP_OK );
 
1161
}
 
1162
 
 
1163
int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1164
AFPObj      *obj;
 
1165
char    *ibuf, *rbuf;
 
1166
int             ibuflen, *rbuflen;
 
1167
{
 
1168
    struct stat st;
 
1169
    char        *volname;
 
1170
#ifndef CNID_DB
 
1171
    char *p;
 
1172
#endif /* CNID_DB */
 
1173
    struct vol  *volume;
 
1174
    struct dir  *dir;
 
1175
    int         len, ret, buflen;
 
1176
    u_int16_t   bitmap;
 
1177
 
 
1178
    ibuf += 2;
 
1179
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
 
1180
    bitmap = ntohs( bitmap );
 
1181
    ibuf += sizeof( bitmap );
 
1182
    if (( bitmap & (1<<VOLPBIT_VID)) == 0 ) {
 
1183
        ret = AFPERR_BITMAP;
 
1184
        goto openvol_err;
 
1185
    }
 
1186
 
 
1187
    len = (unsigned char)*ibuf++;
 
1188
    volname = obj->oldtmp;
 
1189
    memcpy(volname, ibuf, len );
 
1190
    *(volname +  len) = '\0';
 
1191
    ibuf += len;
 
1192
    if ((len + 1) & 1) /* pad to an even boundary */
 
1193
        ibuf++;
 
1194
 
 
1195
    if (!volumes)
 
1196
        load_volumes(obj);
 
1197
 
 
1198
    for ( volume = volumes; volume; volume = volume->v_next ) {
 
1199
        if ( strcasecmp( volname, volume->v_name ) == 0 ) {
 
1200
            break;
 
1201
        }
 
1202
    }
 
1203
 
 
1204
    if ( volume == NULL ) {
 
1205
        ret = AFPERR_PARAM;
 
1206
        goto openvol_err;
 
1207
    }
 
1208
 
 
1209
    /* check for a volume password */
 
1210
    if (volume->v_password &&
 
1211
            strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
 
1212
        ret = AFPERR_ACCESS;
 
1213
        goto openvol_err;
 
1214
    }
 
1215
 
 
1216
    if (( volume->v_flags & AFPVOL_OPEN  ) == 0 ) {
 
1217
        if ((dir = dirnew(strlen(volume->v_name) + 1)) == NULL) {
 
1218
            LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
 
1219
            ret = AFPERR_MISC;
 
1220
            goto openvol_err;
 
1221
        }
 
1222
        dir->d_did = DIRDID_ROOT;
 
1223
        dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
 
1224
        strcpy( dir->d_name, volume->v_name );
 
1225
        volume->v_dir = volume->v_root = dir;
 
1226
        volume->v_flags |= AFPVOL_OPEN;
 
1227
    }
 
1228
#ifdef FORCE_UIDGID
 
1229
    set_uidgid ( volume );
 
1230
#endif /* FORCE_UIDGID */
 
1231
 
 
1232
    if ( stat( volume->v_path, &st ) < 0 ) {
 
1233
        ret = AFPERR_PARAM;
 
1234
        goto openvol_err;
 
1235
    }
 
1236
 
 
1237
    buflen = *rbuflen - sizeof( bitmap );
 
1238
    if (( ret = getvolparams( bitmap, volume, &st,
 
1239
                              rbuf + sizeof(bitmap), &buflen )) != AFP_OK ) {
 
1240
        goto openvol_err;
 
1241
    }
 
1242
    *rbuflen = buflen + sizeof( bitmap );
 
1243
    bitmap = htons( bitmap );
 
1244
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
 
1245
 
 
1246
    if ( chdir( volume->v_path ) < 0 ) {
 
1247
        ret = AFPERR_PARAM;
 
1248
        goto openvol_err;
 
1249
    }
 
1250
    curdir = volume->v_dir;
 
1251
 
 
1252
#ifdef CNID_DB
 
1253
    if (volume->v_dbpath)
 
1254
        volume->v_db = cnid_open (volume->v_dbpath, volume->v_umask);
 
1255
    if (volume->v_db == NULL)
 
1256
        volume->v_db = cnid_open (volume->v_path, volume->v_umask);
 
1257
#endif /* CNID_DB */
 
1258
 
 
1259
#ifndef CNID_DB
 
1260
    /*
 
1261
     * If you mount a volume twice, the second time the trash appears on
 
1262
     * the desk-top.  That's because the Mac remembers the DID for the
 
1263
     * trash (even for volumes in different zones, on different servers).
 
1264
     * Just so this works better, we prime the DID cache with the trash,
 
1265
     * fixing the trash at DID 17.
 
1266
     */
 
1267
    p = Trash;
 
1268
    cname( volume, volume->v_dir, &p );
 
1269
#endif /* CNID_DB */
 
1270
 
 
1271
    return( AFP_OK );
 
1272
 
 
1273
openvol_err:
 
1274
    *rbuflen = 0;
 
1275
    return ret;
 
1276
}
 
1277
 
 
1278
int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1279
AFPObj      *obj;
 
1280
char    *ibuf, *rbuf;
 
1281
int             ibuflen, *rbuflen;
 
1282
{
 
1283
    struct vol  *vol, *ovol;
 
1284
    u_int16_t   vid;
 
1285
 
 
1286
    *rbuflen = 0;
 
1287
    ibuf += 2;
 
1288
    memcpy(&vid, ibuf, sizeof( vid ));
 
1289
    if (NULL == ( vol = getvolbyvid( vid )) ) {
 
1290
        return( AFPERR_PARAM );
 
1291
    }
 
1292
 
 
1293
    vol->v_flags &= ~AFPVOL_OPEN;
 
1294
    for ( ovol = volumes; ovol; ovol = ovol->v_next ) {
 
1295
        if ( ovol->v_flags & AFPVOL_OPEN ) {
 
1296
            break;
 
1297
        }
 
1298
    }
 
1299
    if ( ovol != NULL ) {
 
1300
        /* Even if chdir fails, we can't say afp_closevol fails. */
 
1301
        if ( chdir( ovol->v_path ) == 0 ) {
 
1302
            curdir = ovol->v_dir;
 
1303
        }
 
1304
    }
 
1305
    dirfree( vol->v_root );
 
1306
    vol->v_dir = NULL;
 
1307
#ifdef CNID_DB
 
1308
    cnid_close(vol->v_db);
 
1309
    vol->v_db = NULL;
 
1310
#endif /* CNID_DB */
 
1311
    return( AFP_OK );
 
1312
}
 
1313
 
 
1314
struct vol *getvolbyvid(const u_int16_t vid )
 
1315
{
 
1316
    struct vol  *vol;
 
1317
 
 
1318
    for ( vol = volumes; vol; vol = vol->v_next ) {
 
1319
        if ( vid == vol->v_vid ) {
 
1320
            break;
 
1321
        }
 
1322
    }
 
1323
    if ( vol == NULL || ( vol->v_flags & AFPVOL_OPEN ) == 0 ) {
 
1324
        return( NULL );
 
1325
    }
 
1326
 
 
1327
#ifdef FORCE_UIDGID
 
1328
    set_uidgid ( vol );
 
1329
#endif /* FORCE_UIDGID */
 
1330
 
 
1331
    return( vol );
 
1332
}
 
1333
 
 
1334
/* ------------------------ */
 
1335
static int ext_cmp_key(const void *key, const void *obj)
 
1336
{
 
1337
    const char          *p = key;
 
1338
    const struct extmap *em = obj;
 
1339
    return strdiacasecmp(p, em->em_ext);
 
1340
}
 
1341
struct extmap *getextmap(const char *path)
 
1342
{
 
1343
    char          *p;
 
1344
    struct extmap *em;
 
1345
 
 
1346
    if (NULL == ( p = strrchr( path, '.' )) ) {
 
1347
        return( defextmap );
 
1348
    }
 
1349
    p++;
 
1350
    if (!*p || !extmap_cnt) {
 
1351
        return( defextmap );
 
1352
    }
 
1353
    em = bsearch(p, extmap, extmap_cnt, sizeof(struct extmap), ext_cmp_key);
 
1354
    if (em) {
 
1355
        return( em );
 
1356
    } else {
 
1357
        return( defextmap );
 
1358
    }
 
1359
}
 
1360
 
 
1361
struct extmap *getdefextmap(void)
 
1362
{
 
1363
    return( defextmap );
 
1364
}
 
1365
 
 
1366
/*
 
1367
   poll if a volume is changed by other processes.
 
1368
*/
 
1369
int  pollvoltime(obj)
 
1370
AFPObj *obj;
 
1371
{
 
1372
    struct vol       *vol;
 
1373
    struct timeval   tv;
 
1374
    struct stat      st;
 
1375
    
 
1376
    if (!(afp_version > 21 && obj->options.server_notif)) 
 
1377
         return 0;
 
1378
 
 
1379
    if ( gettimeofday( &tv, 0 ) < 0 ) 
 
1380
         return 0;
 
1381
 
 
1382
    for ( vol = volumes; vol; vol = vol->v_next ) {
 
1383
        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_time + 30 < tv.tv_sec) {
 
1384
            if ( !stat( vol->v_path, &st ) && vol->v_time != st.st_mtime ) {
 
1385
                vol->v_time = st.st_mtime;
 
1386
                obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
 
1387
                return 1;
 
1388
            }
 
1389
        }
 
1390
    }
 
1391
    return 0;
 
1392
}
 
1393
 
 
1394
void setvoltime(obj, vol )
 
1395
AFPObj *obj;
 
1396
struct vol      *vol;
 
1397
{
 
1398
    struct timeval      tv;
 
1399
 
 
1400
    /* just looking at vol->v_time is broken seriously since updates
 
1401
     * from other users afpd processes never are seen.
 
1402
     * This is not the most elegant solution (a shared memory between
 
1403
     * the afpd processes would come closer)
 
1404
     * [RS] */
 
1405
 
 
1406
    if ( gettimeofday( &tv, 0 ) < 0 ) {
 
1407
        LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
 
1408
        return;
 
1409
    }
 
1410
    if( utime( vol->v_path, NULL ) < 0 ) {
 
1411
        /* write of time failed ... probably a read only filesys,
 
1412
         * where no other users can interfere, so there's no issue here
 
1413
         */
 
1414
    }
 
1415
 
 
1416
    /* a little granularity */
 
1417
    if (vol->v_time < tv.tv_sec) {
 
1418
        vol->v_time = tv.tv_sec;
 
1419
        if (afp_version > 21 && obj->options.server_notif) {
 
1420
            obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
 
1421
        }
 
1422
    }
 
1423
}
 
1424
 
 
1425
int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1426
AFPObj      *obj;
 
1427
char    *ibuf, *rbuf;
 
1428
int             ibuflen, *rbuflen;
 
1429
{
 
1430
    struct stat st;
 
1431
    struct vol  *vol;
 
1432
    int         buflen, ret;
 
1433
    u_int16_t   vid, bitmap;
 
1434
 
 
1435
    ibuf += 2;
 
1436
    memcpy(&vid, ibuf, sizeof( vid ));
 
1437
    ibuf += sizeof( vid );
 
1438
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
 
1439
    bitmap = ntohs( bitmap );
 
1440
 
 
1441
    if (NULL == ( vol = getvolbyvid( vid )) ) {
 
1442
        *rbuflen = 0;
 
1443
        return( AFPERR_PARAM );
 
1444
    }
 
1445
 
 
1446
    if ( stat( vol->v_path, &st ) < 0 ) {
 
1447
        *rbuflen = 0;
 
1448
        return( AFPERR_PARAM );
 
1449
    }
 
1450
 
 
1451
    buflen = *rbuflen - sizeof( bitmap );
 
1452
    if (( ret = getvolparams( bitmap, vol, &st,
 
1453
                              rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
 
1454
        *rbuflen = 0;
 
1455
        return( ret );
 
1456
    }
 
1457
    *rbuflen = buflen + sizeof( bitmap );
 
1458
    bitmap = htons( bitmap );
 
1459
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
 
1460
    return( AFP_OK );
 
1461
}
 
1462
 
 
1463
int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1464
AFPObj      *obj;
 
1465
char    *ibuf, *rbuf;
 
1466
int             ibuflen, *rbuflen;
 
1467
{
 
1468
    struct adouble ad;
 
1469
    struct vol  *vol;
 
1470
    u_int16_t   vid, bitmap;
 
1471
    u_int32_t   aint;
 
1472
 
 
1473
    ibuf += 2;
 
1474
    *rbuflen = 0;
 
1475
 
 
1476
    memcpy(&vid, ibuf, sizeof( vid ));
 
1477
    ibuf += sizeof( vid );
 
1478
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
 
1479
    bitmap = ntohs( bitmap );
 
1480
    ibuf += sizeof(bitmap);
 
1481
 
 
1482
    if (( vol = getvolbyvid( vid )) == NULL ) {
 
1483
        return( AFPERR_PARAM );
 
1484
    }
 
1485
 
 
1486
    if (vol->v_flags & AFPVOL_RO)
 
1487
        return AFPERR_VLOCK;
 
1488
 
 
1489
    /* we can only set the backup date. */
 
1490
    if (bitmap != VOLPBIT_BDATE)
 
1491
        return AFPERR_BITMAP;
 
1492
 
 
1493
    memset(&ad, 0, sizeof(ad));
 
1494
    if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR,
 
1495
                  0666, &ad) < 0 ) {
 
1496
        if (errno == EROFS)
 
1497
            return AFPERR_VLOCK;
 
1498
 
 
1499
        return AFPERR_ACCESS;
 
1500
    }
 
1501
 
 
1502
    memcpy(&aint, ibuf, sizeof(aint));
 
1503
    ad_setdate(&ad, AD_DATE_BACKUP, aint);
 
1504
    ad_flush(&ad, ADFLAGS_HF);
 
1505
    ad_close(&ad, ADFLAGS_HF);
 
1506
    return( AFP_OK );
 
1507
}
 
1508
 
 
1509
 
 
1510
int wincheck(const struct vol *vol, const char *path)
 
1511
{
 
1512
    int len;
 
1513
 
 
1514
    if (!(vol->v_flags & AFPVOL_MSWINDOWS))
 
1515
        return 1;
 
1516
 
 
1517
    /* empty paths are not allowed */
 
1518
    if ((len = strlen(path)) == 0)
 
1519
        return 0;
 
1520
 
 
1521
    /* leading or trailing whitespaces are not allowed, carriage returns
 
1522
     * and probably other whitespace is okay, tabs are not allowed
 
1523
     */
 
1524
    if ((path[0] == ' ') || (path[len-1] == ' '))
 
1525
        return 0;
 
1526
 
 
1527
    /* certain characters are not allowed */
 
1528
    if (strpbrk(path, MSWINDOWS_BADCHARS))
 
1529
        return 0;
 
1530
 
 
1531
    /* everything else is okay */
 
1532
    return 1;
 
1533
}