From: franklahm Date: Mon, 16 Mar 2009 13:59:11 +0000 (+0000) Subject: Volname mangling. Fixes bug #2611981, from HAT. Also add new logger doc to afpd.conf... X-Git-Tag: before-dbd-overhaul~25 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=914bcb1bf563396f50c85d92023fb9b8efe2af25 Volname mangling. Fixes bug #2611981, from HAT. Also add new logger doc to afpd.conf.tmpl --- diff --git a/config/afpd.conf.tmpl b/config/afpd.conf.tmpl index 08e32ac5..0364b891 100644 --- a/config/afpd.conf.tmpl +++ b/config/afpd.conf.tmpl @@ -131,26 +131,35 @@ # timing out a connection. The default is 4, therefore # a connection will timeout in 2 minutes. # -icon Use the platform-specific icon. +# -volnamelen +# Max length of UTF8-MAC volume name for Mac OS X. +# Note that Hangul is especially sensitive to this. +# 31: conservative default +# 80: limit for Mac OS X 10.5 +# 255: limit of spec +# Mac OS 9 and earlier are not influenced by this, +# Maccharset volume name is always 27 limit. # -[un]setuplog " []" -# Specify that the given loglevel should be applied -# to log messages of the given logtype and that -# these messages should be logged to the given file. -# If the filename is ommited the loglevel applies to -# messages passed to syslog. -# Each logtype may have a loglevel applied to syslog -# and a loglevel applied to a single file. Latter -# -setuplog settings will override earlier ones of -# the same logtype (file or syslog). -# logtypes: Default, Core, Logger, CNID, AFPDaemon -# loglevels: LOG_SEVERE, LOG_ERROR, LOG_WARN, LOG_NOTE, -# LOG_INFO, LOG_DEBUG, LOG_DEBUG6, LOG_DEBUG7, -# LOG_DEBUG8, LOG_DEBUG9, LOG_MAXDEBUG -# -# for example: -# -setuplog "logger log_maxdebug /var/log/netatalk-logger.log" -# -setuplog "afpdaemon log_maxdebug /var/log/netatalk-afp.log" -# -unsetuplog "default level file" -# -setuplog "default log_maxdebug" +# Specify that any message of a loglevel up to the given loglevel +# should be logged to the given file. If the filename is ommited the +# loglevel applies to messages passed to syslog. Latter -setuplog +# settings will override earlier ones of the same logtype (file or +# syslog). +# +# By default (no explicit -setuplog and no buildtime configure flag +# --with-logfile) all netatalk daemons log to syslog with a default +# logging setup equivalent to "-setuplog default log_debug". +# +# If build with --with-logfile (default logfile +# /var/log/netatalk.log) or --with-logfile=somefile all daemons +# default to a setup that is equivalent to "-setuplog default +# log_info [netatalk.log|somefile]" +# +# Example: Useful default config +# -setuplog "default log_info /var/log/afpd.log" +# +# Debugging config +# -setuplog "default log_maxdebug /var/log/afpd.log" # # -signature { user: | host } # Specify a server signature. This option is useful while diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index e0294e77..414629b5 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -1,5 +1,5 @@ /* - * $Id: afp_options.c,v 1.38 2009-02-27 09:14:40 franklahm Exp $ + * $Id: afp_options.c,v 1.39 2009-03-16 13:59:12 franklahm Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * Copyright (c) 1990,1993 Regents of The University of Michigan. @@ -186,7 +186,7 @@ void afp_options_init(struct afp_options *options) options->unixcodepage = "LOCALE"; options->maccharset = CH_MAC; options->maccodepage = "MAC_ROMAN"; - + options->volnamelen = 31; /* Conservative default. 10.4/10.5 can handle up to 80 */ options->ntdomain = NULL; options->ntseparator = NULL; } @@ -308,6 +308,16 @@ int afp_options_parseline(char *buf, struct afp_options *options) if ((c = getoption(buf, "-server_quantum"))) options->server_quantum = strtoul(c, NULL, 0); + if ((c = getoption(buf, "-volnamelen"))) { + options->volnamelen = atoi(c); + if (options->volnamelen < 8) { + options->volnamelen = 8; /* max mangled volname "???#FFFF" */ + } + if (options->volnamelen > 255) { + options->volnamelen = 255; /* AFP3 spec */ + } + } + /* -[no]setuplog []*/ if ((c = getoption(buf, "-setuplog"))) { char *ptr, *logtype, *loglevel, *filename; diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index f778b153..d8f83a84 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.92 2009-03-15 13:00:14 franklahm Exp $ + * $Id: directory.c,v 1.93 2009-03-16 13:59:12 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -444,6 +444,7 @@ static void dir_hash_del(const struct vol *vol, struct dir *dir) /* remove the node from the tree. this is just like insertion, but * different. actually, it has to worry about a bunch of things that * insertion doesn't care about. */ + static void dir_remove( const struct vol *vol _U_, struct dir *dir) { #ifdef REMOVE_NODES @@ -1264,12 +1265,24 @@ char **cpath; if (toUTF8) { static char temp[ MAXPATHLEN + 1]; - /* not an UTF8 name */ - if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) { - afp_errno = AFPERR_PARAM; - return( NULL ); + if (dir->d_did == DIRDID_ROOT_PARENT) { + /* + With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981. + So we compare it with the longname from the current volume and if they match + we overwrite the requested path with the utf8 volume name so that the following + strcmp can match. + */ + ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1); + if (strcasecmp( path, temp) == 0) + ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN); + } else { + /* toUTF8 */ + if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) { + afp_errno = AFPERR_PARAM; + return( NULL ); + } + strcpy(path, temp); } - strcpy(path, temp); } /* check for OS X mangled filename :( */ @@ -1293,15 +1306,14 @@ char **cpath; } if ( !extend ) { if (dir->d_did == DIRDID_ROOT_PARENT) { - /* root parent has only one child and d_m_name is *NOT* utm (d_u_name) - * d_m_name is the Mac volume name - * d_u_name is the volume unix directory name - * - */ - cdir = NULL; - if (!strcmp(vol->v_dir->d_m_name, ret.m_name)) { - cdir = vol->v_dir; - } + /* + root parent (did 1) has one child: the volume. Requests for did=1 with some + must check against the volume name. + */ + if (!strcmp(vol->v_dir->d_m_name, ret.m_name)) + cdir = vol->v_dir; + else + cdir = NULL; } else { cdir = dirsearch_byname(vol, dir, ret.u_name); diff --git a/etc/afpd/globals.h b/etc/afpd/globals.h index 531c62e6..d5aa7b61 100644 --- a/etc/afpd/globals.h +++ b/etc/afpd/globals.h @@ -1,5 +1,5 @@ /* - * $Id: globals.h,v 1.25 2009-02-02 11:55:00 franklahm Exp $ + * $Id: globals.h,v 1.26 2009-03-16 13:59:12 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -79,10 +79,10 @@ struct afp_options { #ifdef ADMIN_GRP gid_t admingid; #endif /* ADMIN_GRP */ + int volnamelen; /* default value for winbind authentication */ char *ntdomain, *ntseparator; - }; #define AFPOBJ_TMPSIZ (MAXPATHLEN) diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index c3c0c4ea..f4d58f60 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.80 2009-02-16 13:49:20 franklahm Exp $ + * $Id: volume.c,v 1.81 2009-03-16 13:59:12 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -53,6 +53,7 @@ char *strchr (), *strrchr (); #include "file.h" #include "volume.h" #include "unix.h" +#include "mangle.h" #include "fork.h" extern int afprun(int root, char *cmd, int *outfd); @@ -190,6 +191,7 @@ static const _vol_opt_name vol_opt_casefold[] = { 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 volfree(struct vol_option *options, const struct vol_option *save) @@ -548,7 +550,7 @@ static void showvol(const ucs2_t *name) { struct vol *volume; for ( volume = Volumes; volume; volume = volume->v_next ) { - if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) { + if (volume->v_hide && !strcasecmp_w( (utf8_encoding()?volume->v_u8mname:volume->v_macname), name ) ) { volume->v_hide = 0; return; } @@ -563,9 +565,12 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, ) { struct vol *volume; - int vlen; + 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) { @@ -577,18 +582,70 @@ 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 != (size_t)-1 ? tmpvlen : 0] = 0; + } + strcat(tmpname, suffix); + tmpvlen = strlen(tmpname); + } + + /* 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; + + 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; } - /* convert name to UCS2 first */ - if ( 0 >= ( vlen = convert_string(obj->options.unixcharset, CH_UCS2, name, vlen, tmpname, 512)) ) + /* 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 != (size_t)-1 ? tmpvlen : 0] = 0; + } + if (*tmpname == 0) { + strcat(tmpname, "???"); + } + 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_name, tmpname ) == 0 ) { + if (( strcasecmp_w( volume->v_u8mname, u8mtmpname ) == 0 ) || ( strcasecmp_w( volume->v_macname, mactmpname ) == 0 )){ if (volume->v_deleted) { volume->v_new = hide = 1; } @@ -598,19 +655,31 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, } } - 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; } @@ -934,7 +1003,7 @@ struct passwd *pwent; { FILE *fp; char path[ MAXPATHLEN + 1], tmp[ MAXPATHLEN + 1], - volname[ AFPVOL_NAMELEN + 1 ], buf[ BUFSIZ ], + volname[ AFPVOL_U8MNAMELEN + 1 ], buf[ BUFSIZ ], type[ 5 ], creator[ 5 ]; char *u, *p; struct passwd *pw; @@ -1094,8 +1163,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); @@ -1127,7 +1200,7 @@ static void free_volumes(void ) for ( vol = Volumes, ovol = NULL; vol; vol = nvol) { nvol = vol->v_next; - if (vol->v_name == NULL) { + if (vol->v_localname == NULL) { if (Volumes == vol) { Volumes = nvol; ovol = Volumes; @@ -1254,6 +1327,8 @@ int *buflen; 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. */ @@ -1425,8 +1500,8 @@ int *buflen; if ( nameoff ) { ashort = htons( data - buf ); memcpy(nameoff, &ashort, sizeof( ashort )); - /* name is always in mac charset, FIXME mangle if length > 27 char */ - aint = ucs2_to_charset( vol->v_maccharset, vol->v_name, data+1, 255); + /* 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; @@ -1573,8 +1648,13 @@ int ibuflen _U_, *rbuflen; if (volume->v_hide) { 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 (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; @@ -1646,8 +1726,12 @@ int ibuflen _U_, *rbuflen; if ((volname_tmp = strchr(volname,'+')) != NULL) volname = volname_tmp+1; - namelen = convert_string( (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), CH_UCS2, - ibuf, len, volname, sizeof(obj->oldtmp)); + 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){ *rbuflen = 0; return AFPERR_PARAM; @@ -1660,7 +1744,7 @@ int ibuflen _U_, *rbuflen; load_volumes(obj); for ( volume = Volumes; volume; volume = volume->v_next ) { - if ( strcasecmp_w( (ucs2_t*) volname, volume->v_name ) == 0 ) { + if ( strcasecmp_w( (ucs2_t*) volname, (utf8_encoding()?volume->v_u8mname:volume->v_macname) ) == 0 ) { break; } } @@ -1687,7 +1771,7 @@ int ibuflen _U_, *rbuflen; /* initialize volume variables * FIXME file size */ - if (afp_version >= 30) { + if (utf8_encoding()) { volume->max_filename = 255; } else { @@ -1730,8 +1814,11 @@ int ibuflen _U_, *rbuflen; goto openvol_err; } - len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), - volume->v_name, namelen, &vol_mname); + 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; @@ -1914,7 +2001,7 @@ static void deletevol(struct vol *vol) closevol(vol); if (vol->v_deleted) { - showvol(vol->v_name); + showvol(utf8_encoding()?vol->v_u8mname:vol->v_macname); volume_free(vol); volume_unlink(vol); free(vol); diff --git a/etc/afpd/volume.h b/etc/afpd/volume.h index b1a80163..c955c894 100644 --- a/etc/afpd/volume.h +++ b/etc/afpd/volume.h @@ -1,5 +1,5 @@ /* - * $Id: volume.h,v 1.28 2009-02-16 13:49:20 franklahm Exp $ + * $Id: volume.h,v 1.29 2009-03-16 13:59:12 franklahm Exp $ * * Copyright (c) 1990,1994 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -17,13 +17,16 @@ #include "afp_vfs.h" #include "hash.h" -#define AFPVOL_NAMELEN 27 +#define AFPVOL_U8MNAMELEN 255 /* AFP3 sepc */ +#define AFPVOL_MACNAMELEN 27 /* AFP2 spec */ #include struct vol { struct vol *v_next; - ucs2_t *v_name; + char *v_localname; /* as defined in AppleVolumes.default */ + ucs2_t *v_u8mname; /* converted to utf8-mac in ucs2 */ + ucs2_t *v_macname; /* mangled to legacy longname in ucs2 */ char *v_path; struct dir *v_dir, *v_root;