X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=243e7498c0edb2eaa734c78d290c9faf71c1db78;hb=29802be7a2e8f704585fe1210a288b041922efff;hp=57d6d1483cd7dae54569a2b15f67bb5c554471fe;hpb=d6aad9f4b9c9682a9bb47bd237008e0288aee892;p=netatalk.git diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 57d6d148..243e7498 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.51.2.7.2.31 2004-06-09 01:15:21 bfernhomberg Exp $ + * $Id: volume.c,v 1.51.2.7.2.33.2.24 2009-03-26 11:53:32 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -114,12 +114,16 @@ m=u -> map both ways #define VOLOPT_FORCEUID 19 /* force uid for username x */ #define VOLOPT_FORCEGID 20 /* force gid for group x */ -#define VOLOPT_UMASK 21 -#else -#define VOLOPT_UMASK 19 #endif /* FORCE_UIDGID */ -#define VOLOPT_MAX (VOLOPT_UMASK +1) +#define VOLOPT_UMASK 21 +#define VOLOPT_ALLOWED_HOSTS 22 +#define VOLOPT_DENIED_HOSTS 23 +#define VOLOPT_DPERM 24 /* dperm default directories perms */ +#define VOLOPT_FPERM 25 /* fperm default files perms */ +#define VOLOPT_DFLTPERM 26 /* perm */ + +#define VOLOPT_MAX (VOLOPT_DFLTPERM +1) #define VOLOPT_NUM (VOLOPT_MAX + 1) @@ -169,6 +173,8 @@ static const _vol_opt_name vol_opt_names[] = { * maybe because it will be mounted later in preexec */ {AFPVOL_UNIX_PRIV, "UNIXPRIV"}, /* support unix privileges */ {AFPVOL_NODEV, "NODEV"}, /* always use 0 for device number in cnid calls */ + {AFPVOL_EILSEQ, "ILLEGALSEQ"}, /* encode illegal sequence */ + {AFPVOL_CACHE, "CACHEID"}, /* Use adouble v2 CNID caching, default don't use it */ {0, NULL} }; @@ -183,7 +189,7 @@ static const _vol_opt_name vol_opt_casefold[] = { static void handle_special_folders (const struct vol *); static int savevoloptions (const struct vol *); -static __inline__ void volfree(struct vol_option *options, +static void volfree(struct vol_option *options, const struct vol_option *save) { int i; @@ -242,7 +248,7 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, return ret; /* first part of the path. just forward to the next variable. */ - len = MIN(p - src, destlen); + len = MIN((size_t)(p - src), destlen); if (len > 0) { destlen -= len; dest += len; @@ -338,7 +344,7 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, /* stuff up to next $ */ src = p + 2; p = strchr(src, '$'); - len = p ? MIN(p - src, destlen) : destlen; + len = p ? MIN((size_t)(p - src), destlen) : destlen; if (len > 0) { strncpy(dest, src, len); dest += len; @@ -449,6 +455,8 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX; else if (strcasecmp(p, "usedots") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS; + else if (strcasecmp(p, "invisibledots") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS | AFPVOL_INV_DOTS; else if (strcasecmp(p, "limitsize") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_LIMITSIZE; /* support for either "dropbox" or "dropkludge" */ @@ -468,6 +476,10 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV; else if (strcasecmp(p, "nodev") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV; + else if (strcasecmp(p, "illegalseq") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ; + else if (strcasecmp(p, "cachecnid") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE; p = strtok(NULL, ","); } @@ -476,7 +488,13 @@ static void volset(struct vol_option *options, struct vol_option *save, setoption(options, save, VOLOPT_DBPATH, val); } else if (optionok(tmp, "umask:", val)) { - options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8); + options[VOLOPT_UMASK].i_value = (int)strtol(val +1, NULL, 8); + } else if (optionok(tmp, "dperm:", val)) { + options[VOLOPT_DPERM].i_value = (int)strtol(val+1, NULL, 8); + } else if (optionok(tmp, "fperm:", val)) { + options[VOLOPT_FPERM].i_value = (int)strtol(val+1, NULL, 8); + } else if (optionok(tmp, "perm:", val)) { + options[VOLOPT_DFLTPERM].i_value = (int)strtol(val+1, NULL, 8); } else if (optionok(tmp, "mapchars:",val)) { setoption(options, save, VOLOPT_MAPCHARS, val); @@ -504,6 +522,12 @@ static void volset(struct vol_option *options, struct vol_option *save, } else if (optionok(tmp, "postexec:", val)) { setoption(options, save, VOLOPT_POSTEXEC, val); + } else if (optionok(tmp, "allowed_hosts:", val)) { + setoption(options, save, VOLOPT_ALLOWED_HOSTS, val); + + } else if (optionok(tmp, "denied_hosts:", val)) { + setoption(options, save, VOLOPT_DENIED_HOSTS, val); + } else { /* ignore unknown options */ LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp); @@ -526,16 +550,24 @@ static void showvol(const ucs2_t *name) /* ----------------- * FIXME should be define elsewhere */ +static int netatalk_name(const char *name) +{ + return strcasecmp(name,".AppleDB") && + strcasecmp(name,".AppleDouble") && + strcasecmp(name,".AppleDesktop"); +} + static int validupath_adouble(const struct vol *vol, const char *name) { - return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent") - : name[0] != '.'; + return (vol->v_flags & AFPVOL_USEDOTS) ? + netatalk_name(name) && strcasecmp(name,".Parent"): name[0] != '.'; } /* ----------------- */ -static int validupath_osx(const struct vol *vol, const char *name) +static int validupath_osx(const struct vol *vol _U_, const char *name) { - return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2); + return strncmp(name,"._", 2) && ( + (vol->v_flags & AFPVOL_USEDOTS) ? netatalk_name(name): name[0] != '.'); } /* ---------------- */ @@ -628,6 +660,16 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, /* shift in some flags */ volume->v_flags = options[VOLOPT_FLAGS].i_value; + volume->v_ad_options = 0; + if ((volume->v_flags & AFPVOL_NODEV)) + volume->v_ad_options |= ADVOL_NODEV; + if ((volume->v_flags & AFPVOL_CACHE)) + volume->v_ad_options |= ADVOL_CACHE; + if ((volume->v_flags & AFPVOL_UNIX_PRIV)) + volume->v_ad_options |= ADVOL_UNIXPRIV; + if ((volume->v_flags & AFPVOL_INV_DOTS)) + volume->v_ad_options |= ADVOL_INVDOTS; + if (options[VOLOPT_PASSWORD].c_value) volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value); @@ -649,11 +691,19 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if (options[VOLOPT_UMASK].i_value) volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value; + if (options[VOLOPT_DPERM].i_value) + volume->v_dperm = (mode_t)options[VOLOPT_DPERM].i_value; + + if (options[VOLOPT_FPERM].i_value) + volume->v_fperm = (mode_t)options[VOLOPT_FPERM].i_value; + + if (options[VOLOPT_DFLTPERM].i_value) + volume->v_perm = (mode_t)options[VOLOPT_DFLTPERM].i_value; + if (options[VOLOPT_ADOUBLE].i_value) volume->v_adouble = options[VOLOPT_ADOUBLE].i_value; else volume->v_adouble = AD_VERSION; - initvoladouble(volume); #ifdef FORCE_UIDGID if (options[VOLOPT_FORCEUID].c_value) { volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value); @@ -683,7 +733,10 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path, name); } } + volume->v_dperm |= volume->v_perm; + volume->v_fperm |= volume->v_perm; + initvoladouble(volume); volume->v_next = Volumes; Volumes = volume; return 0; @@ -699,8 +752,13 @@ FILE *fp; int c; p = buf; - while ((EOF != ( c = getc( fp )) ) && ( size > 0 )) { + while ((EOF != ( c = getc( fp )) ) && ( size > 1 )) { if ( c == '\n' || c == '\r' ) { + if (p != buf && *(p -1) == '\\') { + p--; + size++; + continue; + } *p++ = '\n'; break; } else { @@ -766,6 +824,55 @@ const char *name; return 0; } +static int hostaccessvol(type, volname, args, obj) +int type; +char *volname; +const char *args; +const AFPObj *obj; +{ + char buf[MAXPATHLEN + 1], *p, *b; + DSI *dsi = obj->handle; + + if (!args) + return -1; + + strlcpy(buf, args, sizeof(buf)); + if ((p = strtok_r(buf, ",", &b)) == NULL) /* nothing, return okay */ + return -1; + + while (p) { + if (obj->proto == AFPPROTO_DSI) { + struct in_addr mask, net; + char *net_char, *mask_char; + int mask_int; + + net_char = strtok(p, "/"); + mask_char = strtok(NULL,"/"); + if (mask_char == NULL) { + mask_int = 32; + } else { + mask_int = atoi(mask_char); + } + + // convert the integer netmask to a bitmask in network order + mask.s_addr = htonl(-1 - ((1 << (32 - mask_int)) - 1)); + net.s_addr = inet_addr(net_char) & mask.s_addr; + + if ((dsi->client.sin_addr.s_addr & mask.s_addr) == net.s_addr) { + if (type == VOLOPT_DENIED_HOSTS) + LOG(log_info, logtype_afpd, "AFP access denied for client IP '%s' to volume '%s' by denied list", + inet_ntoa(dsi->client.sin_addr), volname); + return 1; + } + } + p = strtok_r(NULL, ",", &b); + } + if (type == VOLOPT_ALLOWED_HOSTS) + LOG(log_info, logtype_afpd, "AFP access denied for client IP '%s' to volume '%s', not in allowed list", + inet_ntoa(dsi->client.sin_addr), volname); + return 0; +} + static void setextmap( ext, type, creator, user) char *ext, *type, *creator; int user; @@ -838,7 +945,12 @@ static void sortextmap( void) } if (Extmap_cnt) { qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp); - Defextmap = Extmap; + if (*Extmap->em_ext == 0) { + /* the first line is really "." the default entry, + * we remove the leading '.' in setextmap + */ + Defextmap = Extmap; + } } } @@ -1016,7 +1128,9 @@ struct passwd *pwent; allow -> either no list (-1), or in list (1) deny -> either no list (-1), or not in list (0) */ if (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) && - (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1)) { + (accessvol(options[VOLOPT_DENY].c_value, obj->username) < 1) && + hostaccessvol(VOLOPT_ALLOWED_HOSTS, volname, options[VOLOPT_ALLOWED_HOSTS].c_value, obj) && + (hostaccessvol(VOLOPT_DENIED_HOSTS, volname, options[VOLOPT_DENIED_HOSTS].c_value, obj) < 1)) { /* handle read-only behaviour. semantics: * 1) neither the rolist nor the rwlist exist -> rw @@ -1222,7 +1336,7 @@ int *buflen; * For MacOS8.x support we need to create the * .Parent file here if it doesn't exist. */ - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if ( ad_open( vol->v_path, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT, 0666, &ad) < 0 ) { @@ -1385,7 +1499,8 @@ int *buflen; if ( nameoff ) { ashort = htons( data - buf ); memcpy(nameoff, &ashort, sizeof( ashort )); - aint = ucs2_to_charset( (utf8_encoding()?CH_UTF8_MAC:vol->v_maccharset), vol->v_name, data+1, 255); + /* name is always in mac charset, FIXME mangle if length > 27 char */ + aint = ucs2_to_charset( vol->v_maccharset, vol->v_name, data+1, 255); if ( aint <= 0 ) { *buflen = 0; return AFPERR_MISC; @@ -1402,7 +1517,7 @@ int *buflen; } /* ------------------------- */ -int static stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) +static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) { struct stat st; int buflen, ret; @@ -1486,8 +1601,8 @@ void load_volumes(AFPObj *obj) /* ------------------------------- */ int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +char *ibuf _U_, *rbuf; +int ibuflen _U_, *rbuflen; { struct timeval tv; struct stat st; @@ -1502,6 +1617,8 @@ int ibuflen, *rbuflen; data = rbuf + 5; for ( vcnt = 0, volume = Volumes; volume; volume = volume->v_next ) { if (!(volume->v_flags & AFPVOL_NOSTAT)) { + struct maccess ma; + if ( stat( volume->v_path, &st ) < 0 ) { LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s", volume->v_path, strerror(errno) ); @@ -1510,6 +1627,10 @@ int ibuflen, *rbuflen; if (!S_ISDIR(st.st_mode)) { continue; /* not a dir */ } + accessmode(volume->v_path, &ma, NULL, &st); + if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) { + continue; /* no r-x access */ + } } if (volume->v_hide) { continue; /* config file changed but the volume was mounted */ @@ -1557,7 +1678,7 @@ int ibuflen, *rbuflen; int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int ibuflen _U_, *rbuflen; { struct stat st; char *volname; @@ -1746,8 +1867,10 @@ int ibuflen, *rbuflen; ret = stat_vol(bitmap, volume, rbuf, rbuflen); if (ret == AFP_OK) { - handle_special_folders( volume ); - savevoloptions( volume); + if (!(volume->v_flags & AFPVOL_RO)) { + handle_special_folders( volume ); + savevoloptions( volume); + } /* * If you mount a volume twice, the second time the trash appears on @@ -1764,6 +1887,7 @@ int ibuflen, *rbuflen; LOG (log_error, logtype_afpd, "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend", volume->v_path); + ret = AFPERR_MISC; goto openvol_err; } } @@ -1816,7 +1940,7 @@ void close_all_vol(void) struct vol *ovol; curdir = NULL; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { - if ( ovol->v_flags & AFPVOL_OPEN ) { + if ( (ovol->v_flags & AFPVOL_OPEN) ) { ovol->v_flags &= ~AFPVOL_OPEN; closevol(ovol); } @@ -1825,9 +1949,9 @@ void close_all_vol(void) /* ------------------------- */ int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; { struct vol *vol, *ovol; u_int16_t vid; @@ -1841,7 +1965,7 @@ int ibuflen, *rbuflen; vol->v_flags &= ~AFPVOL_OPEN; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { - if ( ovol->v_flags & AFPVOL_OPEN ) { + if ( (ovol->v_flags & AFPVOL_OPEN) ) { break; } } @@ -1980,9 +2104,9 @@ struct vol *vol; /* ------------------------- */ int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; +AFPObj *obj _U_; char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int ibuflen _U_, *rbuflen; { struct vol *vol; u_int16_t vid, bitmap; @@ -2003,9 +2127,9 @@ int ibuflen, *rbuflen; /* ------------------------- */ int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; { struct adouble ad; struct vol *vol; @@ -2025,14 +2149,14 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM ); } - if (vol->v_flags & AFPVOL_RO) + if ((vol->v_flags & AFPVOL_RO)) return AFPERR_VLOCK; /* we can only set the backup date. */ if (bitmap != (1 << VOLPBIT_BDATE)) return AFPERR_BITMAP; - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0666, &ad) < 0 ) { if (errno == EROFS) @@ -2128,7 +2252,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f if ( !ret && folder->hide) { /* Hide it */ - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR, O_RDWR|O_CREAT, 0666, &ad) < 0) { free (p); @@ -2146,14 +2270,14 @@ static int create_special_folder (const struct vol *vol, const struct _special_f ad_getattr(&ad, &attr); attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE ); ad_setattr(&ad, attr); -#if 0 + /* do the same with the finder info */ if (ad_entry(&ad, ADEID_FINDERI)) { memcpy(&attr, ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, sizeof(attr)); attr |= htons(FINDERINFO_INVISIBLE); memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr)); } -#endif + ad_flush( &ad, ADFLAGS_HF ); ad_close( &ad, ADFLAGS_HF ); } @@ -2166,7 +2290,7 @@ static void handle_special_folders (const struct vol * vol) { const _special_folder *p = &special_folders[0]; - if (vol->v_flags & AFPVOL_RO) + if ((vol->v_flags & AFPVOL_RO)) return; for (; p->name != NULL; p++) { @@ -2254,7 +2378,7 @@ static int savevoloptions (const struct vol *vol) /* volume flags */ strcpy(item, "VOLUME_OPTS:"); for (;op->name; op++) { - if ( vol->v_flags & op->option ) { + if ( (vol->v_flags & op->option) ) { strlcat(item, op->name, sizeof(item)); strlcat(item, " ", sizeof(item)); } @@ -2265,7 +2389,7 @@ static int savevoloptions (const struct vol *vol) /* casefold flags */ strcpy(item, "VOLCASEFOLD:"); for (;cf->name; cf++) { - if ( vol->v_casefold & cf->option ) { + if ( (vol->v_casefold & cf->option) ) { strlcat(item, cf->name, sizeof(item)); strlcat(item, " ", sizeof(item)); } @@ -2277,13 +2401,10 @@ static int savevoloptions (const struct vol *vol) LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf); - if (write( fd, buf, strlen(buf)) < 0) { + if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) { LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno)); - goto done; } - ftruncate(fd, strlen(buf)); -done: lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); close (fd);