]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/volume.c
Revert upriv -> noupriv change
[netatalk.git] / etc / afpd / volume.c
index 2bfd81138427bed77770b660f862314c347de3e6..1a7380a86fc3f58bf0a2610939c723fc36e06e1b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: volume.c,v 1.111 2009-12-17 09:25:40 franklahm Exp $
+ * $Id: volume.c,v 1.125 2010-04-08 05:51:16 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -92,45 +92,37 @@ static void             free_extmap(void);
 #define VOLOPT_CASEFOLD   5  /* character case mangling */
 #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<u -> map u to m
-                                !u  -> make u illegal always
-                                ~u  -> make u illegal only as the first
-                                part of a double-byte character.
-                             */
+/* Usable slots: 8 and 9 */
 #define VOLOPT_VETO          10  /* list of veto filespec */
 #define VOLOPT_PREEXEC       11  /* preexec command */
 #define VOLOPT_ROOTPREEXEC   12  /* root preexec command */
-
 #define VOLOPT_POSTEXEC      13  /* postexec command */
 #define VOLOPT_ROOTPOSTEXEC  14  /* root postexec command */
-
 #define VOLOPT_ENCODING      15  /* mac encoding (pre OSX)*/
 #define VOLOPT_MACCHARSET    16
 #define VOLOPT_CNIDSCHEME    17
 #define VOLOPT_ADOUBLE       18  /* adouble version */
+
 #ifdef FORCE_UIDGID
 #warning UIDGID
 #include "uid.h"
 
-#define VOLOPT_FORCEUID  19  /* force uid for username x */
-#define VOLOPT_FORCEGID  20  /* force gid for group x */
+#define VOLOPT_FORCEUID      19  /* force uid for username x */
+#define VOLOPT_FORCEGID      20  /* force gid for group x */
 #endif /* FORCE_UIDGID */
 
-#define VOLOPT_UMASK     21
+#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_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_CNIDSERVER    28  /* CNID Server ip address*/
+#define VOLOPT_CNIDPORT      30  /* CNID server tcp port */
 
-#define VOLOPT_MAX       28  /* <== IMPORTANT !!!!!! */
-#define VOLOPT_NUM       (VOLOPT_MAX + 1)
+#define VOLOPT_MAX           31  /* <== IMPORTANT !!!!!! */
+#define VOLOPT_NUM           (VOLOPT_MAX + 1)
 
 #define VOLPASSLEN  8
 #define VOLOPT_DEFAULT     ":DEFAULT:"
@@ -158,12 +150,13 @@ static const _special_folder special_folders[] = {
 #endif
     {NULL, 0, 0, 0}};
 
+/* Forward declarations */
 static void handle_special_folders (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 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;
 
@@ -469,6 +462,18 @@ static void volset(struct vol_option *options, struct vol_option *save,
             p = strtok(NULL, ",");
         }
 
+    } else if (optionok(tmp, "cnidserver:", val)) {
+        setoption(options, save, VOLOPT_CNIDSERVER, val);
+
+        char *p = strrchr(val + 1, ':');
+        if (p) {
+            *p = 0;
+            setoption(options, save, VOLOPT_CNIDPORT, p);
+        }
+
+        LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s",
+            volname, val + 1, p ? p + 1 : Cnid_port);
+
     } else if (optionok(tmp, "dbpath:", val)) {
         setoption(options, save, VOLOPT_DBPATH, val);
 
@@ -480,9 +485,6 @@ static void volset(struct vol_option *options, struct vol_option *save,
         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);
-
     } else if (optionok(tmp, "password:", val)) {
         setoption(options, save, VOLOPT_PASSWORD, val);
 
@@ -516,6 +518,10 @@ static void volset(struct vol_option *options, struct vol_option *save,
     } 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 */
@@ -670,7 +676,6 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     /* os X start at 1 and use network order ie. 1 2 3 */
     volume->v_vid = ++lastvid;
     volume->v_vid = htons(volume->v_vid);
-    volume->v_vfs_ea = AFPVOL_EA_SYS;
 
     /* handle options */
     if (options) {
@@ -692,6 +697,8 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
             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);
@@ -711,6 +718,12 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
         if (options[VOLOPT_CNIDSCHEME].c_value)
             volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value);
 
+        if (options[VOLOPT_CNIDSERVER].c_value)
+            volume->v_cnidserver = strdup(options[VOLOPT_CNIDSERVER].c_value);
+
+        if (options[VOLOPT_CNIDPORT].c_value)
+            volume->v_cnidport = strdup(options[VOLOPT_CNIDPORT].c_value);
+
         if (options[VOLOPT_UMASK].i_value)
             volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
 
@@ -752,8 +765,6 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
         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);
@@ -786,6 +797,11 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
     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;
     return 0;
