]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/directory.c
Move volume loading to libatalk
[netatalk.git] / etc / afpd / directory.c
index 53bfb201092f2b545e14d3431df0842a79464f0c..844d346a1f9d45d6c804d33c7ed06798d051503b 100644 (file)
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <grp.h>
 #include <pwd.h>
 #include <sys/param.h>
@@ -31,6 +32,7 @@
 #include <atalk/errchk.h>
 #include <atalk/globals.h>
 #include <atalk/fce_api.h>
+#include <atalk/netatalk_conf.h>
 
 #include "directory.h"
 #include "dircache.h"
@@ -1412,11 +1414,8 @@ int movecwd(const struct vol *vol, struct dir *dir)
  * If we aren't the file's owner we can't change its perms when moving it and smb
  * nfs,... don't even try.
  */
-#define AFP_CHECK_ACCESS
-
-int check_access(char *path, int mode)
+int check_access(const AFPObj *obj, struct vol *vol, char *path, int mode)
 {
-#ifdef AFP_CHECK_ACCESS
     struct maccess ma;
     char *p;
 
@@ -1424,21 +1423,21 @@ int check_access(char *path, int mode)
     if (!p)
         return -1;
 
-    accessmode(current_vol, p, &ma, curdir, NULL);
+    accessmode(obj, vol, p, &ma, curdir, NULL);
     if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
         return -1;
     if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
         return -1;
-#endif
+
     return 0;
 }
 
 /* --------------------- */
-int file_access(struct path *path, int mode)
+int file_access(const AFPObj *obj, struct vol *vol, struct path *path, int mode)
 {
     struct maccess ma;
 
-    accessmode(current_vol, path->u_name, &ma, curdir, &path->st);
+    accessmode(obj, vol, path->u_name, &ma, curdir, &path->st);
 
     LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x",
         path->u_name, ma.ma_user);
@@ -1477,7 +1476,8 @@ int dirreenumerate(struct dir *dir, struct stat *st)
    (name, dir) with curdir:name == dir, from afp_enumerate
 */
 
-int getdirparams(const struct vol *vol,
+int getdirparams(const AFPObj *obj,
+                 const struct vol *vol,
                  uint16_t bitmap, struct path *s_path,
                  struct dir *dir,
                  char *buf, size_t *buflen )
@@ -1642,7 +1642,7 @@ int getdirparams(const struct vol *vol,
             break;
 
         case DIRPBIT_ACCESS :
-            accessmode(vol, upath, &ma, dir , st);
+            accessmode(obj, vol, upath, &ma, dir , st);
 
             *data++ = ma.ma_user;
             *data++ = ma.ma_world;
@@ -1678,7 +1678,7 @@ int getdirparams(const struct vol *vol,
 
         case DIRPBIT_UNIXPR :
             /* accessmode may change st_mode with ACLs */
-            accessmode(vol, upath, &ma, dir, st);
+            accessmode(obj, vol, upath, &ma, dir, st);
 
             aint = htonl(st->st_uid);
             memcpy( data, &aint, sizeof( aint ));
@@ -1796,8 +1796,6 @@ int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
 }
 
 /*
- * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
- *
  * assume path == '\0' eg. it's a directory in canonical form
  */
 int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *buf )
@@ -1809,7 +1807,7 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
 
     char                *upath;
     struct dir          *dir;
-    int         bit, isad = 1;
+    int         bit, isad = 0;
     int                 cdate, bdate;
     int                 owner, group;
     uint16_t       ashort, bshort, oshort;
@@ -1821,7 +1819,9 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
     u_char              finder_buf[32];
     uint32_t       upriv;
     mode_t              mpriv = 0;
-    uint16_t           upriv_bit = 0;
+    bool                set_upriv = false, set_maccess = false;
+
+    LOG(log_debug, logtype_afpd, "setdirparams(\"%s\", bitmap: %02x)", path->u_name, bitmap);
 
     bit = 0;
     upath = path->u_name;
@@ -1858,27 +1858,21 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
             buf += 32;
             break;
         case DIRPBIT_UID :  /* What kind of loser mounts as root? */
-            change_parent_mdate = 1;
             memcpy( &owner, buf, sizeof(owner));
             buf += sizeof( owner );
             break;
         case DIRPBIT_GID :
-            change_parent_mdate = 1;
             memcpy( &group, buf, sizeof( group ));
             buf += sizeof( group );
             break;
         case DIRPBIT_ACCESS :
+            set_maccess = true;
             change_mdate = 1;
-            change_parent_mdate = 1;
             ma.ma_user = *buf++;
             ma.ma_world = *buf++;
             ma.ma_group = *buf++;
             ma.ma_owner = *buf++;
             mpriv = mtoumode( &ma ) | vol->v_dperm;
-            if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
-                err = set_dir_errors(path, "setdirmode", errno);
-                bitmap = 0;
-            }
             break;
             /* Ignore what the client thinks we should do to the
                ProDOS information block.  Skip over the data and
@@ -1894,27 +1888,16 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
             break;
         case DIRPBIT_UNIXPR :
             if (vol_unix_priv(vol)) {
+                set_upriv = true;
                 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
                 buf += sizeof( owner );
                 memcpy( &group, buf, sizeof( group ));
                 buf += sizeof( group );
 
                 change_mdate = 1;
-                change_parent_mdate = 1;
                 memcpy( &upriv, buf, sizeof( upriv ));
                 buf += sizeof( upriv );
                 upriv = ntohl (upriv) | vol->v_dperm;
-                if (dir_rx_set(upriv)) {
-                    /* maybe we are trying to set perms back */
-                    if ( setdirunixmode(vol, upath, upriv) < 0 ) {
-                        bitmap = 0;
-                        err = set_dir_errors(path, "setdirunixmode", errno);
-                    }
-                }
-                else {
-                    /* do it later */
-                    upriv_bit = 1;
-                }
                 break;
             }
             /* fall through */
