X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=73904fc4c3b083891f6c9d82607e0387e542bee4;hp=a012dcd82eb38010d363ec5aee9a279ea8919c18;hb=260c314546ffcfdbef47f2c7de82d5310b26df0a;hpb=25ca059b795321076af8d8d422ba6a473ef04cf6 diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index a012dcd8..73904fc4 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -14,29 +14,14 @@ #include #include #include -#ifdef HAVE_STRINGS_H -#include -#endif -/* STDC check */ -#if STDC_HEADERS #include -#else /* STDC_HEADERS */ -#ifndef HAVE_STRCHR -#define strchr index -#define strrchr index -#endif /* HAVE_STRCHR */ -char *strchr (), *strrchr (); -#ifndef HAVE_MEMCPY -#define memcpy(d,s,n) bcopy ((s), (d), (n)) -#define memmove(d,s,n) bcopy ((s), (d), (n)) -#endif /* ! HAVE_MEMCPY */ -#endif /* STDC_HEADERS */ #include #include #include #include +#include +#include -#include #include #include #include @@ -45,14 +30,19 @@ char *strchr (), *strrchr (); #include #include #include +#include #include #include +#include +#include +#include +#include +#include #ifdef CNID_DB #include #endif /* CNID_DB*/ -#include "globals.h" #include "directory.h" #include "file.h" #include "volume.h" @@ -64,25 +54,13 @@ char *strchr (), *strrchr (); extern int afprun(int root, char *cmd, int *outfd); -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif /* ! MIN */ - -#ifndef UUID_PRINTABLE_STRING_LENGTH -#define UUID_PRINTABLE_STRING_LENGTH 37 -#endif - /* Globals */ struct vol *current_vol; /* last volume from getvolbyvid() */ static struct vol *Volumes = NULL; -static u_int16_t lastvid = 0; +static uint16_t lastvid = 0; static char *Trash = "\02\024Network Trash Folder"; -static struct extmap *Extmap = NULL, *Defextmap = NULL; -static int Extmap_cnt; -static void free_extmap(void); - #define VOLOPT_ALLOW 0 /* user allow list */ #define VOLOPT_DENY 1 /* user deny list */ #define VOLOPT_RWLIST 2 /* user rw list */ @@ -102,15 +80,7 @@ static void free_extmap(void); #define VOLOPT_MACCHARSET 16 #define VOLOPT_CNIDSCHEME 17 #define VOLOPT_ADOUBLE 18 /* adouble version */ - -#ifdef FORCE_UIDGID -#warning UIDGID -#include "uid.h" - -#define VOLOPT_FORCEUID 19 /* force uid for username x */ -#define VOLOPT_FORCEGID 20 /* force gid for group x */ -#endif /* FORCE_UIDGID */ - +/* Usable slot: 19/20 */ #define VOLOPT_UMASK 21 #define VOLOPT_ALLOWED_HOSTS 22 #define VOLOPT_DENIED_HOSTS 23 @@ -125,8 +95,6 @@ static void free_extmap(void); #define VOLOPT_NUM (VOLOPT_MAX + 1) #define VOLPASSLEN 8 -#define VOLOPT_DEFAULT ":DEFAULT:" -#define VOLOPT_DEFAULT_LEN 9 struct vol_option { char *c_value; @@ -142,12 +110,7 @@ typedef struct _special_folder { static const _special_folder special_folders[] = { {"Network Trash Folder", 1, 0777, 1}, - {"Temporary Items", 1, 0777, 1}, {".AppleDesktop", 1, 0777, 0}, -#if 0 - {"TheFindByContentFolder", 0, 0, 1}, - {"TheVolumeSettingsFolder", 0, 0, 1}, -#endif {NULL, 0, 0, 0}}; /* Forward declarations */ @@ -156,7 +119,6 @@ static void deletevol(struct vol *vol); static void volume_free(struct vol *vol); static void check_ea_sys_support(struct vol *vol); static char *get_vol_uuid(const AFPObj *obj, const char *volname); -static int readvolfile(AFPObj *obj, struct afp_volume_name *p1,char *p2, int user, struct passwd *pwent); static void volfree(struct vol_option *options, const struct vol_option *save) { @@ -190,7 +152,6 @@ static void volfree(struct vol_option *options, const struct vol_option *save) * $s -> server name (hostname if it doesn't exist) * $u -> username (guest is usually nobody) * $v -> volume name or basename if null - * $z -> zone (may not exist) * $$ -> $ * * This get's called from readvolfile with @@ -261,22 +222,12 @@ static char *volxlate(AFPObj *obj, } else if (is_var(p, "$c")) { if (afpmaster && xlatevolname) return NULL; - if (obj->proto == AFPPROTO_ASP) { - ASP asp = obj->handle; - - len = sprintf(dest, "%u.%u", ntohs(asp->asp_sat.sat_addr.s_net), - asp->asp_sat.sat_addr.s_node); - dest += len; - destlen -= len; - - } else if (obj->proto == AFPPROTO_DSI) { - DSI *dsi = obj->handle; - len = sprintf(dest, "%s:%u", - getip_string((struct sockaddr *)&dsi->client), - getip_port((struct sockaddr *)&dsi->client)); - dest += len; - destlen -= len; - } + DSI *dsi = obj->dsi; + len = sprintf(dest, "%s:%u", + getip_string((struct sockaddr *)&dsi->client), + getip_port((struct sockaddr *)&dsi->client)); + dest += len; + destlen -= len; } else if (is_var(p, "$d")) { if (afpmaster && xlatevolname) return NULL; @@ -298,24 +249,10 @@ static char *volxlate(AFPObj *obj, } else if (is_var(p, "$i")) { if (afpmaster && xlatevolname) return NULL; - if (obj->proto == AFPPROTO_ASP) { - ASP asp = obj->handle; - - len = sprintf(dest, "%u", ntohs(asp->asp_sat.sat_addr.s_net)); - dest += len; - destlen -= len; - - } else if (obj->proto == AFPPROTO_DSI) { - DSI *dsi = obj->handle; - q = getip_string((struct sockaddr *)&dsi->client); - } + DSI *dsi = obj->dsi; + q = getip_string((struct sockaddr *)&dsi->client); } else if (is_var(p, "$s")) { - if (obj->Obj) - q = obj->Obj; - else if (obj->options.server) { - q = obj->options.server; - } else - q = obj->options.hostname; + q = obj->options.hostname; } else if (obj->username && is_var(p, "$u")) { if (afpmaster && xlatevolname) return NULL; @@ -336,8 +273,6 @@ static char *volxlate(AFPObj *obj, else if (*(q + 1) != '\0') q++; } - } else if (is_var(p, "$z")) { - q = obj->Zone; } else if (is_var(p, "$$")) { q = "$"; } else @@ -365,216 +300,160 @@ static char *volxlate(AFPObj *obj, return ret; } -/* to make sure that val is valid, make sure to select an opt that - includes val */ -static int optionok(const char *buf, const char *opt, const char *val) -{ - if (!strstr(buf,opt)) - return 0; - if (!val[1]) - return 0; - return 1; -} - - /* -------------------- */ -static void setoption(struct vol_option *options, struct vol_option *save, int opt, const char *val) +static void setoption(struct vol_option *options, const struct vol_option *save, int opt, const char *val) { if (options[opt].c_value && (!save || options[opt].c_value != save[opt].c_value)) free(options[opt].c_value); options[opt].c_value = strdup(val + 1); } -/* ------------------------------------------ - handle all the options. tmp can't be NULL. */ -static void volset(struct vol_option *options, struct vol_option *save, - char *volname, int vlen, - const char *tmp) +/* Parse iniconfig and initalize volume options */ +static void volset(const dictionary *conf, const char *vol, struct vol_option *options, const struct vol_option *save) { - char *val; + const char *val; + char *p, *q; - val = strchr(tmp, ':'); - if (!val) { - /* we'll assume it's a volume name. */ - strncpy(volname, tmp, vlen); - volname[vlen] = 0; - return; - } -#if 0 - LOG(log_debug, logtype_afpd, "Parsing volset %s", val); -#endif - if (optionok(tmp, "allow:", val)) { + if (val = iniparser_getstring(conf, vol, "allow", NULL)) setoption(options, save, VOLOPT_ALLOW, val); - } else if (optionok(tmp, "deny:", val)) { + if (val = iniparser_getstring(conf, vol, "deny", NULL)) setoption(options, save, VOLOPT_DENY, val); - } else if (optionok(tmp, "rwlist:", val)) { + if (val = iniparser_getstring(conf, vol, "rwlist", NULL)) setoption(options, save, VOLOPT_RWLIST, val); - } else if (optionok(tmp, "rolist:", val)) { + if (val = iniparser_getstring(conf, vol, "rolist", NULL)) setoption(options, save, VOLOPT_ROLIST, val); - } else if (optionok(tmp, "codepage:", val)) { - LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!"); - /* Make sure we don't screw anything */ - exit (EXITERR_CONF); - } else if (optionok(tmp, "volcharset:", val)) { + if (val = iniparser_getstring(conf, vol, "volcharset", NULL)) setoption(options, save, VOLOPT_ENCODING, val); - } else if (optionok(tmp, "maccharset:", val)) { - setoption(options, save, VOLOPT_MACCHARSET, val); - } else if (optionok(tmp, "veto:", val)) { - setoption(options, save, VOLOPT_VETO, val); - } else if (optionok(tmp, "cnidscheme:", val)) { - setoption(options, save, VOLOPT_CNIDSCHEME, val); - } else if (optionok(tmp, "casefold:", val)) { - if (strcasecmp(val + 1, "tolower") == 0) - options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER; - else if (strcasecmp(val + 1, "toupper") == 0) - options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMUPPER; - else if (strcasecmp(val + 1, "xlatelower") == 0) - options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER; - else if (strcasecmp(val + 1, "xlateupper") == 0) - options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER; - } else if (optionok(tmp, "adouble:", val)) { - if (strcasecmp(val + 1, "v1") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION1; -#if AD_VERSION == AD_VERSION2 - else if (strcasecmp(val + 1, "v2") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION2; - else if (strcasecmp(val + 1, "osx") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX; - else if (strcasecmp(val + 1, "sfm") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM; -#endif - } else if (optionok(tmp, "options:", val)) { - char *p; - - if ((p = strtok(val + 1, ",")) == NULL) /* nothing */ - return; - - while (p) { - if (strcasecmp(p, "prodos") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_A2VOL; - else if (strcasecmp(p, "mswindows") == 0) { - options[VOLOPT_FLAGS].i_value |= AFPVOL_MSWINDOWS | AFPVOL_USEDOTS; - } else if (strcasecmp(p, "crlf") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF; - else if (strcasecmp(p, "noadouble") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_NOADOUBLE; - else if (strcasecmp(p, "ro") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; - else if (strcasecmp(p, "nohex") == 0) - 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" */ - else if (strcasecmp(p, "dropbox") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX; - else if (strcasecmp(p, "dropkludge") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX; - else if (strcasecmp(p, "nofileid") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID; - else if (strcasecmp(p, "nostat") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT; - else if (strcasecmp(p, "preexec_close") == 0) - options[VOLOPT_PREEXEC].i_value = 1; - else if (strcasecmp(p, "root_preexec_close") == 0) - options[VOLOPT_ROOTPREEXEC].i_value = 1; - else if (strcasecmp(p, "upriv") == 0) - 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, "caseinsensitive") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN; - else if (strcasecmp(p, "illegalseq") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ; - else if (strcasecmp(p, "nocnidcache") == 0) - options[VOLOPT_FLAGS].i_value &= ~AFPVOL_CACHE; - else if (strcasecmp(p, "tm") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_TM; - else if (strcasecmp(p, "searchdb") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB; -/* Found this in branch dir-rewrite, maybe we want to use it sometimes */ -#if 0 - else if (strcasecmp(p, "cdrom") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_CDROM | AFPVOL_RO; -#endif - p = strtok(NULL, ","); - } - } else if (optionok(tmp, "cnidserver:", val)) { - setoption(options, save, VOLOPT_CNIDSERVER, val); + if (val = iniparser_getstring(conf, vol, "maccharset", NULL)) + setoption(options, save, VOLOPT_MACCHARSET, val); - char *p = strrchr(val + 1, ':'); - if (p) { - *p = 0; - setoption(options, save, VOLOPT_CNIDPORT, p); - } + if (val = iniparser_getstring(conf, vol, "veto", NULL)) + setoption(options, save, VOLOPT_VETO, val); - LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s", - volname, val + 1, p ? p + 1 : Cnid_port); + if (val = iniparser_getstring(conf, vol, "cnidscheme", NULL)) + setoption(options, save, VOLOPT_CNIDSCHEME, val); - } else if (optionok(tmp, "dbpath:", val)) { + if (val = iniparser_getstring(conf, vol, "dbpath", NULL)) setoption(options, save, VOLOPT_DBPATH, val); - } else if (optionok(tmp, "umask:", val)) { - 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, "password:", val)) { + if (val = iniparser_getstring(conf, vol, "password", NULL)) setoption(options, save, VOLOPT_PASSWORD, val); -#ifdef FORCE_UIDGID - - /* this code allows forced uid/gid per volume settings */ - } else if (optionok(tmp, "forceuid:", val)) { - setoption(options, save, VOLOPT_FORCEUID, val); - } else if (optionok(tmp, "forcegid:", val)) { - setoption(options, save, VOLOPT_FORCEGID, val); - -#endif /* FORCE_UIDGID */ - } else if (optionok(tmp, "root_preexec:", val)) { + if (val = iniparser_getstring(conf, vol, "root_preexec", NULL)) setoption(options, save, VOLOPT_ROOTPREEXEC, val); - } else if (optionok(tmp, "preexec:", val)) { + if (val = iniparser_getstring(conf, vol, "preexec", NULL)) setoption(options, save, VOLOPT_PREEXEC, val); - } else if (optionok(tmp, "root_postexec:", val)) { + if (val = iniparser_getstring(conf, vol, "root_postexec", NULL)) setoption(options, save, VOLOPT_ROOTPOSTEXEC, val); - } else if (optionok(tmp, "postexec:", val)) { + if (val = iniparser_getstring(conf, vol, "postexec", NULL)) setoption(options, save, VOLOPT_POSTEXEC, val); - } else if (optionok(tmp, "allowed_hosts:", val)) { + if (val = iniparser_getstring(conf, vol, "allowed_hosts", NULL)) setoption(options, save, VOLOPT_ALLOWED_HOSTS, val); - } else if (optionok(tmp, "denied_hosts:", val)) { + if (val = iniparser_getstring(conf, vol, "denied_hosts", NULL)) setoption(options, save, VOLOPT_DENIED_HOSTS, val); - } else if (optionok(tmp, "ea:", val)) { - if (strcasecmp(val + 1, "ad") == 0) + if (val = iniparser_getstring(conf, vol, "umask", NULL)) + options[VOLOPT_UMASK].i_value = (int)strtol(val, NULL, 8); + + if (val = iniparser_getstring(conf, vol, "dperm", NULL)) + options[VOLOPT_DPERM].i_value = (int)strtol(val, NULL, 8); + + if (val = iniparser_getstring(conf, vol, "fperm", NULL)) + options[VOLOPT_FPERM].i_value = (int)strtol(val, NULL, 8); + + if (val = iniparser_getstring(conf, vol, "perm", NULL)) + options[VOLOPT_DFLTPERM].i_value = (int)strtol(val, NULL, 8); + + if (val = iniparser_getstring(conf, vol, "volsizelimit", NULL)) + options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val, NULL, 10); + + if (val = iniparser_getstring(conf, vol, "casefold", NULL)) { + if (strcasecmp(val, "tolower") == 0) + options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER; + else if (strcasecmp(val, "toupper") == 0) + options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMUPPER; + else if (strcasecmp(val, "xlatelower") == 0) + options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER; + else if (strcasecmp(val, "xlateupper") == 0) + options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER; + } + + if (val = iniparser_getstring(conf, vol, "adouble", NULL)) { + if (strcasecmp(val, "v2") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION2; + else if (strcasecmp(val, "ea") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA; + } + + if (val = iniparser_getstring(conf, vol, "ea", NULL)) { + if (strcasecmp(val, "ad") == 0) options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AD; - else if (strcasecmp(val + 1, "sys") == 0) + else if (strcasecmp(val, "sys") == 0) options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_SYS; - else if (strcasecmp(val + 1, "none") == 0) + else if (strcasecmp(val, "none") == 0) options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_NONE; + } - } else if (optionok(tmp, "volsizelimit:", val)) { - options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val + 1, NULL, 10); - - } else { - /* ignore unknown options */ - LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp); + if (p = iniparser_getstrdup(conf, vol, "cnidserver", NULL)) { + if (q = strrchr(val, ':')) { + *q = 0; + setoption(options, save, VOLOPT_CNIDPORT, q + 1); + } + setoption(options, save, VOLOPT_CNIDSERVER, p); + LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s", + vol, p, q ? q + 1 : "4700"); + free(p); + } + if (q = iniparser_getstrdup(conf, vol, "options", NULL)) { + if (p = strtok(q, ",")) { + while (p) { + if (strcasecmp(p, "ro") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; + else if (strcasecmp(p, "nohex") == 0) + 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, "nostat") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT; + else if (strcasecmp(p, "preexec_close") == 0) + options[VOLOPT_PREEXEC].i_value = 1; + else if (strcasecmp(p, "root_preexec_close") == 0) + options[VOLOPT_ROOTPREEXEC].i_value = 1; + else if (strcasecmp(p, "upriv") == 0) + 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, "caseinsensitive") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN; + else if (strcasecmp(p, "illegalseq") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ; + else if (strcasecmp(p, "tm") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_TM; + else if (strcasecmp(p, "searchdb") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB; + else if (strcasecmp(p, "nonetids") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS; + else if (strcasecmp(p, "noacls") == 0) + options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS; + else if (strcasecmp(p, "nov2toeaconv") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV; + p = strtok(NULL, ","); + } + } + free(q); } } @@ -593,9 +472,7 @@ static void showvol(const ucs2_t *name) /* ------------------------------- */ static int creatvol(AFPObj *obj, struct passwd *pwd, char *path, char *name, - struct vol_option *options, - const int user /* user defined volume */ - ) + struct vol_option *options) { struct vol *volume; int suffixlen, vlen, tmpvlen, u8mvlen, macvlen; @@ -603,7 +480,7 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, char tmpname[AFPVOL_U8MNAMELEN+1]; ucs2_t u8mtmpname[(AFPVOL_U8MNAMELEN+1)*2], mactmpname[(AFPVOL_MACNAMELEN+1)*2]; char suffix[6]; /* max is #FFFF */ - u_int16_t flags; + uint16_t flags; LOG(log_debug, logtype_afpd, "createvol: Volume '%s'", name); @@ -662,7 +539,14 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if ( (flags & CONV_REQMANGLE) || (tmpvlen > AFPVOL_MACNAMELEN)) { if (tmpvlen + suffixlen > AFPVOL_MACNAMELEN) { flags = CONV_FORCE; - tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, name, vlen, tmpname, AFPVOL_MACNAMELEN - suffixlen, &flags); + tmpvlen = convert_charset(obj->options.unixcharset, + obj->options.maccharset, + 0, + name, + vlen, + tmpname, + AFPVOL_MACNAMELEN - suffixlen, + &flags); tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0; } strcat(tmpname, suffix); @@ -670,15 +554,24 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, } /* Secondly convert name from maccharset to UCS2 */ - if ( 0 >= ( macvlen = convert_string(obj->options.maccharset, CH_UCS2, tmpname, tmpvlen, mactmpname, AFPVOL_U8MNAMELEN*2)) ) + if ( 0 >= ( macvlen = convert_string(obj->options.maccharset, + CH_UCS2, + tmpname, + tmpvlen, + mactmpname, + AFPVOL_U8MNAMELEN*2)) ) return -1; LOG(log_maxdebug, logtype_afpd, "createvol: Volume '%s' -> Longname: '%s'", name, tmpname); /* check duplicate */ for ( volume = Volumes; volume; volume = volume->v_next ) { - if (( strcasecmp_w( volume->v_u8mname, u8mtmpname ) == 0 ) || ( strcasecmp_w( volume->v_macname, mactmpname ) == 0 )){ - LOG (log_error, logtype_afpd, "ERROR: Volume name is duplicated. Check AppleVolumes files."); + if ((utf8_encoding() && (strcasecmp_w(volume->v_u8mname, u8mtmpname) == 0)) + || + (!utf8_encoding() && (strcasecmp_w(volume->v_macname, mactmpname) == 0))) { + LOG (log_error, logtype_afpd, + "Duplicate volume name, check AppleVolumes files: previous: \"%s\", new: \"%s\"", + volume->v_localname, name); if (volume->v_deleted) { volume->v_new = hide = 1; } @@ -728,9 +621,10 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, volume->v_vid = ++lastvid; volume->v_vid = htons(volume->v_vid); #ifdef HAVE_ACLS - if (check_vol_acl_support(volume)) - volume->v_flags |= AFPVOL_ACLS -; + if (!check_vol_acl_support(volume)) { + LOG(log_debug, logtype_afpd, "creatvol(\"%s\"): disabling ACL support", volume->v_path); + options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS; + } #endif /* handle options */ @@ -744,14 +638,10 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, 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 ((volume->v_flags & AFPVOL_NOADOUBLE)) - volume->v_ad_options |= ADVOL_NOADOUBLE; if (options[VOLOPT_PASSWORD].c_value) volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value); @@ -821,34 +711,19 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if ((volume->v_flags & AFPVOL_EILSEQ)) volume->v_utom_flags |= CONV__EILSEQ; -#ifdef FORCE_UIDGID - if (options[VOLOPT_FORCEUID].c_value) { - volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value); - } else { - volume->v_forceuid = NULL; /* set as null so as to return 0 later on */ - } - - if (options[VOLOPT_FORCEGID].c_value) { - volume->v_forcegid = strdup(options[VOLOPT_FORCEGID].c_value); - } else { - volume->v_forcegid = NULL; /* set as null so as to return 0 later on */ - } -#endif - if (!user) { - if (options[VOLOPT_PREEXEC].c_value) - volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name); - volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value; + if (options[VOLOPT_PREEXEC].c_value) + volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name); + volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value; - if (options[VOLOPT_POSTEXEC].c_value) - volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name); + if (options[VOLOPT_POSTEXEC].c_value) + volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name); - if (options[VOLOPT_ROOTPREEXEC].c_value) - volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path, name); - volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value; + if (options[VOLOPT_ROOTPREEXEC].c_value) + volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path, name); + volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value; - if (options[VOLOPT_ROOTPOSTEXEC].c_value) - volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path, name); - } + if (options[VOLOPT_ROOTPOSTEXEC].c_value) + 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; @@ -858,8 +733,8 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, check_ea_sys_support(volume); initvol_vfs(volume); - /* get/store uuid from file */ - if (volume->v_flags & AFPVOL_TM) { + /* get/store uuid from file in afpd master*/ + if ((parent_or_child == 0) && (volume->v_flags & AFPVOL_TM)) { char *uuid = get_vol_uuid(obj, volume->v_localname); if (!uuid) { LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID", @@ -957,7 +832,7 @@ static int hostaccessvol(int type, const char *volname, const char *args, const { int mask_int; char buf[MAXPATHLEN + 1], *p, *b; - DSI *dsi = obj->handle; + DSI *dsi = obj->dsi; struct sockaddr_storage client; if (!args) @@ -967,9 +842,6 @@ static int hostaccessvol(int type, const char *volname, const char *args, const if ((p = strtok_r(buf, ",", &b)) == NULL) /* nothing, return okay */ return -1; - if (obj->proto != AFPPROTO_DSI) - return -1; - while (p) { int ret; char *ipaddr, *mask_char; @@ -1021,304 +893,117 @@ static int hostaccessvol(int type, const char *volname, const char *args, const return 0; } -static void setextmap(char *ext, char *type, char *creator, int user) -{ - struct extmap *em; - int cnt; - - if (Extmap == NULL) { - if (( Extmap = calloc(1, sizeof( struct extmap ))) == NULL ) { - LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) ); - return; - } - } - ext++; - for ( em = Extmap, cnt = 0; em->em_ext; em++, cnt++) { - if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) { - break; - } - } - - if ( em->em_ext == NULL ) { - if (!(Extmap = realloc( Extmap, sizeof( struct extmap ) * (cnt +2))) ) { - LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) ); - return; - } - (Extmap +cnt +1)->em_ext = NULL; - em = Extmap +cnt; - } else if ( !user ) { - return; - } - if (em->em_ext) - free(em->em_ext); - - if (!(em->em_ext = strdup( ext))) { - LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) ); - return; - } - - if ( *type == '\0' ) { - memcpy(em->em_type, "\0\0\0\0", sizeof( em->em_type )); - } else { - memcpy(em->em_type, type, sizeof( em->em_type )); - } - if ( *creator == '\0' ) { - memcpy(em->em_creator, "\0\0\0\0", sizeof( em->em_creator )); - } else { - memcpy(em->em_creator, creator, sizeof( em->em_creator )); - } -} - -/* -------------------------- */ -static int extmap_cmp(const void *map1, const void *map2) -{ - const struct extmap *em1 = map1; - const struct extmap *em2 = map2; - return strdiacasecmp(em1->em_ext, em2->em_ext); -} - -static void sortextmap( void) -{ - struct extmap *em; - - Extmap_cnt = 0; - if ((em = Extmap) == NULL) { - return; - } - while (em->em_ext) { - em++; - Extmap_cnt++; - } - if (Extmap_cnt) { - qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp); - if (*Extmap->em_ext == 0) { - /* the first line is really "." the default entry, - * we remove the leading '.' in setextmap - */ - Defextmap = Extmap; - } - } -} - -/* ---------------------- - */ -static void free_extmap( void) -{ - struct extmap *em; - - if (Extmap) { - for ( em = Extmap; em->em_ext; em++) { - free (em->em_ext); - } - free(Extmap); - Extmap = NULL; - Defextmap = Extmap; - Extmap_cnt = 0; - } -} - /* ---------------------- */ -static int volfile_changed(struct afp_volume_name *p) +static int volfile_changed(struct afp_options *p) { struct stat st; - char *name; - - if (p->full_name) - name = p->full_name; - else - name = p->name; - if (!stat( name, &st) && st.st_mtime > p->mtime) { - p->mtime = st.st_mtime; + if (!stat(p->configfile, &st) && st.st_mtime > p->volfile.mtime) { + p->volfile.mtime = st.st_mtime; return 1; } return 0; } +static int vol_section(const char *sec) +{ + if (STRCMP(sec, ==, INISEC_GLOBAL) == 0) + return 0; + if (strcmp(sec, INISEC_AFP) == 0) + return 0; + if (strcmp(sec, INISEC_CNID) == 0) + return 0; + return 1; +} + /* ---------------------- - * Read a volume configuration file and add the volumes contained within to + * Read volumes from iniconfig and add the volumes contained within to * the global volume list. This gets called from the forked afpd childs. * The master now reads this too for Zeroconf announcements. - * - * If p2 is non-NULL, the file that is opened is - * p1/p2 - * - * Lines that begin with # and blank lines are ignored. - * Volume lines are of the form: - * [] [allow:,<@group>,...] \ - * [codepage:] [casefold:] - * TYPE [CREATOR] - * */ -static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent) +static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, struct passwd *pwent) { - FILE *fp; char path[MAXPATHLEN + 1]; - char tmp[MAXPATHLEN + 1]; char volname[AFPVOL_U8MNAMELEN + 1]; - char buf[BUFSIZ]; - char type[5], creator[5]; - char *u, *p; + char tmp[MAXPATHLEN + 1]; + char *u; + const char *p; int fd; int i; - struct passwd *pw; - struct vol_option save_options[VOLOPT_NUM]; - struct vol_option options[VOLOPT_NUM]; - struct stat st; + struct passwd *pw; + struct vol_option save_options[VOLOPT_NUM]; + struct vol_option default_options[VOLOPT_NUM]; + struct vol_option options[VOLOPT_NUM]; + + LOG(log_debug, logtype_afpd, "readvolfile: BEGIN"); - if (!p1->name) - return -1; p1->mtime = 0; - strcpy( path, p1->name ); - if ( p2 != NULL ) { - strcat( path, "/" ); - strcat( path, p2 ); - if (p1->full_name) { - free(p1->full_name); - } - p1->full_name = strdup(path); - } - if (NULL == ( fp = fopen( path, "r" )) ) { - return( -1 ); - } - fd = fileno(fp); - if (fd != -1 && !fstat( fd, &st) ) { - p1->mtime = st.st_mtime; - } + memset(default_options, 0, sizeof(default_options)); - if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) { - LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path); - if ( fclose( fp ) != 0 ) { - LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) ); - } - return -1; - } + /* Enable some default options for all volumes */ +#ifdef HAVE_ACLS + default_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS; +#endif + default_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO; + default_options[VOLOPT_UMASK].i_value = obj->options.umask; + memcpy(save_options, default_options, sizeof(options)); - memset(save_options, 0, sizeof(save_options)); + int secnum = iniparser_getnsec(obj->iniconfig); + const char *secname; - /* Enable some default options for all volumes */ - save_options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE; - save_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO; - LOG(log_maxdebug, logtype_afpd, "readvolfile: seeding default umask: %04o", - obj->options.umask); - save_options[VOLOPT_UMASK].i_value = obj->options.umask; - - LOG(log_debug, logtype_afpd, "readvolfile: \"%s\"", path); - - while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) { - initline( strlen( buf ), buf ); - parseline( sizeof( path ) - 1, path ); - switch ( *path ) { - case '\0' : - case '#' : + for (i = 0; i < secnum; secname = iniparser_getsecname(obj->iniconfig, i), i++) { + if (!vol_section(secname)) + continue; + if ((p = iniparser_getstrdup(obj->iniconfig, secname, "path", NULL)) == NULL) continue; + strlcpy(path, p, MAXPATHLEN); + strcpy(tmp, path); + strlcpy(volname, secname, AFPVOL_U8MNAMELEN); - case ':': - /* change the default options for this file */ - if (strncmp(path, VOLOPT_DEFAULT, VOLOPT_DEFAULT_LEN) == 0) { - *tmp = '\0'; - for (i = 0; i < VOLOPT_NUM; i++) { - if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1, - path + VOLOPT_DEFAULT_LEN) < 0) - break; - volset(save_options, NULL, tmp, sizeof(tmp) - 1, - path + VOLOPT_DEFAULT_LEN); - } - } - break; + if (!pwent && obj->username) + pwent = getpwnam(obj->username); - case '~' : - if (( p = strchr( path, '/' )) != NULL ) { - *p++ = '\0'; - } - u = path; - u++; - if ( *u == '\0' ) { - u = obj->username; - } - if ( u == NULL || *u == '\0' || ( pw = getpwnam( u )) == NULL ) { - continue; - } - strcpy( tmp, pw->pw_dir ); - if ( p != NULL && *p != '\0' ) { - strcat( tmp, "/" ); - strcat( tmp, p ); - } - /* fall through */ + if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL) + continue; - case '/' : - /* send path through variable substitution */ - if (*path != '~') /* need to copy path to tmp */ - strcpy(tmp, path); - if (!pwent && obj->username) - pwent = getpwnam(obj->username); + memcpy(options, default_options, sizeof(options)); + volset(obj->iniconfig, secname, options, default_options); + + /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.): + allow -> either no list (-1), or in list (1) + deny -> either no list (-1), or not in list (0) */ + if (parent_or_child == 0 + || + (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) && + (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 + * 2) rolist exists -> ro if user is in it. + * 3) rwlist exists -> ro unless user is in it. */ + if (parent_or_child == 1 + && + ((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0) + && + ((accessvol(options[VOLOPT_ROLIST].c_value, obj->username) == 1) || + !accessvol(options[VOLOPT_RWLIST].c_value, obj->username))) + options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; - if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL) + /* do variable substitution for volname */ + if (volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL) == NULL) { + volfree(options, default_options); continue; - - /* this is sort of braindead. basically, i want to be - * able to specify things in any order, but i don't want to - * re-write everything. */ - - memcpy(options, save_options, sizeof(options)); - *volname = '\0'; - - /* read in up to VOLOP_NUM possible options */ - for (i = 0; i < VOLOPT_NUM; i++) { - if (parseline( sizeof( tmp ) - 1, tmp ) < 0) - break; - - volset(options, save_options, volname, sizeof(volname) - 1, tmp); - } - - /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.): - allow -> either no list (-1), or in list (1) - deny -> either no list (-1), or not in list (0) */ - if (parent_or_child == 0 - || - (accessvol(options[VOLOPT_ALLOW].c_value, obj->username) && - (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 - * 2) rolist exists -> ro if user is in it. - * 3) rwlist exists -> ro unless user is in it. */ - if (parent_or_child == 1 - && - ((options[VOLOPT_FLAGS].i_value & AFPVOL_RO) == 0) - && - ((accessvol(options[VOLOPT_ROLIST].c_value, obj->username) == 1) || - !accessvol(options[VOLOPT_RWLIST].c_value, obj->username))) - options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; - - /* do variable substitution for volname */ - if (volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL) == NULL) - continue; - - creatvol(obj, pwent, path, tmp, options, p2 != NULL); } - volfree(options, save_options); - break; - case '.' : - parseline( sizeof( type ) - 1, type ); - parseline( sizeof( creator ) - 1, creator ); - setextmap( path, type, creator, user); - break; - - default : - break; + creatvol(obj, pwent, path, tmp, options); } + volfree(options, default_options); } volfree(save_options, NULL); - sortextmap(); - if ( fclose( fp ) != 0 ) { - LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) ); - } p1->loaded = 1; return( 0 ); } @@ -1340,10 +1025,6 @@ static void volume_free(struct vol *vol) free(vol->v_cnidscheme); free(vol->v_dbpath); free(vol->v_gvs); -#ifdef FORCE_UIDGID - free(vol->v_forceuid); - free(vol->v_forcegid); -#endif /* FORCE_UIDGID */ if (vol->v_uuid) free(vol->v_uuid); } @@ -1402,22 +1083,169 @@ static void volume_unlink(struct vol *volume) } } } +/*! + * Read band-size info from Info.plist XML file of an TM sparsebundle + * + * @param path (r) path to Info.plist file + * @return band-size in bytes, -1 on error + */ +static long long int get_tm_bandsize(const char *path) +{ + EC_INIT; + FILE *file = NULL; + char buf[512]; + long long int bandsize = -1; + + EC_NULL_LOGSTR( file = fopen(path, "r"), + "get_tm_bandsize(\"%s\"): %s", + path, strerror(errno) ); + + while (fgets(buf, sizeof(buf), file) != NULL) { + if (strstr(buf, "band-size") == NULL) + continue; + + if (fscanf(file, " %lld", &bandsize) != 1) { + LOG(log_error, logtype_afpd, "get_tm_bandsize(\"%s\"): can't parse band-size", path); + EC_FAIL; + } + break; + } + +EC_CLEANUP: + if (file) + fclose(file); + LOG(log_debug, logtype_afpd, "get_tm_bandsize(\"%s\"): bandsize: %lld", path, bandsize); + return bandsize; +} + +/*! + * Return number on entries in a directory + * + * @param path (r) path to dir + * @return number of entries, -1 on error + */ +static long long int get_tm_bands(const char *path) +{ + EC_INIT; + long long int count = 0; + DIR *dir = NULL; + const struct dirent *entry; + + EC_NULL( dir = opendir(path) ); + + while ((entry = readdir(dir)) != NULL) + count++; + count -= 2; /* All OSens I'm aware of return "." and "..", so just substract them, avoiding string comparison in loop */ + +EC_CLEANUP: + if (dir) + closedir(dir); + if (ret != 0) + return -1; + return count; +} + +/*! + * Calculate used size of a TimeMachine volume + * + * This assumes that the volume is used only for TimeMachine. + * + * 1) readdir(path of volume) + * 2) for every element that matches regex "\(.*\)\.sparsebundle$" : + * 3) parse "\1.sparsebundle/Info.plist" and read the band-size XML key integer value + * 4) readdir "\1.sparsebundle/bands/" counting files + * 5) calculate used size as: (file_count - 1) * band-size + * + * The result of the calculation is returned in "volume->v_tm_used". + * "volume->v_appended" gets reset to 0. + * "volume->v_tm_cachetime" is updated with the current time from time(NULL). + * + * "volume->v_tm_used" is cached for TM_USED_CACHETIME seconds and updated by + * "volume->v_appended". The latter is increased by X every time the client + * appends X bytes to a file (in fork.c). + * + * @param vol (rw) volume to calculate + * @return 0 on success, -1 on error + */ +#define TM_USED_CACHETIME 60 /* cache for 60 seconds */ +static int get_tm_used(struct vol * restrict vol) +{ + EC_INIT; + long long int bandsize; + VolSpace used = 0; + bstring infoplist = NULL; + bstring bandsdir = NULL; + DIR *dir = NULL; + const struct dirent *entry; + const char *p; + struct stat st; + long int links; + time_t now = time(NULL); + + if (vol->v_tm_cachetime + && ((vol->v_tm_cachetime + TM_USED_CACHETIME) >= now)) { + if (vol->v_tm_used == -1) + EC_FAIL; + vol->v_tm_used += vol->v_appended; + vol->v_appended = 0; + LOG(log_debug, logtype_afpd, "getused(\"%s\"): cached: %" PRIu64 " bytes", + vol->v_path, vol->v_tm_used); + return 0; + } + + vol->v_tm_cachetime = now; + + EC_NULL( dir = opendir(vol->v_path) ); + + while ((entry = readdir(dir)) != NULL) { + if (((p = strstr(entry->d_name, "sparsebundle")) != NULL) + && (strlen(entry->d_name) == (p + strlen("sparsebundle") - entry->d_name))) { + + EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") ); + + if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) + continue; + + EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") ); + + if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) + continue; + + used += (links - 1) * bandsize; + LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes", + cfrombstr(bandsdir), used); + } + } + + vol->v_tm_used = used; + +EC_CLEANUP: + if (infoplist) + bdestroy(infoplist); + if (bandsdir) + bdestroy(bandsdir); + if (dir) + closedir(dir); + + LOG(log_debug, logtype_afpd, "getused(\"%s\"): %" PRIu64 " bytes", vol->v_path, vol->v_tm_used); + + EC_EXIT; +} static int getvolspace(struct vol *vol, - u_int32_t *bfree, u_int32_t *btotal, - VolSpace *xbfree, VolSpace *xbtotal, u_int32_t *bsize) + uint32_t *bfree, uint32_t *btotal, + VolSpace *xbfree, VolSpace *xbtotal, uint32_t *bsize) { int spaceflag, rc; - u_int32_t maxsize; + uint32_t maxsize; + VolSpace used; #ifndef NO_QUOTA_SUPPORT VolSpace qfree, qtotal; #endif spaceflag = AFPVOL_GVSMASK & vol->v_flags; /* report up to 2GB if afp version is < 2.2 (4GB if not) */ - maxsize = (vol->v_flags & AFPVOL_A2VOL) ? 0x01fffe00 : - (((afp_version < 22) || (vol->v_flags & AFPVOL_LIMITSIZE)) - ? 0x7fffffffL : 0xffffffffL); + maxsize = (afp_version < 22) ? 0x7fffffffL : 0xffffffffL; #ifdef AFS if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) { @@ -1432,13 +1260,12 @@ static int getvolspace(struct vol *vol, return( rc ); } -#define min(a,b) ((a)<(b)?(a):(b)) #ifndef NO_QUOTA_SUPPORT if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_UQUOTA ) { if ( uquota_getvolspace( vol, &qfree, &qtotal, *bsize ) == AFP_OK ) { vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_UQUOTA; - *xbfree = min(*xbfree, qfree); - *xbtotal = min( *xbtotal, qtotal); + *xbfree = MIN(*xbfree, qfree); + *xbtotal = MIN(*xbtotal, qtotal); goto getvolspace_done; } } @@ -1447,57 +1274,43 @@ static int getvolspace(struct vol *vol, getvolspace_done: if (vol->v_limitsize) { - bstring cmdstr; - if ((cmdstr = bformat("du -sh \"%s\" 2> /dev/null | cut -f1", vol->v_path)) == NULL) + if (get_tm_used(vol) != 0) return AFPERR_MISC; - FILE *cmd = popen(cfrombstr(cmdstr), "r"); - bdestroy(cmdstr); - if (cmd == NULL) - return AFPERR_MISC; + *xbtotal = MIN(*xbtotal, (vol->v_limitsize * 1024 * 1024)); + *xbfree = MIN(*xbfree, *xbtotal < vol->v_tm_used ? 0 : *xbtotal - vol->v_tm_used); - char buf[100]; - fgets(buf, 100, cmd); + LOG(log_debug, logtype_afpd, + "volparams: total: %" PRIu64 ", used: %" PRIu64 ", free: %" PRIu64 " bytes", + *xbtotal, vol->v_tm_used, *xbfree); + } - if (pclose(cmd) == -1) - return AFPERR_MISC; + *bfree = MIN(*xbfree, maxsize); + *btotal = MIN(*xbtotal, maxsize); + return( AFP_OK ); +} - size_t multi = 0; - if (buf[strlen(buf) - 2] == 'G' || buf[strlen(buf) - 2] == 'g') - /* GB */ - multi = 1024 * 1024 * 1024; - else if (buf[strlen(buf) - 2] == 'M' || buf[strlen(buf) - 2] == 'm') - /* MB */ - multi = 1024 * 1024; - else if (buf[strlen(buf) - 2] == 'K' || buf[strlen(buf) - 2] == 'k') - /* MB */ - multi = 1024; - - char *p; - if (p = strchr(buf, ',')) - /* ignore fraction */ - *p = 0; - else - /* remove G|M|K char */ - buf[strlen(buf) - 2] = 0; - /* now buf contains only digits */ - long long used = atoll(buf) * multi; - LOG(log_debug, logtype_afpd, "volparams: used on volume: %llu bytes", used); +#define FCE_TM_DELTA 10 /* send notification every 10 seconds */ +void vol_fce_tm_event(void) +{ + static time_t last; + time_t now = time(NULL); + struct vol *vol = Volumes; - *xbtotal = min(*xbtotal, (vol->v_limitsize * 1024 * 1024)); - *xbfree = min(*xbfree, *xbtotal < used ? 0 : *xbtotal - used); + if ((last + FCE_TM_DELTA) < now) { + last = now; + for ( ; vol; vol = vol->v_next ) { + if (vol->v_flags & AFPVOL_TM) + (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_appended); + } } - - *bfree = min( *xbfree, maxsize); - *btotal = min( *xbtotal, maxsize); - return( AFP_OK ); } /* ----------------------- * set volume creation date * avoid duplicate, well at least it tries */ -static void vol_setdate(u_int16_t id, struct adouble *adp, time_t date) +static void vol_setdate(uint16_t id, struct adouble *adp, time_t date) { struct vol *volume; struct vol *vol = Volumes; @@ -1516,13 +1329,13 @@ static void vol_setdate(u_int16_t id, struct adouble *adp, time_t date) } /* ----------------------- */ -static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, char *buf, size_t *buflen) +static int getvolparams( uint16_t bitmap, struct vol *vol, struct stat *st, char *buf, size_t *buflen) { struct adouble ad; int bit = 0, isad = 1; - u_int32_t aint; + uint32_t aint; u_short ashort; - u_int32_t bfree, btotal, bsize; + uint32_t bfree, btotal, bsize; VolSpace xbfree, xbtotal; /* extended bytes */ char *data, *nameoff = NULL; char *slash; @@ -1533,8 +1346,11 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha * For MacOS8.x support we need to create the * .Parent file here if it doesn't exist. */ - ad_init(&ad, vol->v_adouble, vol->v_ad_options); - if ( ad_open_metadata( vol->v_path, ADFLAGS_DIR, O_CREAT, &ad) < 0 ) { + /* Convert adouble:v2 to adouble:ea on the fly */ + (void)ad_convert(vol->v_path, st, vol); + + ad_init(&ad, vol); + if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) { isad = 0; vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime); @@ -1591,10 +1407,8 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha } /* prior 2.1 only VOLPBIT_ATTR_RO is defined */ if (afp_version > 20) { - if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL && - (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { + if (vol->v_cdb != NULL && (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) ashort |= VOLPBIT_ATTR_FILEID; - } ashort |= VOLPBIT_ATTR_CATSEARCH; if (afp_version >= 30) { @@ -1603,7 +1417,8 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha ashort |= VOLPBIT_ATTR_UNIXPRIV; if (vol->v_flags & AFPVOL_TM) ashort |= VOLPBIT_ATTR_TM; - + if (vol->v_flags & AFPVOL_NONETIDS) + ashort |= VOLPBIT_ATTR_NONETIDS; if (afp_version >= 32) { if (vol->v_vfs_ea) ashort |= VOLPBIT_ATTR_EXT_ATTRS; @@ -1665,28 +1480,20 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha #ifndef NO_LARGE_VOL_SUPPORT case VOLPBIT_XBFREE : xbfree = hton64( xbfree ); -#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG) - bcopy(&xbfree, data, sizeof(xbfree)); -#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ memcpy(data, &xbfree, sizeof( xbfree )); -#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ data += sizeof( xbfree ); break; case VOLPBIT_XBTOTAL : xbtotal = hton64( xbtotal ); -#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG) - bcopy(&xbtotal, data, sizeof(xbtotal)); -#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ memcpy(data, &xbtotal, sizeof( xbtotal )); -#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ data += sizeof( xbfree ); break; #endif /* ! NO_LARGE_VOL_SUPPORT */ case VOLPBIT_NAME : nameoff = data; - data += sizeof( u_int16_t ); + data += sizeof( uint16_t ); break; case VOLPBIT_BSIZE: /* block size */ @@ -1718,14 +1525,14 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha data += aint; } if ( isad ) { - ad_close_metadata( &ad); + ad_close(&ad, ADFLAGS_HF); } *buflen = data - buf; return( AFP_OK ); } /* ------------------------- */ -static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, size_t *rbuflen) +static int stat_vol(uint16_t bitmap, struct vol *vol, char *rbuf, size_t *rbuflen) { struct stat st; int ret; @@ -1754,27 +1561,11 @@ static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, size_t *rbufl /* ------------------------------- */ void load_volumes(AFPObj *obj) { + EC_INIT; + int fd = -1; struct passwd *pwent; - - if (Volumes) { - int changed = 0; - - /* check files date */ - if (obj->options.defaultvol.loaded) { - changed = volfile_changed(&obj->options.defaultvol); - } - if (obj->options.systemvol.loaded) { - changed |= volfile_changed(&obj->options.systemvol); - } - if (obj->options.uservol.loaded) { - changed |= volfile_changed(&obj->options.uservol); - } - if (!changed) - return; - - free_extmap(); - free_volumes(); - } + struct stat st; + int retries = 0; if (parent_or_child == 0) { LOG(log_debug, logtype_afpd, "load_volumes: AFP MASTER"); @@ -1782,39 +1573,42 @@ void load_volumes(AFPObj *obj) LOG(log_debug, logtype_afpd, "load_volumes: user: %s", obj->username); } - pwent = getpwnam(obj->username); - if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) { - readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent); + if (Volumes) { + if (!volfile_changed(&obj->options)) + return; + free_volumes(); } - if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) { - readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent); - } else if (pwent) { - /* - * Read user's AppleVolumes or .AppleVolumes file - * If neither are readable, read the default volumes file. if - * that doesn't work, create a user share. - */ - if (obj->options.uservol.name) { - free(obj->options.uservol.name); - } - obj->options.uservol.name = strdup(pwent->pw_dir); - if ( readvolfile(obj, &obj->options.uservol, "AppleVolumes", 1, pwent) < 0 && - readvolfile(obj, &obj->options.uservol, ".AppleVolumes", 1, pwent) < 0 && - readvolfile(obj, &obj->options.uservol, "applevolumes", 1, pwent) < 0 && - readvolfile(obj, &obj->options.uservol, ".applevolumes", 1, pwent) < 0 && - obj->options.defaultvol.name != NULL ) { - if (readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent) < 0) - creatvol(obj, pwent, pwent->pw_dir, NULL, NULL, 1); + /* try putting a read lock on the volume file twice, sleep 1 second if first attempt fails */ + + fd = open(obj->options.configfile, O_RDWR); + + while (retries < 2) { + if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) { + retries++; + if (!retries) { + LOG(log_error, logtype_afpd, "readvolfile: can't lock configfile \"%s\"", + obj->options.configfile); + EC_FAIL; + } + sleep(1); + continue; } - } - if ( obj->options.flags & OPTION_USERVOLFIRST ) { - readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent ); + break; } - if ( obj->options.closevol ) { - struct vol *vol; + iniparser_freedict(obj->iniconfig); + obj->iniconfig = iniparser_load(obj->options.configfile); + + if (obj->username) + pwent = getpwnam(obj->username); + else + pwent = NULL; + + readvolfile(obj, &obj->options.volfile, pwent); + if ( obj->options.flags & OPTION_CLOSEVOL) { + struct vol *vol; for ( vol = Volumes; vol; vol = vol->v_next ) { if (vol->v_deleted && !vol->v_new ) { of_closevol(vol); @@ -1823,6 +1617,11 @@ void load_volumes(AFPObj *obj) } } } + +EC_CLEANUP: + if (fd != -1) + (void)close(fd); + return; } /* ------------------------------- */ @@ -1851,7 +1650,7 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf if (!S_ISDIR(st.st_mode)) { continue; /* not a dir */ } - accessmode(volume->v_path, &ma, NULL, &st); + accessmode(volume, volume->v_path, &ma, NULL, &st); if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) { continue; /* no r-x access */ } @@ -1872,13 +1671,6 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf /* set password bit if there's a volume password */ *data = (volume->v_password) ? AFPSRVR_PASSWD : 0; - /* Apple 2 clients running ProDOS-8 expect one volume to have - bit 0 of this byte set. They will not recognize anything - on the server unless this is the case. I have not - completely worked this out, but it's related to booting - from the server. Support for that function is a ways - off.. */ - *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0; *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */ *data++ = len; memcpy(data, namebuf, len ); @@ -1895,8 +1687,8 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf return AFPERR_PARAM; } tv.tv_sec = AD_DATE_FROM_UNIX(tv.tv_sec); - memcpy(data, &tv.tv_sec, sizeof( u_int32_t)); - data += sizeof( u_int32_t); + memcpy(data, &tv.tv_sec, sizeof( uint32_t)); + data += sizeof( uint32_t); *data = vcnt; return( AFP_OK ); } @@ -1936,7 +1728,7 @@ static int volume_codepage(AFPObj *obj, struct vol *volume) } /* ------------------------- */ -static int volume_openDB(struct vol *volume) +static int volume_openDB(const AFPObj *obj, struct vol *volume) { int flags = 0; @@ -1951,37 +1743,15 @@ static int volume_openDB(struct vol *volume) } LOG(log_info, logtype_afpd, "CNID server: %s:%s", - volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : Cnid_port); - -#if 0 -/* Found this in branch dir-rewrite, maybe we want to use it sometimes */ - - /* Legacy pre 2.1 way of sharing eg CD-ROM */ - if (strcmp(volume->v_cnidscheme, "last") == 0) { - /* "last" is gone. We support it by switching to in-memory "tdb" */ - volume->v_cnidscheme = strdup("tdb"); - flags |= CNID_FLAG_MEMORY; - } - - /* New way of sharing CD-ROM */ - if (volume->v_flags & AFPVOL_CDROM) { - flags |= CNID_FLAG_MEMORY; - if (strcmp(volume->v_cnidscheme, "tdb") != 0) { - free(volume->v_cnidscheme); - volume->v_cnidscheme = strdup("tdb"); - LOG(log_info, logtype_afpd, "Volume %s is ejectable, switching to scheme %s.", - volume->v_path, volume->v_cnidscheme); - } - } -#endif + volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, + volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); volume->v_cdb = cnid_open(volume->v_path, volume->v_umask, volume->v_cnidscheme, flags, - volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : Cnid_port); + volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, + volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) { /* The first attempt failed and it wasn't yet an attempt to open in-memory */ @@ -1998,7 +1768,6 @@ static int volume_openDB(struct vol *volume) "Check server messages for details!"); kill(getpid(), SIGUSR2); /* deactivate cnid caching/storing in AppleDouble files */ - volume->v_flags &= ~AFPVOL_CACHE; } #endif } @@ -2066,7 +1835,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t struct dir *dir; int len, ret; size_t namelen; - u_int16_t bitmap; + uint16_t bitmap; char path[ MAXPATHLEN + 1]; char *vol_uname; char *vol_mname; @@ -2121,9 +1890,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t if (( volume->v_flags & AFPVOL_OPEN ) ) { /* the volume is already open */ -#ifdef FORCE_UIDGID - set_uidgid ( volume ); -#endif return stat_vol(bitmap, volume, rbuf, rbuflen); } @@ -2134,10 +1900,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t } } -#ifdef FORCE_UIDGID - set_uidgid ( volume ); -#endif - if (volume->v_preexec) { if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) { LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret ); @@ -2219,7 +1981,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t DIRDID_ROOT_PARENT, DIRDID_ROOT, bfromcstr(volume->v_path), - st.st_ctime) + &st) ) == NULL) { free(vol_mname); LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) ); @@ -2230,7 +1992,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t volume->v_root = dir; curdir = dir; - if (volume_openDB(volume) < 0) { + if (volume_openDB(obj, volume) < 0) { LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s", volume->v_path, volume->v_cnidscheme); ret = AFPERR_MISC; @@ -2238,14 +2000,13 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t } ret = stat_vol(bitmap, volume, rbuf, rbuflen); + if (ret == AFP_OK) { + handle_special_folders(volume); + savevolinfo(volume, + volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, + volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); - if (!(volume->v_flags & AFPVOL_RO)) { - handle_special_folders( volume ); - savevolinfo(volume, - volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : Cnid_port); - } /* * If you mount a volume twice, the second time the trash appears on @@ -2353,7 +2114,7 @@ static void deletevol(struct vol *vol) int afp_closevol(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { struct vol *vol; - u_int16_t vid; + uint16_t vid; *rbuflen = 0; ibuf += 2; @@ -2369,7 +2130,7 @@ int afp_closevol(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ } /* ------------------------- */ -struct vol *getvolbyvid(const u_int16_t vid ) +struct vol *getvolbyvid(const uint16_t vid ) { struct vol *vol; @@ -2382,48 +2143,11 @@ struct vol *getvolbyvid(const u_int16_t vid ) return( NULL ); } -#ifdef FORCE_UIDGID - set_uidgid ( vol ); -#endif /* FORCE_UIDGID */ - current_vol = vol; return( vol ); } -/* ------------------------ */ -static int ext_cmp_key(const void *key, const void *obj) -{ - const char *p = key; - const struct extmap *em = obj; - return strdiacasecmp(p, em->em_ext); -} -struct extmap *getextmap(const char *path) -{ - char *p; - struct extmap *em; - - if (!Extmap_cnt || NULL == ( p = strrchr( path, '.' )) ) { - return( Defextmap ); - } - p++; - if (!*p) { - return( Defextmap ); - } - em = bsearch(p, Extmap, Extmap_cnt, sizeof(struct extmap), ext_cmp_key); - if (em) { - return( em ); - } else { - return( Defextmap ); - } -} - -/* ------------------------- */ -struct extmap *getdefextmap(void) -{ - return( Defextmap ); -} - /* -------------------------- poll if a volume is changed by other processes. return @@ -2443,7 +2167,7 @@ int pollvoltime(AFPObj *obj) struct timeval tv; struct stat st; - if (!(afp_version > 21 && obj->options.server_notif)) + if (!(afp_version > 21 && obj->options.flags & OPTION_SERVERNOTIF)) return 0; if ( gettimeofday( &tv, NULL ) < 0 ) @@ -2453,7 +2177,7 @@ int pollvoltime(AFPObj *obj) if ( (vol->v_flags & AFPVOL_OPEN) && vol->v_mtime + 30 < tv.tv_sec) { if ( !stat( vol->v_path, &st ) && vol->v_mtime != st.st_mtime ) { vol->v_mtime = st.st_mtime; - if (!obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED)) + if (!obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED)) return -1; return 1; } @@ -2467,12 +2191,6 @@ void setvoltime(AFPObj *obj, struct vol *vol) { struct timeval tv; - /* just looking at vol->v_mtime is broken seriously since updates - * from other users afpd processes never are seen. - * This is not the most elegant solution (a shared memory between - * the afpd processes would come closer) - * [RS] */ - if ( gettimeofday( &tv, NULL ) < 0 ) { LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) ); return; @@ -2489,8 +2207,8 @@ void setvoltime(AFPObj *obj, struct vol *vol) /* or finder doesn't update free space * AFP 3.2 and above clients seem to be ok without so many notification */ - if (afp_version < 32 && obj->options.server_notif) { - obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); + if (afp_version < 32 && obj->options.flags & OPTION_SERVERNOTIF) { + obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); } } } @@ -2499,7 +2217,7 @@ void setvoltime(AFPObj *obj, struct vol *vol) int afp_getvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,char *rbuf, size_t *rbuflen) { struct vol *vol; - u_int16_t vid, bitmap; + uint16_t vid, bitmap; ibuf += 2; memcpy(&vid, ibuf, sizeof( vid )); @@ -2520,8 +2238,8 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf { struct adouble ad; struct vol *vol; - u_int16_t vid, bitmap; - u_int32_t aint; + uint16_t vid, bitmap; + uint32_t aint; ibuf += 2; *rbuflen = 0; @@ -2543,9 +2261,8 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf if (bitmap != (1 << VOLPBIT_BDATE)) return AFPERR_BITMAP; - 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 ) { + ad_init(&ad, vol); + if ( ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR) < 0 ) { if (errno == EROFS) return AFPERR_VLOCK; @@ -2559,33 +2276,6 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf return( AFP_OK ); } -/* ------------------------- */ -int wincheck(const struct vol *vol, const char *path) -{ - int len; - - if (!(vol->v_flags & AFPVOL_MSWINDOWS)) - return 1; - - /* empty paths are not allowed */ - if ((len = strlen(path)) == 0) - return 0; - - /* leading or trailing whitespaces are not allowed, carriage returns - * and probably other whitespace is okay, tabs are not allowed - */ - if ((path[0] == ' ') || (path[len-1] == ' ')) - return 0; - - /* certain characters are not allowed */ - if (strpbrk(path, MSWINDOWS_BADCHARS)) - return 0; - - /* everything else is okay */ - return 1; -} - - /* * precreate a folder * this is only intended for folders in the volume root @@ -2595,7 +2285,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f { char *p,*q,*r; struct adouble ad; - u_int16_t attr; + uint16_t attr; struct stat st; int ret; @@ -2639,9 +2329,9 @@ 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, vol->v_ad_options); - if (ad_open_metadata( p, ADFLAGS_DIR, O_CREAT, &ad) < 0) { - free (p); + ad_init(&ad, vol); + if (ad_open(&ad, p, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) { + free(p); free(q); return (-1); } @@ -2659,8 +2349,8 @@ static int create_special_folder (const struct vol *vol, const struct _special_f memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr)); } - ad_flush( &ad ); - ad_close_metadata( &ad); + ad_flush(&ad); + ad_close(&ad, ADFLAGS_HF); } free(p); free(q); @@ -2670,13 +2360,25 @@ static int create_special_folder (const struct vol *vol, const struct _special_f static void handle_special_folders (const struct vol * vol) { const _special_folder *p = &special_folders[0]; + uid_t process_uid; - if ((vol->v_flags & AFPVOL_RO)) - return; + process_uid = geteuid(); + if (process_uid) { + if (seteuid(0) == -1) { + process_uid = 0; + } + } for (; p->name != NULL; p++) { create_special_folder (vol, p); } + + if (process_uid) { + if (seteuid(process_uid) == -1) { + LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno)); + exit(EXITERR_SYS); + } + } } const struct vol *getvolumes(void) @@ -2684,10 +2386,9 @@ const struct vol *getvolumes(void) return Volumes; } -void unload_volumes_and_extmap(void) +void unload_volumes(void) { LOG(log_debug, logtype_afpd, "unload_volumes_and_extmap"); - free_extmap(); free_volumes(); }