@@ -973,12 +989,12 @@ static void setextmap(char *ext, char *type, char *creator, int user)
     }
 
     if ( *type == '\0' ) {
-        memcpy(em->em_type, "????", sizeof( em->em_type ));
+        memcpy(em->em_type, "\0\0\0\0", sizeof( em->em_type ));
     } else {
         memcpy(em->em_type, type, sizeof( em->em_type ));
     }
     if ( *creator == '\0' ) {
-        memcpy(em->em_creator, "UNIX", sizeof( em->em_creator ));
+        memcpy(em->em_creator, "\0\0\0\0", sizeof( em->em_creator ));
     } else {
         memcpy(em->em_creator, creator, sizeof( em->em_creator ));
     }
@@ -1065,12 +1081,15 @@ static int volfile_changed(struct afp_volume_name *p)
 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_U8MNAMELEN + 1 ], buf[ BUFSIZ ],
-        type[ 5 ], creator[ 5 ];
+    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   options[VOLOPT_NUM], save_options[VOLOPT_NUM];
+    struct vol_option   save_options[VOLOPT_NUM];
+    struct vol_option   options[VOLOPT_NUM];
     int                 i;
     struct stat         st;
     int                 fd;
@@ -1100,6 +1119,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
 
     /* 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 );
@@ -1397,7 +1417,7 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha
      * .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);
 
@@ -1805,15 +1825,20 @@ static int volume_openDB(struct vol *volume)
         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);
+
+    LOG(log_info, logtype_afpd, "%s:%s", volume->v_cnidserver, volume->v_cnidport);
+    
+    volume->v_cdb = cnid_open(volume->v_dbpath ? volume->v_dbpath : volume->v_path,
+                              volume->v_umask,
+                              volume->v_cnidscheme,
+                              flags,
+                              volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
+                              volume->v_cnidport ? volume->v_cnidport : Cnid_port);
 
     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);
+        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL);
 #ifdef SERVERTEXT
         /* kill ourself with SIGUSR2 aka msg pending */
         if (volume->v_cdb) {
@@ -1830,15 +1855,23 @@ static int volume_openDB(struct vol *volume)
 /* 
    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.
 */
 static void check_ea_sys_support(struct vol *vol)
 {
     uid_t process_uid = 0;
-    const char *fname = ".";
     char eaname[] = {"org.netatalk.supports-eas.XXXXXX"};
     const char *eacontent = "yes";
 
-    if (vol->v_vfs_ea == AFPVOL_EA_SYS) {
+    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();
@@ -1848,15 +1881,15 @@ static void check_ea_sys_support(struct vol *vol)
                 exit(EXITERR_SYS);
             }
 
-        if ((sys_setxattr(fname, eaname, eacontent, 4, 0)) == -1) {
+        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;
-            initvol_vfs(vol);
         }
 
-        sys_removexattr(fname, eaname);
-
         if (process_uid) {
             if (seteuid(process_uid) == -1) {
                 LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno));
@@ -1972,6 +2005,27 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
         return AFPERR_MISC;
     }
 
+    /* Normalize volume path */
+#ifdef REALPATH_TAKES_NULL
+    if ((volume->v_path = realpath(path, NULL)) == NULL)
+        return AFPERR_MISC;
+#else
+    if ((volume->v_path = malloc(MAXPATHLEN+1)) == NULL)
+        return AFPERR_MISC;
+    if (realpath(path, volume->v_path) == NULL) {
+        free(volume->v_path);
+        return AFPERR_MISC;
+    }
+    /* Safe some memory */
+    char *tmp;
+    if ((tmp = strdup(volume->v_path)) == NULL) {
+        free(volume->v_path);
+        return AFPERR_MISC;
+    } 
+    free(volume->v_path);
+    volume->v_path = tmp;
+#endif
+
     if (volume_codepage(obj, volume) < 0) {
         ret = AFPERR_MISC;
         goto openvol_err;
@@ -2036,8 +2090,9 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
 
         if (!(volume->v_flags & AFPVOL_RO)) {
             handle_special_folders( volume );
-            check_ea_sys_support(volume);
-            savevolinfo(volume, Cnid_srv, Cnid_port);
+            savevolinfo(volume,
+                        volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
+                        volume->v_cnidport   ? volume->v_cnidport   : Cnid_port);
         }
 
         /*
@@ -2279,9 +2334,9 @@ void setvoltime(AFPObj *obj, struct vol *vol)
     if (vol->v_mtime < tv.tv_sec) {
         vol->v_mtime = tv.tv_sec;
         /* or finder doesn't update free space
-         * XXX is it still true with newer OSX?
+         * AFP 3.2 and above clients seem to be ok without so many notification
          */
-        if (afp_version > 21 && obj->options.server_notif) {
+        if (afp_version < 32 && obj->options.server_notif) {
             obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
         }
     }
@@ -2432,19 +2487,13 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
     if ( !ret && folder->hide) {
         /* Hide it */
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR,
-                     O_RDWR|O_CREAT, 0666, &ad) < 0) {
+        if (ad_open_metadata( p, ADFLAGS_DIR, O_CREAT, &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_setname(&ad, folder->name);
 
         ad_getattr(&ad, &attr);
         attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
@@ -2458,7 +2507,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
         }
 
         ad_flush( &ad );
-        ad_close( &ad, ADFLAGS_HF );
+        ad_close_metadata( &ad);
     }
     free(p);
     free(q);