X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=fd174e1737c609a36d7fb306a2d4bd71eb8b58f8;hb=a1fbe98fceb7b7e11ba1694b358a7c4c8ee919dc;hp=b5cdd208689162e10c00274872a824a15b38c2df;hpb=cd5246df10e6566010dfd460b63018f92551661a;p=netatalk.git diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index b5cdd208..fd174e17 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.60 2005-05-14 12:54:53 didg Exp $ + * $Id: volume.c,v 1.117 2010-02-08 10:29:22 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,10 @@ char *strchr (), *strrchr (); #include #include #include +#include #include +#include +#include #ifdef CNID_DB #include #endif /* CNID_DB*/ @@ -53,7 +55,9 @@ char *strchr (), *strrchr (); #include "file.h" #include "volume.h" #include "unix.h" +#include "mangle.h" #include "fork.h" +#include "hash.h" extern int afprun(int root, char *cmd, int *outfd); @@ -73,10 +77,10 @@ extern int afprun(int root, char *cmd, int *outfd); #endif /* ! NO_LARGE_VOL_SUPPORT */ static struct vol *Volumes = NULL; -static u_int16_t lastvid = 0; -static char *Trash = "\02\024Network Trash Folder"; +static u_int16_t lastvid = 0; +static char *Trash = "\02\024Network Trash Folder"; -static struct extmap *Extmap = NULL, *Defextmap = NULL; +static struct extmap *Extmap = NULL, *Defextmap = NULL; static int Extmap_cnt; static void free_extmap(void); @@ -89,15 +93,15 @@ static void free_extmap(void); #define VOLOPT_FLAGS 6 /* various flags */ #define VOLOPT_DBPATH 7 /* path to database */ #define VOLOPT_MAPCHARS 8 /* does mtou and utom mappings. syntax: -m and u can be double-byte hex -strings if necessary. -m=u -> map both ways - m>u -> map m to u - m map u to m - !u -> make u illegal always - ~u -> make u illegal only as the first - part of a double-byte character. - */ + m and u can be double-byte hex + strings if necessary. + m=u -> map both ways + m>u -> map m to u + m map u to m + !u -> make u illegal always + ~u -> make u illegal only as the first + part of a double-byte character. + */ #define VOLOPT_VETO 10 /* list of veto filespec */ #define VOLOPT_PREEXEC 11 /* preexec command */ #define VOLOPT_ROOTPREEXEC 12 /* root preexec command */ @@ -115,81 +119,52 @@ 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_EA_VFS 27 /* Extended Attributes vfs indirection */ -#define VOLOPT_NUM (VOLOPT_MAX + 1) +#define VOLOPT_MAX 28 /* <== IMPORTANT !!!!!! */ +#define VOLOPT_NUM (VOLOPT_MAX + 1) #define VOLPASSLEN 8 #define VOLOPT_DEFAULT ":DEFAULT:" #define VOLOPT_DEFAULT_LEN 9 - struct vol_option { - char *c_value; - int i_value; - }; + +struct vol_option { + char *c_value; + int i_value; +}; typedef struct _special_folder { - const char *name; - int precreate; - mode_t mode; - int hide; + const char *name; + int precreate; + mode_t mode; + int hide; } _special_folder; static const _special_folder special_folders[] = { - {"Network Trash Folder", 1, 0777, 1}, - {"Temporary Items", 1, 0777, 1}, - {".AppleDesktop", 1, 0777, 0}, + {"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}, + {"TheFindByContentFolder", 0, 0, 1}, + {"TheVolumeSettingsFolder", 0, 0, 1}, #endif - {NULL, 0, 0, 0}}; - -typedef struct _volopt_name { - const u_int32_t option; - const char *name; -} _vol_opt_name; - -static const _vol_opt_name vol_opt_names[] = { - {AFPVOL_A2VOL, "PRODOS"}, /* prodos volume */ - {AFPVOL_CRLF, "CRLF"}, /* cr/lf translation */ - {AFPVOL_NOADOUBLE, "NOADOUBLE"}, /* don't create .AppleDouble by default */ - {AFPVOL_RO, "READONLY"}, /* read-only volume */ - {AFPVOL_MSWINDOWS, "MSWINDOWS"}, /* deal with ms-windows yuckiness. this is going away. */ - {AFPVOL_NOHEX, "NOHEX"}, /* don't do :hex translation */ - {AFPVOL_USEDOTS, "USEDOTS"}, /* use real dots */ - {AFPVOL_LIMITSIZE, "LIMITSIZE"}, /* limit size for older macs */ - {AFPVOL_MAPASCII, "MAPASCII"}, /* map the ascii range as well */ - {AFPVOL_DROPBOX, "DROPBOX"}, /* dropkludge dropbox support */ - {AFPVOL_NOFILEID, "NOFILEID"}, /* don't advertise createid resolveid and deleteid calls */ - {AFPVOL_NOSTAT, "NOSTAT"}, /* advertise the volume even if we can't stat() it - * 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_CASEINSEN, "CASEINSENSITIVE"}, /* volume is case insensitive */ - {AFPVOL_EILSEQ, "ILLEGALSEQ"}, /* encode illegal sequence */ - {AFPVOL_CACHE, "CACHE ID"}, /* encode illegal sequence */ - {0, NULL} -}; - -static const _vol_opt_name vol_opt_casefold[] = { - {AFPVOL_MTOUUPPER, "MTOULOWER"}, - {AFPVOL_MTOULOWER, "MTOULOWER"}, - {AFPVOL_UTOMUPPER, "UTOMUPPER"}, - {AFPVOL_UTOMLOWER, "UTOMLOWER"}, - {0, NULL} -}; + {NULL, 0, 0, 0}}; +/* Forward declarations */ static void handle_special_folders (const struct vol *); -static int savevoloptions (const struct vol *); static void deletevol(struct vol *vol); +static void volume_free(struct vol *vol); +static void check_ea_sys_support(struct vol *vol); -static __inline__ void volfree(struct vol_option *options, - const struct vol_option *save) +static void volfree(struct vol_option *options, const struct vol_option *save) { int i; @@ -213,7 +188,7 @@ static __inline__ void volfree(struct vol_option *options, * $d -> volume pathname on server * $f -> full name (whatever's in the gecos field) * $g -> group - * $h -> hostname + * $h -> hostname * $i -> client ip/appletalk address without port * $s -> server name (hostname if it doesn't exist) * $u -> username (guest is usually nobody) @@ -226,12 +201,13 @@ static __inline__ void volfree(struct vol_option *options, #define is_var(a, b) (strncmp((a), (b), 2) == 0) static char *volxlate(AFPObj *obj, char *dest, size_t destlen, - char *src, struct passwd *pwd, char *path, char *volname) + char *src, struct passwd *pwd, char *path, char *volname) { - char *p, *q; + char *p, *r; + const char *q; int len; char *ret; - + if (!src) { return NULL; } @@ -274,17 +250,17 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, } else if (obj->proto == AFPPROTO_DSI) { DSI *dsi = obj->handle; - - len = sprintf(dest, "%s:%u", inet_ntoa(dsi->client.sin_addr), - ntohs(dsi->client.sin_port)); + 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")) { - q = path; + q = path; } else if (is_var(p, "$f")) { - if ((q = strchr(pwd->pw_gecos, ','))) - *q = '\0'; + if ((r = strchr(pwd->pw_gecos, ','))) + *r = '\0'; q = pwd->pw_gecos; } else if (is_var(p, "$g")) { struct group *grp = getgrgid(pwd->pw_gid); @@ -295,15 +271,14 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, } else if (is_var(p, "$i")) { 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 = inet_ntoa(dsi->client.sin_addr); + q = getip_string((struct sockaddr *)&dsi->client); } } else if (is_var(p, "$s")) { if (obj->Obj) @@ -313,7 +288,11 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, } else q = obj->options.hostname; } else if (is_var(p, "$u")) { - q = obj->username; + char* sep = NULL; + if ( obj->options.ntseparator && (sep = strchr(obj->username, obj->options.ntseparator[0])) != NULL) + q = sep+1; + else + q = obj->username; } else if (is_var(p, "$v")) { if (volname) { q = volname; @@ -355,13 +334,13 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, /* 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) +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; + return 1; } @@ -375,7 +354,7 @@ static void setoption(struct vol_option *options, struct vol_option *save, int o /* ------------------------------------------ handle all the options. tmp can't be NULL. */ -static void volset(struct vol_option *options, struct vol_option *save, +static void volset(struct vol_option *options, struct vol_option *save, char *volname, int vlen, const char *tmp) { @@ -404,9 +383,9 @@ static void volset(struct vol_option *options, struct vol_option *save, 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); + 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)) { setoption(options, save, VOLOPT_ENCODING, val); } else if (optionok(tmp, "maccharset:", val)) { @@ -427,13 +406,13 @@ static void volset(struct vol_option *options, struct vol_option *save, } else if (optionok(tmp, "adouble:", val)) { if (strcasecmp(val + 1, "v1") == 0) options[VOLOPT_ADOUBLE].i_value = AD_VERSION1; -#if AD_VERSION == AD_VERSION2 +#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, "ads") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_ADS; + else if (strcasecmp(val + 1, "sfm") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM; #endif } else if (optionok(tmp, "options:", val)) { char *p; @@ -456,6 +435,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,19 +449,23 @@ static void volset(struct vol_option *options, struct vol_option *save, 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; + options[VOLOPT_PREEXEC].i_value = 1; else if (strcasecmp(p, "root_preexec_close") == 0) - options[VOLOPT_ROOTPREEXEC].i_value = 1; + options[VOLOPT_ROOTPREEXEC].i_value = 1; else if (strcasecmp(p, "upriv") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV; + else if (strcasecmp(p, "acls") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS; 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, "cachecnid") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE; + 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; p = strtok(NULL, ","); } @@ -489,7 +474,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 +1, (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); @@ -517,17 +508,31 @@ 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 if (optionok(tmp, "ea:", val)) { + if (strcasecmp(val + 1, "ad") == 0) + options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AD; + else if (strcasecmp(val + 1, "sys") == 0) + options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_SYS; + else if (strcasecmp(val + 1, "none") == 0) + options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_NONE; + } else { /* ignore unknown options */ LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp); - } + } } /* ----------------- */ static void showvol(const ucs2_t *name) { - struct vol *volume; + struct vol *volume; for ( volume = Volumes; volume; volume = volume->v_next ) { if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) { volume->v_hide = 0; @@ -537,20 +542,23 @@ static void showvol(const ucs2_t *name) } /* ------------------------------- */ -static int creatvol(AFPObj *obj, struct passwd *pwd, - char *path, char *name, - struct vol_option *options, +static int creatvol(AFPObj *obj, struct passwd *pwd, + char *path, char *name, + struct vol_option *options, const int user /* user defined volume */ - ) + ) { - struct vol *volume; - int vlen; + struct vol *volume; + int suffixlen, vlen, tmpvlen, u8mvlen, macvlen; int hide = 0; - ucs2_t tmpname[512]; + 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; if ( name == NULL || *name == '\0' ) { if ((name = strrchr( path, '/' )) == NULL) { - return -1; /* Obviously not a fully qualified path */ + return -1; /* Obviously not a fully qualified path */ } /* if you wish to share /, you need to specify a name. */ @@ -558,43 +566,106 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, return -1; } + /* suffix for mangling use (lastvid + 1) */ + /* because v_vid has not been decided yet. */ + suffixlen = sprintf(suffix, "%c%X", MANGLE_CHAR, lastvid + 1 ); + vlen = strlen( name ); - if ( vlen > AFPVOL_NAMELEN ) { - vlen = AFPVOL_NAMELEN; - name[AFPVOL_NAMELEN] = '\0'; + + /* Unicode Volume Name */ + /* Firstly convert name from unixcharset to UTF8-MAC */ + flags = CONV_IGNORE; + tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags); + if (tmpvlen <= 0) { + strcpy(tmpname, "???"); + tmpvlen = 3; + } + + /* Do we have to mangle ? */ + if ( (flags & CONV_REQMANGLE) || (tmpvlen > obj->options.volnamelen)) { + if (tmpvlen + suffixlen > obj->options.volnamelen) { + flags = CONV_FORCE; + tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, obj->options.volnamelen - suffixlen, &flags); + tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0; + } + strcat(tmpname, suffix); + tmpvlen = strlen(tmpname); } - /* convert name to UCS2 first */ - if ( 0 >= ( vlen = convert_string(obj->options.unixcharset, CH_UCS2, name, vlen, tmpname, 512)) ) + /* Secondly convert name from UTF8-MAC to UCS2 */ + if ( 0 >= ( u8mvlen = convert_string(CH_UTF8_MAC, CH_UCS2, tmpname, tmpvlen, u8mtmpname, AFPVOL_U8MNAMELEN*2)) ) return -1; - for ( volume = Volumes; volume; volume = volume->v_next ) { - if ( strcasecmp_w( volume->v_name, tmpname ) == 0 ) { - if (volume->v_deleted) { - volume->v_new = hide = 1; - } - else { - return -1; /* Won't be able to access it, anyway... */ - } + LOG(log_debug, logtype_afpd, "createvol: Volume '%s' -> UTF8-MAC Name: '%s'", name, tmpname); + + /* Maccharset Volume Name */ + /* Firsty convert name from unixcharset to maccharset */ + flags = CONV_IGNORE; + tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags); + if (tmpvlen <= 0) { + strcpy(tmpname, "???"); + tmpvlen = 3; + } + + /* Do we have to mangle ? */ + 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); + tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0; } + strcat(tmpname, suffix); + tmpvlen = strlen(tmpname); } + /* Secondly convert name from maccharset to UCS2 */ + if ( 0 >= ( macvlen = convert_string(obj->options.maccharset, CH_UCS2, tmpname, tmpvlen, mactmpname, AFPVOL_U8MNAMELEN*2)) ) + return -1; + + LOG(log_debug, 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 )){ + if (volume->v_deleted) { + volume->v_new = hide = 1; + } + else { + return -1; /* Won't be able to access it, anyway... */ + } + } + } if (!( volume = (struct vol *)calloc(1, sizeof( struct vol ))) ) { LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) ); return -1; } - if ( NULL == ( volume->v_name = strdup_w(tmpname))) { + if ( NULL == ( volume->v_localname = strdup(name))) { LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) ); free(volume); return -1; } + + if ( NULL == ( volume->v_u8mname = strdup_w(u8mtmpname))) { + LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) ); + volume_free(volume); + free(volume); + return -1; + } + if ( NULL == ( volume->v_macname = strdup_w(mactmpname))) { + LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) ); + volume_free(volume); + free(volume); + return -1; + } if (!( volume->v_path = (char *)malloc( strlen( path ) + 1 )) ) { LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) ); - free(volume->v_name); + volume_free(volume); free(volume); return -1; } + + volume->v_name = utf8_encoding()?volume->v_u8mname:volume->v_macname; volume->v_hide = hide; strcpy( volume->v_path, path ); @@ -613,12 +684,21 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, /* shift in some flags */ volume->v_flags = options[VOLOPT_FLAGS].i_value; + if (options[VOLOPT_EA_VFS].i_value) + volume->v_vfs_ea = options[VOLOPT_EA_VFS].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 ((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); @@ -634,18 +714,50 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if (options[VOLOPT_DBPATH].c_value) volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path, name); - if (options[VOLOPT_CNIDSCHEME].c_value) - volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value); + if (options[VOLOPT_CNIDSCHEME].c_value) + volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value); - if (options[VOLOPT_UMASK].i_value) - volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value; + if (options[VOLOPT_UMASK].i_value) + volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value; - if (options[VOLOPT_ADOUBLE].i_value) - volume->v_adouble = options[VOLOPT_ADOUBLE].i_value; - else - volume->v_adouble = AD_VERSION; + 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; + + /* Mac to Unix conversion flags*/ + volume->v_mtou_flags = 0; + if (!(volume->v_flags & AFPVOL_NOHEX)) + volume->v_mtou_flags |= CONV_ESCAPEHEX; + if (!(volume->v_flags & AFPVOL_USEDOTS)) + volume->v_mtou_flags |= CONV_ESCAPEDOTS; + if ((volume->v_flags & AFPVOL_EILSEQ)) + volume->v_mtou_flags |= CONV__EILSEQ; + + if ((volume->v_casefold & AFPVOL_MTOUUPPER)) + volume->v_mtou_flags |= CONV_TOUPPER; + else if ((volume->v_casefold & AFPVOL_MTOULOWER)) + volume->v_mtou_flags |= CONV_TOLOWER; + + /* Unix to Mac conversion flags*/ + volume->v_utom_flags = CONV_IGNORE | CONV_UNESCAPEHEX; + if ((volume->v_casefold & AFPVOL_UTOMUPPER)) + volume->v_utom_flags |= CONV_TOUPPER; + else if ((volume->v_casefold & AFPVOL_UTOMLOWER)) + volume->v_utom_flags |= CONV_TOLOWER; + + if ((volume->v_flags & AFPVOL_EILSEQ)) + volume->v_utom_flags |= CONV__EILSEQ; - initvol_vfs(volume); #ifdef FORCE_UIDGID if (options[VOLOPT_FORCEUID].c_value) { volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value); @@ -675,6 +787,13 @@ 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; + + /* Check EA support on volume */ + if (volume->v_vfs_ea == AFPVOL_EA_AUTO) + check_ea_sys_support(volume); + initvol_vfs(volume); volume->v_next = Volumes; Volumes = volume; @@ -682,17 +801,19 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, } /* ---------------- */ -static char *myfgets( buf, size, fp ) -char *buf; -int size; -FILE *fp; +static char *myfgets( char *buf, int size, FILE *fp) { - char *p; - int c; + char *p; + 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 { @@ -722,9 +843,9 @@ FILE *fp; */ #ifndef NO_REAL_USER_NAME -/* authentication is case insensitive +/* authentication is case insensitive * FIXME should we do the same with group name? -*/ + */ #define access_strcmp strcasecmp #else @@ -732,9 +853,7 @@ FILE *fp; #endif -static int accessvol(args, name) -const char *args; -const char *name; +static int accessvol(const char *args, const char *name) { char buf[MAXPATHLEN + 1], *p; struct group *gr; @@ -758,11 +877,77 @@ const char *name; return 0; } -static void setextmap( ext, type, creator, user) -char *ext, *type, *creator; -int user; +static int hostaccessvol(int type, const char *volname, const char *args, const AFPObj *obj) +{ + int mask_int; + char buf[MAXPATHLEN + 1], *p, *b; + DSI *dsi = obj->handle; + struct sockaddr_storage client; + + if (!args) + return -1; + + strlcpy(buf, args, sizeof(buf)); + 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; + struct addrinfo hints, *ai; + + ipaddr = strtok(p, "/"); + mask_char = strtok(NULL,"/"); + + /* Get address from string with getaddrinfo */ + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((ret = getaddrinfo(ipaddr, NULL, &hints, &ai)) != 0) { + LOG(log_error, logtype_afpd, "hostaccessvol: getaddrinfo: %s\n", gai_strerror(ret)); + continue; + } + + /* netmask */ + if (mask_char != NULL) + mask_int = atoi(mask_char); /* apply_ip_mask does range checking on it */ + else { + if (ai->ai_family == AF_INET) /* IPv4 */ + mask_int = 32; + else /* IPv6 */ + mask_int = 128; + } + + /* Apply mask to addresses */ + client = dsi->client; + apply_ip_mask((struct sockaddr *)&client, mask_int); + apply_ip_mask(ai->ai_addr, mask_int); + + if (compare_ip((struct sockaddr *)&client, ai->ai_addr) == 0) { + if (type == VOLOPT_DENIED_HOSTS) + LOG(log_info, logtype_afpd, "AFP access denied for client IP '%s' to volume '%s' by denied list", + getip_string((struct sockaddr *)&client), volname); + freeaddrinfo(ai); + return 1; + } + + /* next address */ + freeaddrinfo(ai); + 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", + getip_string((struct sockaddr *)&dsi->client), volname); + return 0; +} + +static void setextmap(char *ext, char *type, char *creator, int user) { - struct extmap *em; + struct extmap *em; int cnt; if (Extmap == NULL) { @@ -789,7 +974,7 @@ int user; return; } if (em->em_ext) - free(em->em_ext); + free(em->em_ext); if (!(em->em_ext = strdup( ext))) { LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) ); @@ -818,7 +1003,7 @@ static int extmap_cmp(const void *map1, const void *map2) static void sortextmap( void) { - struct extmap *em; + struct extmap *em; Extmap_cnt = 0; if ((em = Extmap) == NULL) { @@ -831,23 +1016,23 @@ static void sortextmap( void) 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, + /* the first line is really "." the default entry, * we remove the leading '.' in setextmap - */ + */ Defextmap = Extmap; } } } /* ---------------------- -*/ + */ static void free_extmap( void) { - struct extmap *em; + struct extmap *em; if (Extmap) { for ( em = Extmap; em->em_ext; em++) { - free (em->em_ext); + free (em->em_ext); } free(Extmap); Extmap = NULL; @@ -857,17 +1042,17 @@ static void free_extmap( void) } /* ---------------------- -*/ -static int volfile_changed(struct afp_volume_name *p) + */ +static int volfile_changed(struct afp_volume_name *p) { struct stat st; char *name; - - if (p->full_name) - name = p->full_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; return 1; @@ -879,27 +1064,25 @@ static int volfile_changed(struct afp_volume_name *p) * Read a volume configuration file and add the volumes contained within to * the global volume list. 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>,...] \ + * [] [allow:,<@group>,...] \ * [codepage:] [casefold:] - * TYPE [CREATOR] + * TYPE [CREATOR] */ -static int readvolfile(obj, p1, p2, user, pwent) -AFPObj *obj; -struct afp_volume_name *p1; -char *p2; -int user; -struct passwd *pwent; +static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent) { - FILE *fp; - char path[ MAXPATHLEN + 1], tmp[ MAXPATHLEN + 1], - volname[ AFPVOL_NAMELEN + 1 ], buf[ BUFSIZ ], - type[ 5 ], creator[ 5 ]; - char *u, *p; - struct passwd *pw; - struct vol_option options[VOLOPT_NUM], save_options[VOLOPT_NUM]; + 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; + struct passwd *pw; + struct vol_option save_options[VOLOPT_NUM]; + struct vol_option options[VOLOPT_NUM]; int i; struct stat st; int fd; @@ -926,6 +1109,11 @@ struct passwd *pwent; } memset(save_options, 0, sizeof(save_options)); + + /* 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; + while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) { initline( strlen( buf ), buf ); parseline( sizeof( path ) - 1, path ); @@ -965,10 +1153,10 @@ struct passwd *pwent; strcat( tmp, "/" ); strcat( tmp, p ); } - /* Tag a user's home directory with their umask. Note, this will - * be overwritten if the user actually specifies a umask: option - * for a '~' volume. */ - save_options[VOLOPT_UMASK].i_value = obj->options.save_mask; + /* Tag a user's home directory with their umask. Note, this will + * be overwritten if the user actually specifies a umask: option + * for a '~' volume. */ + save_options[VOLOPT_UMASK].i_value = obj->options.save_mask; /* fall through */ case '/' : @@ -980,10 +1168,10 @@ struct passwd *pwent; volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL); /* 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. + * able to specify things in any order, but i don't want to + * re-write everything. * - * currently we have options: + * currently we have options: * volname * codepage:x * casefold:x @@ -1013,17 +1201,19 @@ 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 * 2) rolist exists -> ro if user is in it. * 3) rwlist exists -> ro unless user is in it. */ if (((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))) + ((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 */ @@ -1055,8 +1245,12 @@ struct passwd *pwent; /* ------------------------------- */ static void volume_free(struct vol *vol) { - free(vol->v_name); - vol->v_name = NULL; + free(vol->v_localname); + vol->v_localname = NULL; + free(vol->v_u8mname); + vol->v_u8mname = NULL; + free(vol->v_macname); + vol->v_macname = NULL; free(vol->v_path); free(vol->v_password); free(vol->v_veto); @@ -1074,7 +1268,7 @@ static void volume_free(struct vol *vol) /* ------------------------------- */ static void free_volumes(void ) { - struct vol *vol; + struct vol *vol; struct vol *nvol, *ovol; for ( vol = Volumes; vol; vol = vol->v_next ) { @@ -1088,18 +1282,18 @@ static void free_volumes(void ) for ( vol = Volumes, ovol = NULL; vol; vol = nvol) { nvol = vol->v_next; - if (vol->v_name == NULL) { - if (Volumes == vol) { - Volumes = nvol; - ovol = Volumes; - } - else { - ovol->v_next = nvol; - } - free(vol); + if (vol->v_localname == NULL) { + if (Volumes == vol) { + Volumes = nvol; + ovol = Volumes; + } + else { + ovol->v_next = nvol; + } + free(vol); } else { - ovol = vol; + ovol = vol; } } } @@ -1107,7 +1301,7 @@ static void free_volumes(void ) /* ------------------------------- */ static void volume_unlink(struct vol *volume) { -struct vol *vol, *ovol, *nvol; + struct vol *vol, *ovol, *nvol; if (volume == Volumes) { Volumes = Volumes->v_next; @@ -1121,27 +1315,26 @@ struct vol *vol, *ovol, *nvol; break; } else { - ovol = vol; + ovol = vol; } } } -static int getvolspace( vol, bfree, btotal, xbfree, xbtotal, bsize ) -struct vol *vol; -u_int32_t *bfree, *btotal, *bsize; -VolSpace *xbfree, *xbtotal; +static int getvolspace(struct vol *vol, + u_int32_t *bfree, u_int32_t *btotal, + VolSpace *xbfree, VolSpace *xbtotal, u_int32_t *bsize) { - int spaceflag, rc; + int spaceflag, rc; u_int32_t maxsize; #ifndef NO_QUOTA_SUPPORT - VolSpace qfree, qtotal; + 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); + (((afp_version < 22) || (vol->v_flags & AFPVOL_LIMITSIZE)) + ? 0x7fffffffL : 0xffffffffL); #ifdef AFS if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) { @@ -1157,7 +1350,7 @@ VolSpace *xbfree, *xbtotal; return( rc ); } -#define min(a,b) ((a)<(b)?(a):(b)) +#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 ) { @@ -1176,14 +1369,14 @@ getvolspace_done: 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) { - struct vol *volume; - struct vol *vol = Volumes; + struct vol *volume; + struct vol *vol = Volumes; for ( volume = Volumes; volume; volume = volume->v_next ) { if (volume->v_vid == id) { @@ -1199,32 +1392,29 @@ static void vol_setdate(u_int16_t id, struct adouble *adp, time_t date) } /* ----------------------- */ -static int getvolparams( bitmap, vol, st, buf, buflen ) -u_int16_t bitmap; -struct vol *vol; -struct stat *st; -char *buf; -int *buflen; +static int getvolparams( u_int16_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; - u_short ashort; - u_int32_t bfree, btotal, bsize; + struct adouble ad; + int bit = 0, isad = 1; + u_int32_t aint; + u_short ashort; + u_int32_t bfree, btotal, bsize; VolSpace xbfree, xbtotal; /* extended bytes */ - char *data, *nameoff = NULL; + char *data, *nameoff = NULL; char *slash; + LOG(log_debug, logtype_afpd, "getvolparams: Volume '%s'", vol->v_localname); + /* courtesy of jallison@whistle.com: * 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, vol_noadouble(vol) | ADFLAGS_DIR, O_CREAT, &ad) < 0 ) { + if ( ad_open_metadata( vol->v_path, ADFLAGS_DIR, O_CREAT, &ad) < 0 ) { isad = 0; vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime); - } else if (ad_get_HF_flags( &ad ) & O_CREAT) { + } else if (ad_get_MD_flags( &ad ) & O_CREAT) { slash = strrchr( vol->v_path, '/' ); if(slash) slash++; @@ -1233,15 +1423,15 @@ int *buflen; if (ad_getentryoff(&ad, ADEID_NAME)) { ad_setentrylen( &ad, ADEID_NAME, strlen( slash )); memcpy(ad_entry( &ad, ADEID_NAME ), slash, - ad_getentrylen( &ad, ADEID_NAME )); + ad_getentrylen( &ad, ADEID_NAME )); } vol_setdate(vol->v_vid, &ad, st->st_mtime); - ad_flush_metadata(&ad); + ad_flush(&ad); } else { if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0) vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime); - else + else vol->v_ctime = aint; } @@ -1249,7 +1439,7 @@ int *buflen; (1<v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL && - (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { - ashort = VOLPBIT_ATTR_FILEID; - } /* check for read-only. * NOTE: we don't actually set the read-only flag unless * it's passed in that way as it's possible to mount * a read-write filesystem under a read-only one. */ if ((vol->v_flags & AFPVOL_RO) || - ((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) { + ((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) { ashort |= VOLPBIT_ATTR_RO; } - ashort |= VOLPBIT_ATTR_CATSEARCH; - if (afp_version >= 30) { - ashort |= VOLPBIT_ATTR_UTF8; - if (vol->v_flags & AFPVOL_UNIX_PRIV) - ashort |= VOLPBIT_ATTR_UNIXPRIV; + /* 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)) { + ashort |= VOLPBIT_ATTR_FILEID; + } + ashort |= VOLPBIT_ATTR_CATSEARCH; + + if (afp_version >= 30) { + ashort |= VOLPBIT_ATTR_UTF8; + if (vol->v_flags & AFPVOL_UNIX_PRIV) + ashort |= VOLPBIT_ATTR_UNIXPRIV; + if (vol->v_flags & AFPVOL_TM) + ashort |= VOLPBIT_ATTR_TM; + + if (afp_version >= 32) { + if (vol->v_vfs_ea) + ashort |= VOLPBIT_ATTR_EXT_ATTRS; + if (vol->v_flags & AFPVOL_ACLS) + ashort |= VOLPBIT_ATTR_ACLS; + } + } } ashort = htons(ashort); memcpy(data, &ashort, sizeof( ashort )); @@ -1380,12 +1583,13 @@ 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); - if ( aint <= 0 ) { - *buflen = 0; + /* name is always in mac charset */ + aint = ucs2_to_charset( vol->v_maccharset, vol->v_macname, data+1, AFPVOL_MACNAMELEN + 1); + if ( aint <= 0 ) { + *buflen = 0; return AFPERR_MISC; } - + *data++ = aint; data += aint; } @@ -1397,10 +1601,11 @@ int *buflen; } /* ------------------------- */ -static int 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, size_t *rbuflen) { - struct stat st; - int buflen, ret; + struct stat st; + int ret; + size_t buflen; if ( stat( vol->v_path, &st ) < 0 ) { *rbuflen = 0; @@ -1425,11 +1630,11 @@ static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) /* ------------------------------- */ void load_volumes(AFPObj *obj) { - struct passwd *pwent; + struct passwd *pwent; if (Volumes) { int changed = 0; - + /* check files date */ if (obj->options.defaultvol.loaded) { changed = volfile_changed(&obj->options.defaultvol); @@ -1442,11 +1647,11 @@ void load_volumes(AFPObj *obj) } if (!changed) return; - + free_extmap(); free_volumes(); } - + pwent = getpwnam(obj->username); if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) { readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent); @@ -1456,19 +1661,19 @@ void load_volumes(AFPObj *obj) 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. - */ + * 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 ) { + 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); } @@ -1476,10 +1681,10 @@ void load_volumes(AFPObj *obj) if ( obj->options.flags & OPTION_USERVOLFIRST ) { readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent ); } - + if ( obj->options.closevol ) { struct vol *vol; - + for ( vol = Volumes; vol; vol = vol->v_next ) { if (vol->v_deleted && !vol->v_new ) { of_closevol(vol); @@ -1491,40 +1696,48 @@ void load_volumes(AFPObj *obj) } /* ------------------------------- */ -int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf _U_, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { - struct timeval tv; - struct stat st; - struct vol *volume; - char *data; - char *namebuf; - int vcnt; - size_t len; + struct timeval tv; + struct stat st; + struct vol *volume; + char *data; + char *namebuf; + int vcnt; + size_t len; load_volumes(obj); 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) ); - continue; /* can't access directory */ + volume->v_path, strerror(errno) ); + continue; /* can't access directory */ } if (!S_ISDIR(st.st_mode)) { - continue; /* not a dir */ + 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 */ + continue; /* config file changed but the volume was mounted */ } - len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), - &namebuf, volume->v_name); - if (len == (size_t)-1) - continue; + + if (utf8_encoding()) { + len = ucs2_to_charset_allocate(CH_UTF8_MAC, &namebuf, volume->v_u8mname); + } else { + len = ucs2_to_charset_allocate(obj->options.maccharset, &namebuf, volume->v_macname); + } + + if (len == (size_t)-1) + continue; /* set password bit if there's a volume password */ *data = (volume->v_password) ? AFPSRVR_PASSWD : 0; @@ -1540,13 +1753,13 @@ int ibuflen _U_, *rbuflen; *data++ = len; memcpy(data, namebuf, len ); data += len; - free(namebuf); + free(namebuf); vcnt++; } *rbuflen = data - rbuf; data = rbuf; - if ( gettimeofday( &tv, 0 ) < 0 ) { + if ( gettimeofday( &tv, NULL ) < 0 ) { LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) ); *rbuflen = 0; return AFPERR_PARAM; @@ -1558,41 +1771,164 @@ int ibuflen _U_, *rbuflen; return( AFP_OK ); } -/* ------------------------- - * we are the user here +/* ------------------------- */ +static int volume_codepage(AFPObj *obj, struct vol *volume) +{ + struct charset_functions *charset; + /* Codepages */ + + if (!volume->v_volcodepage) + volume->v_volcodepage = strdup("UTF8"); + + if ( (charset_t) -1 == ( volume->v_volcharset = add_charset(volume->v_volcodepage)) ) { + LOG (log_error, logtype_afpd, "Setting codepage %s as volume codepage failed", volume->v_volcodepage); + return -1; + } + + if ( NULL == (charset = find_charset_functions(volume->v_volcodepage)) || charset->flags & CHARSET_ICONV ) { + LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage); + } + + if (!volume->v_maccodepage) + volume->v_maccodepage = strdup(obj->options.maccodepage); + + if ( (charset_t) -1 == ( volume->v_maccharset = add_charset(volume->v_maccodepage)) ) { + LOG (log_error, logtype_afpd, "Setting codepage %s as mac codepage failed", volume->v_maccodepage); + return -1; + } + + if ( NULL == ( charset = find_charset_functions(volume->v_maccodepage)) || ! (charset->flags & CHARSET_CLIENT) ) { + LOG (log_error, logtype_afpd, "Fatal error: mac charset %s not supported", volume->v_maccodepage); + return -1; + } + volume->v_kTextEncoding = htonl(charset->kTextEncoding); + return 0; +} + +/* ------------------------- */ +static int volume_openDB(struct vol *volume) +{ + int flags = 0; + + if ((volume->v_flags & AFPVOL_NODEV)) { + flags |= CNID_FLAG_NODEV; + } + + if (volume->v_cnidscheme == NULL) { + volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME); + LOG(log_info, logtype_afpd, "Volume %s use CNID scheme %s.", volume->v_path, volume->v_cnidscheme); + } + if (volume->v_dbpath) + volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, flags); + else + volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, flags); + + if (!volume->v_cdb) { + flags |= CNID_FLAG_MEMORY; + LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", volume->v_path); + volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags); +#ifdef SERVERTEXT + /* kill ourself with SIGUSR2 aka msg pending */ + if (volume->v_cdb) { + setmessage("Something wrong with the volume's DB ... FIXME with a better msg"); + kill(getpid(), SIGUSR2); + /* XXX desactivate cachecnid ? */ + } +#endif + } + + return (!volume->v_cdb)?-1:0; +} + +/* + Check if the underlying filesystem supports EAs for ea:sys volumes. + If not, switch to ea:ad. + As we can't check (requires write access) on ro-volumes, we switch ea:auto + volumes that are options:ro to ea:none. */ -int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +static void check_ea_sys_support(struct vol *vol) +{ + uid_t process_uid = 0; + char eaname[] = {"org.netatalk.supports-eas.XXXXXX"}; + const char *eacontent = "yes"; + + if (vol->v_vfs_ea == AFPVOL_EA_AUTO) { + + if ((vol->v_flags & AFPVOL_RO) == AFPVOL_RO) { + LOG(log_info, logtype_logger, "read-only volume '%s', can't test for EA support, disabling EAs", vol->v_localname); + vol->v_vfs_ea = AFPVOL_EA_NONE; + return; + } + + mktemp(eaname); + + process_uid = geteuid(); + if (process_uid) + if (seteuid(0) == -1) { + LOG(log_error, logtype_logger, "check_ea_sys_support: can't seteuid(0): %s", strerror(errno)); + exit(EXITERR_SYS); + } + + if ((sys_setxattr(vol->v_path, eaname, eacontent, 4, 0)) == 0) { + sys_removexattr(vol->v_path, eaname); + vol->v_vfs_ea = AFPVOL_EA_SYS; + } else { + LOG(log_warning, logtype_afpd, "volume \"%s\" does not support Extended Attributes, using ea:ad instead", + vol->v_localname); + vol->v_vfs_ea = AFPVOL_EA_AD; + } + + if (process_uid) { + if (seteuid(process_uid) == -1) { + LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno)); + exit(EXITERR_SYS); + } + } + } +} + +/* ------------------------- + * we are the user here + */ +int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { - struct stat st; - char *volname; + struct stat st; + char *volname; char *p; - struct vol *volume; - struct dir *dir; - int len, ret; - size_t namelen; - u_int16_t bitmap; + + struct vol *volume; + struct dir *dir; + int len, ret; + size_t namelen; + u_int16_t bitmap; char path[ MAXPATHLEN + 1]; char *vol_uname; char *vol_mname; + char *volname_tmp; ibuf += 2; memcpy(&bitmap, ibuf, sizeof( bitmap )); bitmap = ntohs( bitmap ); ibuf += sizeof( bitmap ); + + *rbuflen = 0; if (( bitmap & (1<oldtmp; - namelen = convert_string( (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), CH_UCS2, - ibuf, len, volname, sizeof(obj->oldtmp)); - if ( namelen <= 0){ - *rbuflen = 0; + + if ((volname_tmp = strchr(volname,'+')) != NULL) + volname = volname_tmp+1; + + if (utf8_encoding()) { + namelen = convert_string(CH_UTF8_MAC, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp)); + } else { + namelen = convert_string(obj->options.maccharset, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp)); + } + + if ( namelen <= 0) { return AFPERR_PARAM; } @@ -1609,13 +1945,11 @@ int ibuflen _U_, *rbuflen; } if ( volume == NULL ) { - *rbuflen = 0; return AFPERR_PARAM; } /* check for a volume password */ if (volume->v_password && strncmp(ibuf, volume->v_password, VOLPASSLEN)) { - *rbuflen = 0; return AFPERR_ACCESS; } @@ -1627,28 +1961,11 @@ int ibuflen _U_, *rbuflen; return stat_vol(bitmap, volume, rbuf, rbuflen); } - /* initialize volume variables - * FIXME file size - */ - if (afp_version >= 30) { - volume->max_filename = 255; - } - else { - volume->max_filename = MACFILELEN; - } - - volume->v_dir = volume->v_root = NULL; - volume->v_hash = NULL; - - volume->v_flags |= AFPVOL_OPEN; - volume->v_cdb = NULL; - if (volume->v_root_preexec) { - if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) { + if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) { LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret ); - ret = AFPERR_MISC; - goto openvol_err; - } + return AFPERR_MISC; + } } #ifdef FORCE_UIDGID @@ -1656,44 +1973,64 @@ int ibuflen _U_, *rbuflen; #endif if (volume->v_preexec) { - if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) { + 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 ); - ret = AFPERR_MISC; - goto openvol_err; - } + return AFPERR_MISC; + } } if ( stat( volume->v_path, &st ) < 0 ) { - ret = AFPERR_PARAM; - goto openvol_err; + return AFPERR_PARAM; } if ( chdir( volume->v_path ) < 0 ) { - ret = AFPERR_PARAM; - goto openvol_err; + return AFPERR_PARAM; } - len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), - volume->v_name, namelen, &vol_mname); - if ( !vol_mname || len <= 0) { - ret = AFPERR_MISC; - goto openvol_err; - } - if ( NULL == getcwd(path, MAXPATHLEN)) { /* shouldn't be fatal but it will fail later */ LOG(log_error, logtype_afpd, "afp_openvol(%s): volume pathlen too long", volume->v_path); + return AFPERR_MISC; + } + + if (volume_codepage(obj, volume) < 0) { ret = AFPERR_MISC; goto openvol_err; - } - + } + + /* initialize volume variables + * FIXME file size + */ + if (utf8_encoding()) { + volume->max_filename = 255; + } + else { + volume->max_filename = MACFILELEN; + } + + volume->v_dir = volume->v_root = NULL; + volume->v_hash = NULL; + + volume->v_flags |= AFPVOL_OPEN; + volume->v_cdb = NULL; + + if (utf8_encoding()) { + len = convert_string_allocate(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, namelen, &vol_mname); + } else { + len = convert_string_allocate(CH_UCS2, obj->options.maccharset, volume->v_macname, namelen, &vol_mname); + } + if ( !vol_mname || len <= 0) { + ret = AFPERR_MISC; + goto openvol_err; + } + if ((vol_uname = strrchr(path, '/')) == NULL) - vol_uname = path; + vol_uname = path; else if (*(vol_uname + 1) != '\0') - vol_uname++; - + vol_uname++; + if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) { - free(vol_mname); + free(vol_mname); LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) ); ret = AFPERR_MISC; goto openvol_err; @@ -1704,61 +2041,23 @@ int ibuflen _U_, *rbuflen; dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */ dir->d_m_name_ucs2 = strdup_w(volume->v_name); volume->v_dir = volume->v_root = dir; + volume->v_curdir = NULL; volume->v_hash = dirhash(); curdir = volume->v_dir; - if (volume->v_cnidscheme == NULL) { - volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME); - LOG(log_warning, logtype_afpd, "Warning: No CNID scheme for volume %s. Using default.", - volume->v_path); - } - if (volume->v_dbpath) - volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV)); - else - volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV)); - if (volume->v_cdb == NULL) { - LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s", - volume->v_path, volume->v_cnidscheme); + if (volume_openDB(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; goto openvol_err; } - /* Codepages */ - - if (!volume->v_volcodepage) - volume->v_volcodepage = strdup("UTF8"); - - if ( (charset_t) -1 == ( volume->v_volcharset = add_charset(volume->v_volcodepage)) ) { - LOG (log_error, logtype_afpd, "Setting codepage %s as volume codepage failed", volume->v_volcodepage); - ret = AFPERR_MISC; - goto openvol_err; - } - - if ( NULL == ( volume->v_vol = find_charset_functions(volume->v_volcodepage)) || volume->v_vol->flags & CHARSET_ICONV ) { - LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage); - } - - if (!volume->v_maccodepage) - volume->v_maccodepage = strdup(obj->options.maccodepage); - - if ( (charset_t) -1 == ( volume->v_maccharset = add_charset(volume->v_maccodepage)) ) { - LOG (log_error, logtype_afpd, "Setting codepage %s as mac codepage failed", volume->v_maccodepage); - ret = AFPERR_MISC; - goto openvol_err; - } - - if ( NULL == ( volume->v_mac = find_charset_functions(volume->v_maccodepage)) || ! (volume->v_mac->flags & CHARSET_CLIENT) ) { - LOG (log_error, logtype_afpd, "Fatal error: mac charset %s not supported", volume->v_maccodepage); - ret = AFPERR_MISC; - goto openvol_err; - } - ret = stat_vol(bitmap, volume, rbuf, rbuflen); if (ret == AFP_OK) { if (!(volume->v_flags & AFPVOL_RO)) { handle_special_folders( volume ); - savevoloptions( volume); + savevolinfo(volume, Cnid_srv, Cnid_port); } /* @@ -1773,14 +2072,14 @@ int ibuflen _U_, *rbuflen; /* FIXME find db time stamp */ if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) { - 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; - } - } - else { + 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; + } + } + else { p = Trash; cname( volume, volume->v_dir, &p ); } @@ -1789,7 +2088,7 @@ int ibuflen _U_, *rbuflen; openvol_err: if (volume->v_dir) { - hash_free( volume->v_hash); + hash_free( volume->v_hash); dirfree( volume->v_dir ); volume->v_dir = volume->v_root = NULL; } @@ -1804,7 +2103,7 @@ openvol_err: } /* ------------------------- */ -static void closevol(struct vol *vol) +static void closevol(struct vol *vol) { if (!vol) return; @@ -1818,17 +2117,17 @@ static void closevol(struct vol *vol) } if (vol->v_postexec) { - afprun(0, vol->v_postexec, NULL); + afprun(0, vol->v_postexec, NULL); } if (vol->v_root_postexec) { - afprun(1, vol->v_root_postexec, NULL); + afprun(1, vol->v_root_postexec, NULL); } } /* ------------------------- */ void close_all_vol(void) { - struct vol *ovol; + struct vol *ovol; curdir = NULL; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { if ( (ovol->v_flags & AFPVOL_OPEN) ) { @@ -1841,7 +2140,7 @@ void close_all_vol(void) /* ------------------------- */ static void deletevol(struct vol *vol) { - struct vol *ovol; + struct vol *ovol; vol->v_flags &= ~AFPVOL_OPEN; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { @@ -1858,21 +2157,18 @@ static void deletevol(struct vol *vol) closevol(vol); if (vol->v_deleted) { - showvol(vol->v_name); - volume_free(vol); - volume_unlink(vol); - free(vol); + showvol(vol->v_name); + volume_free(vol); + volume_unlink(vol); + free(vol); } } /* ------------------------- */ -int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf _U_; -int ibuflen _U_, *rbuflen; +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; + struct vol *vol; + u_int16_t vid; *rbuflen = 0; ibuf += 2; @@ -1889,7 +2185,7 @@ int ibuflen _U_, *rbuflen; /* ------------------------- */ struct vol *getvolbyvid(const u_int16_t vid ) { - struct vol *vol; + struct vol *vol; for ( vol = Volumes; vol; vol = vol->v_next ) { if ( vid == vol->v_vid ) { @@ -1916,14 +2212,14 @@ static int ext_cmp_key(const void *key, const void *obj) } struct extmap *getextmap(const char *path) { - char *p; + char *p; struct extmap *em; - if (NULL == ( p = strrchr( path, '.' )) ) { + if (!Extmap_cnt || NULL == ( p = strrchr( path, '.' )) ) { return( Defextmap ); } p++; - if (!*p || !Extmap_cnt) { + if (!*p) { return( Defextmap ); } em = bsearch(p, Extmap, Extmap_cnt, sizeof(struct extmap), ext_cmp_key); @@ -1942,19 +2238,28 @@ struct extmap *getdefextmap(void) /* -------------------------- poll if a volume is changed by other processes. + return + 0 no attention msg sent + 1 attention msg sent + -1 error (socket closed) + + Note: if attention return -1 no packet has been + sent because the buffer is full, we don't care + either there's no reader or there's a lot of + traffic and another pollvoltime will follow */ -int pollvoltime(obj) -AFPObj *obj; +int pollvoltime(AFPObj *obj) + { - struct vol *vol; + struct vol *vol; struct timeval tv; struct stat st; - - if (!(afp_version > 21 && obj->options.server_notif)) - return 0; - if ( gettimeofday( &tv, 0 ) < 0 ) - return 0; + if (!(afp_version > 21 && obj->options.server_notif)) + return 0; + + if ( gettimeofday( &tv, NULL ) < 0 ) + return 0; for ( vol = Volumes; vol; vol = vol->v_next ) { if ( (vol->v_flags & AFPVOL_OPEN) && vol->v_mtime + 30 < tv.tv_sec) { @@ -1970,11 +2275,9 @@ AFPObj *obj; } /* ------------------------- */ -void setvoltime(obj, vol ) -AFPObj *obj; -struct vol *vol; +void setvoltime(AFPObj *obj, struct vol *vol) { - struct timeval tv; + struct timeval tv; /* just looking at vol->v_mtime is broken seriously since updates * from other users afpd processes never are seen. @@ -1982,7 +2285,7 @@ struct vol *vol; * the afpd processes would come closer) * [RS] */ - if ( gettimeofday( &tv, 0 ) < 0 ) { + if ( gettimeofday( &tv, NULL ) < 0 ) { LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) ); return; } @@ -1995,21 +2298,20 @@ struct vol *vol; /* a little granularity */ if (vol->v_mtime < tv.tv_sec) { vol->v_mtime = tv.tv_sec; - /* or finder doesn't update free space */ - if (afp_version > 21 && obj->options.server_notif) { + /* 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); } } } /* ------------------------- */ -int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +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; + struct vol *vol; + u_int16_t vid, bitmap; ibuf += 2; memcpy(&vid, ibuf, sizeof( vid )); @@ -2026,14 +2328,11 @@ int ibuflen _U_, *rbuflen; } /* ------------------------- */ -int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf _U_; -int ibuflen _U_, *rbuflen; +int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { struct adouble ad; - struct vol *vol; - u_int16_t vid, bitmap; + struct vol *vol; + u_int16_t vid, bitmap; u_int32_t aint; ibuf += 2; @@ -2067,7 +2366,7 @@ int ibuflen _U_, *rbuflen; memcpy(&aint, ibuf, sizeof(aint)); ad_setdate(&ad, AD_DATE_BACKUP, aint); - ad_flush(&ad, ADFLAGS_HF); + ad_flush(&ad); ad_close(&ad, ADFLAGS_HF); return( AFP_OK ); } @@ -2100,219 +2399,100 @@ int wincheck(const struct vol *vol, const char *path) /* - * precreate a folder - * this is only intended for folders in the volume root - * It will *not* work if the folder name contains extended characters + * precreate a folder + * this is only intended for folders in the volume root + * It will *not* work if the folder name contains extended characters */ static int create_special_folder (const struct vol *vol, const struct _special_folder *folder) { - char *p,*q,*r; - struct adouble ad; - u_int16_t attr; - struct stat st; - int ret; - - - p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2); - if ( p == NULL) { - LOG(log_error, logtype_afpd,"malloc failed"); - exit (EXITERR_SYS); - } - - q=strdup(folder->name); - if ( q == NULL) { - LOG(log_error, logtype_afpd,"malloc failed"); - exit (EXITERR_SYS); - } - - strcpy(p, vol->v_path); - strcat(p, "/"); - - r=q; - while (*r) { - if ((vol->v_casefold & AFPVOL_MTOUUPPER)) - *r=toupper(*r); - else if ((vol->v_casefold & AFPVOL_MTOULOWER)) - *r=tolower(*r); - r++; - } - strcat(p, q); - - if ( (ret = stat( p, &st )) < 0 ) { - if (folder->precreate) { - if (ad_mkdir(p, folder->mode)) { - LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno)); - free(p); - free(q); - return -1; - } - ret = 0; - } - } - - if ( !ret && folder->hide) { - /* Hide it */ - 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); - free(q); - return (-1); - } - if ((ad_get_HF_flags( &ad ) & O_CREAT) ) { - if (ad_getentryoff(&ad, ADEID_NAME)) { - ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name)); - memcpy(ad_entry( &ad, ADEID_NAME ), folder->name, - ad_getentrylen( &ad, ADEID_NAME )); - } - } - - 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 ); - } - free(p); - free(q); - return 0; -} - -static void handle_special_folders (const struct vol * vol) -{ - const _special_folder *p = &special_folders[0]; + char *p,*q,*r; + struct adouble ad; + u_int16_t attr; + struct stat st; + int ret; - if ((vol->v_flags & AFPVOL_RO)) - return; - for (; p->name != NULL; p++) { - create_special_folder (vol, p); - } -} + p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2); + if ( p == NULL) { + LOG(log_error, logtype_afpd,"malloc failed"); + exit (EXITERR_SYS); + } -/* - * Save the volume options to a file, used by - * shell utilities. - * Writing the file everytime a volume is opened is - * unnecessary, but it shouldn't hurt much. - */ -static int savevoloptions (const struct vol *vol) -{ - char buf[16348]; - char item[MAXPATHLEN]; - int fd; - int ret = 0; - struct flock lock; - const _vol_opt_name *op = &vol_opt_names[0]; - const _vol_opt_name *cf = &vol_opt_casefold[0]; - - strlcpy (item, vol->v_path, sizeof(item)); - strlcat (item, "/.AppleDesktop/", sizeof(item)); - strlcat (item, VOLINFOFILE, sizeof(item)); - - if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) { - LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno)); - return (-1); - } - - /* try to get a lock */ - lock.l_start = 0; - lock.l_whence = SEEK_SET; - lock.l_len = 0; - lock.l_type = F_WRLCK; - - if (fcntl(fd, F_SETLK, &lock) < 0) { - if (errno == EACCES || errno == EAGAIN) { - /* ignore, other process already writing the file */ - return 0; - } else { - LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno)); - return (-1); - } + q=strdup(folder->name); + if ( q == NULL) { + LOG(log_error, logtype_afpd,"malloc failed"); + exit (EXITERR_SYS); } - /* write volume options */ - snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage); - snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage); - strlcat(buf, item, sizeof(buf)); + strcpy(p, vol->v_path); + strcat(p, "/"); - switch (vol->v_adouble) { - case AD_VERSION1: - strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf)); - break; - case AD_VERSION2: - strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf)); - break; - case AD_VERSION2_OSX: - strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf)); - break; - case AD_VERSION1_ADS: - strlcat(buf, "ADOUBLE_VER:ads\n", sizeof(buf)); - break; + r=q; + while (*r) { + if ((vol->v_casefold & AFPVOL_MTOUUPPER)) + *r=toupper(*r); + else if ((vol->v_casefold & AFPVOL_MTOULOWER)) + *r=tolower(*r); + r++; } + strcat(p, q); - strlcat(buf, "CNIDBACKEND:", sizeof(buf)); - strlcat(buf, vol->v_cnidscheme, sizeof(buf)); - strlcat(buf, "\n", sizeof(buf)); - - strlcat(buf, "CNIDDBDHOST:", sizeof(buf)); - strlcat(buf, Cnid_srv, sizeof(buf)); - strlcat(buf, "\n", sizeof(buf)); + if ( (ret = stat( p, &st )) < 0 ) { + if (folder->precreate) { + if (ad_mkdir(p, folder->mode)) { + LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno)); + free(p); + free(q); + return -1; + } + ret = 0; + } + } - snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port); - strlcat(buf, item, sizeof(buf)); + if ( !ret && folder->hide) { + /* Hide it */ + ad_init(&ad, vol->v_adouble, vol->v_ad_options); + if (ad_open( p, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR|O_CREAT, 0666, &ad) < 0) { + free (p); + free(q); + return (-1); + } + if ((ad_get_HF_flags( &ad ) & O_CREAT) ) { + if (ad_getentryoff(&ad, ADEID_NAME)) { + ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name)); + memcpy(ad_entry( &ad, ADEID_NAME ), folder->name, + ad_getentrylen( &ad, ADEID_NAME )); + } + } - strcpy(item, "CNID_DBPATH:"); - if (vol->v_dbpath) - strlcat(item, vol->v_dbpath, sizeof(item)); - else - strlcat(item, vol->v_path, sizeof(item)); - strlcat(item, "\n", sizeof(item)); - strlcat(buf, item, sizeof(buf)); + ad_getattr(&ad, &attr); + attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE ); + ad_setattr(&ad, attr); - /* volume flags */ - strcpy(item, "VOLUME_OPTS:"); - for (;op->name; op++) { - if ( (vol->v_flags & op->option) ) { - strlcat(item, op->name, sizeof(item)); - strlcat(item, " ", sizeof(item)); + /* 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)); } - } - strlcat(item, "\n", sizeof(item)); - strlcat(buf, item, sizeof(buf)); - /* casefold flags */ - strcpy(item, "VOLCASEFOLD:"); - for (;cf->name; cf++) { - if ( (vol->v_casefold & cf->option) ) { - strlcat(item, cf->name, sizeof(item)); - strlcat(item, " ", sizeof(item)); - } + ad_flush( &ad ); + ad_close( &ad, ADFLAGS_HF ); } - strlcat(item, "\n", sizeof(item)); - strlcat(buf, item, sizeof(buf)); - - if (strlen(buf) >= sizeof(buf)-1) - LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf); + free(p); + free(q); + return 0; +} +static void handle_special_folders (const struct vol * vol) +{ + const _special_folder *p = &special_folders[0]; - if (write( fd, buf, strlen(buf)) < 0) { - LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno)); - goto done; - } - ftruncate(fd, strlen(buf)); + if ((vol->v_flags & AFPVOL_RO)) + return; -done: - lock.l_type = F_UNLCK; - fcntl(fd, F_SETLK, &lock); - close (fd); - return ret; + for (; p->name != NULL; p++) { + create_special_folder (vol, p); + } } +