@@ -1927,33 +1910,17 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
         bitmap = bitmap>>1;
         bit++;
     }
-    ad_init(&ad, vol);
 
-    if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
-        /*
-         * Check to see what we're trying to set.  If it's anything
-         * but ACCESS, UID, or GID, give an error.  If it's any of those
-         * three, we don't need the ad to be open, so just continue.
-         *
-         * note: we also don't need to worry about mdate. also, be quiet
-         *       if we're using the noadouble option.
-         */
-        if (!vol_noadouble(vol) && (d_bitmap &
-                                    ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
-                                      (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
-                                      (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
+    if (d_bitmap & ((1<<DIRPBIT_ATTR) | (1<<DIRPBIT_CDATE) | (1<<DIRPBIT_BDATE) | (1<<DIRPBIT_FINFO))) {
+        ad_init(&ad, vol);
+        if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
+            LOG(log_debug, logtype_afpd, "setdirparams(\"%s\", bitmap: %02x): need adouble", path->u_name, d_bitmap);
             return AFPERR_ACCESS;
         }
-
-        isad = 0;
-    } else {
-        /*
-         * Check to see if a create was necessary. If it was, we'll want
-         * to set our name, etc.
-         */
-        if ( (ad_get_MD_flags( &ad ) & O_CREAT)) {
+        if ((ad_get_MD_flags(&ad) & O_CREAT)) {
             ad_setname(&ad, cfrombstr(curdir->d_m_name));
         }
+        isad = 1;
     }
 
     bit = 0;
@@ -2038,19 +2005,6 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
             }
             break;
         case DIRPBIT_ACCESS :
-            if (dir->d_did == DIRDID_ROOT) {
-                setdeskmode(mpriv);
-                if (!dir_rx_set(mpriv)) {
-                    /* we can't remove read and search for owner on volume root */
-                    err = AFPERR_ACCESS;
-                    goto setdirparam_done;
-                }
-            }
-
-            if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
-                err = set_dir_errors(path, "setdirmode", errno);
-                goto setdirparam_done;
-            }
             break;
         case DIRPBIT_PDINFO :
             if (afp_version >= 30) {
@@ -2059,27 +2013,7 @@ int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *bu
             }
             break;
         case DIRPBIT_UNIXPR :
-            if (vol_unix_priv(vol)) {
-                if (dir->d_did == DIRDID_ROOT) {
-                    if (!dir_rx_set(upriv)) {
-                        /* we can't remove read and search for owner on volume root */
-                        err = AFPERR_ACCESS;
-                        goto setdirparam_done;
-                    }
-                    setdeskowner( -1, ntohl(group) );
-                    setdeskmode( upriv );
-                }
-                if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
-                    err = set_dir_errors(path, "setdirowner", errno);
-                    goto setdirparam_done;
-                }
-
-                if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
-                    err = set_dir_errors(path, "setdirunixmode", errno);
-                    goto setdirparam_done;
-                }
-            }
-            else {
+            if (!vol_unix_priv(vol)) {
                 err = AFPERR_BITMAP;
                 goto setdirparam_done;
             }
@@ -2105,18 +2039,69 @@ setdirparam_done:
         utime(upath, &ut);
     }
 
