]> arthur.barton.de Git - netatalk.git/commitdiff
Volname mangling. Fixes bug #2611981, from HAT. Also add new logger doc to afpd.conf...
authorfranklahm <franklahm>
Mon, 16 Mar 2009 13:59:11 +0000 (13:59 +0000)
committerfranklahm <franklahm>
Mon, 16 Mar 2009 13:59:11 +0000 (13:59 +0000)
config/afpd.conf.tmpl
etc/afpd/afp_options.c
etc/afpd/directory.c
etc/afpd/globals.h
etc/afpd/volume.c
etc/afpd/volume.h

index 08e32ac56ef7720c48a4714d54529731e0c11884..0364b891871b779bc4532a2f6fbbe2b0677ec545 100644 (file)
 #                         timing out a connection.  The default is 4, therefore
 #                         a connection will timeout in 2 minutes.
 #     -icon               Use the platform-specific icon.
+#     -volnamelen <number>
+#                         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 "<logtype> <loglevel> [<filename>]"
-#                         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:<text> | host }
 #                         Specify a server signature. This option is useful while
index e0294e771516950e14ee57501caa0ac46efea858..414629b5e3008c50c04aad18a5dfdc6dca0ff29c 100644 (file)
@@ -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 <logtype> <loglevel> [<filename>]*/
     if ((c = getoption(buf, "-setuplog"))) {
       char *ptr, *logtype, *loglevel, *filename;
index f778b1535feb07841a3628865f0d40a48e7c453e..d8f83a84402cffe2413d600d8c1a660a4572cbf7 100644 (file)
@@ -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 <name>
+                   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);
index 531c62e6f26608888429acc07f391057332063b3..d5aa7b61273d816b09db683010534c9adf181733 100644 (file)
@@ -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)
index c3c0c4eac60e8c717e586b1de444774ea3a572da..f4d58f606376c37778a71d92222d9bc6dd31c76f 100644 (file)
@@ -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);
index b1a801636d5425e4e34769f5a3c4a93302a88fed..c955c894ce689e0e358a5d9df4dcc7a6a96b6759 100644 (file)
@@ -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.
 #include "afp_vfs.h"
 #include "hash.h"
 
-#define AFPVOL_NAMELEN   27
+#define AFPVOL_U8MNAMELEN   255 /* AFP3 sepc */
+#define AFPVOL_MACNAMELEN    27 /* AFP2 spec */
 
 #include <atalk/cnid.h>
 
 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;