-    if ( isad ) {
+    if (isad) {
         if (path->st_valid && !path->st_errno) {
             struct stat *st = &path->st;
-
             if (dir && dir->d_pdid) {
                 ad_setid(&ad, st->st_dev, st->st_ino,  dir->d_did, dir->d_pdid, vol->v_stamp);
             }
         }
-        ad_flush(&ad);
+        if (ad_flush(&ad) != 0) {
+            switch (errno) {
+            case EACCES:
+                err = AFPERR_ACCESS;
+                break;
+            default:
+                err = AFPERR_MISC;
+                break;
+           }
+        }
         ad_close(&ad, ADFLAGS_HF);
     }
 
+    if (err == AFP_OK) {
+        if (set_maccess == true) {
+            if (dir->d_did == DIRDID_ROOT) {
+                setdeskmode(mpriv);
+                if (!dir_rx_set(mpriv)) {
+                    /* we can't remove read and search for owner on volume root */
+                    err = AFPERR_ACCESS;
+                    goto setprivdone;
+                }
+            }
+            if (setdirunixmode(vol, upath, mpriv) < 0) {
+                LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirunixmode: %s",
+                    fullpathname(upath), strerror(errno));
+                err = set_dir_errors(path, "setdirmode", errno);
+            }
+        }
+        if ((set_upriv == true) && vol_unix_priv(vol)) {
+            if (dir->d_did == DIRDID_ROOT) {
+                if (!dir_rx_set(upriv)) {
+                    /* we can't remove read and search for owner on volume root */
+                    err = AFPERR_ACCESS;
+                    goto setprivdone;
+                }
+                setdeskowner(-1, ntohl(group));
+                setdeskmode(upriv);
+            }
+
+            if (setdirowner(vol, upath, -1, ntohl(group)) < 0) {
+                LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirowner: %s",
+                    fullpathname(upath), strerror(errno));
+                err = set_dir_errors(path, "setdirowner", errno);
+                goto setprivdone;
+            }
+
+            if (setdirunixmode(vol, upath, upriv) < 0) {
+                LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirunixmode: %s",
+                    fullpathname(upath), strerror(errno));
+                err = set_dir_errors(path, "setdirunixmode", errno);
+            }
+        }
+    }
+
+setprivdone:
     if (change_parent_mdate && dir->d_did != DIRDID_ROOT
         && gettimeofday(&tv, NULL) == 0) {
         if (movecwd(vol, dirlookup(vol, dir->d_pdid)) == 0) {
@@ -2127,7 +2112,6 @@ setdirparam_done:
             /* should we reset curdir ?*/
         }
     }
-
     return err;
 }
 
@@ -2283,8 +2267,6 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
 
     ad_init(&ad, vol);
     if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) < 0)  {
-        if (vol_noadouble(vol))
-            goto createdir_done;
         return( AFPERR_ACCESS );
     }
     ad_setname(&ad, s_path->m_name);