]> arthur.barton.de Git - netatalk.git/commitdiff
EA VFS: chmod for files and directorires
authorfranklahm <franklahm>
Tue, 20 Oct 2009 08:38:41 +0000 (08:38 +0000)
committerfranklahm <franklahm>
Tue, 20 Oct 2009 08:38:41 +0000 (08:38 +0000)
include/atalk/ea.h
libatalk/vfs/ea.c
libatalk/vfs/vfs.c

index c590a3d15fdac70175f2b8ec6954d7e3b9c869c7..53ace0e622a33a043917c056ff569b2c915e9cd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   $Id: ea.h,v 1.4 2009-10-15 15:00:55 franklahm Exp $
+   $Id: ea.h,v 1.5 2009-10-20 08:38:41 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
@@ -127,6 +127,8 @@ extern int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE);
 extern int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE);
 extern int ea_copyfile(VFS_FUNC_ARGS_COPYFILE);
 extern int ea_chown(VFS_FUNC_ARGS_CHOWN);
+extern int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE);
+extern int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE);
 
 /* Solaris native EAs */
 #ifdef HAVE_SOLARIS_EAS
index e6222b98dd0099a7e99a45ae805aa813c6b3a7d8..069676b625ed120c213722a466f1fc29b2ba53b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: ea.c,v 1.6 2009-10-15 15:35:05 franklahm Exp $
+  $Id: ea.c,v 1.7 2009-10-20 08:38:41 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
  * - store EAs in files "fileWithEAs::EA::testEA1" and "fileWithEAs::EA::testEA2"
  */
 
+/* 
+ * Build mode for EA header from file mode
+ */
+static inline mode_t ea_header_mode(mode_t mode)
+{
+    /* Same as ad_hf_mode(mode) */
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+    /* Owner must be able to open, read and w-lock it, in order to chmod from eg 0000 -> 0xxxx*/
+    mode |= S_IRUSR | S_IWUSR;
+    return mode;
+}
+
+/* 
+ * Build mode for EA file from file mode
+ */
+static inline mode_t ea_mode(mode_t mode)
+{
+    /* Same as ad_hf_mode(mode) */
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+    return mode;
+}
+
 /*
  * Function: unpack_header
  *
@@ -655,7 +677,7 @@ static int ea_open(const struct vol * restrict vol,
 
     /* Now lock, open and read header file from disk */
     if ((ea->ea_fd = open(eaname, (ea->ea_flags & EA_RDWR) ? O_RDWR : O_RDONLY)) == -1) {
-        LOG(log_error, logtype_afpd, "ea_open: error on open for header: %s", eaname);
+        LOG(log_error, logtype_afpd, "ea_open('%s'): error: %s", eaname, strerror(errno));
         ret = -1;
         goto exit;
     }
@@ -1802,3 +1824,150 @@ exit:
 
     return ret;
 }
+
+int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
+{
+    LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name);
+
+    int count = 0, ret = AFP_OK;
+    const char *eaname;
+    struct ea ea;
+
+    /* Open EA stuff */
+    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else
+            return AFPERR_MISC;
+    }
+
+    /* Set mode on EA header file */
+    if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL), strerror(errno));
+        switch (errno) {
+        case EPERM:
+        case EACCES:
+            ret = AFPERR_ACCESS;
+            goto exit;
+        default:
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    /* Set mode on EA files */
+    while (count < ea.ea_count) {
+        eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name);
+        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
+            switch (errno) {
+            case EPERM:
+            case EACCES:
+                ret = AFPERR_ACCESS;
+                goto exit;
+            default:
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            continue;
+        }
+
+        count++;
+    }
+
+exit:
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): error closing ea handle", name);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
+{
+    LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name);
+
+    int ret = AFP_OK;
+    uid_t uid;
+    const char *eaname;
+    const char *eaname_safe = NULL;
+    struct ea ea;
+
+    /* .AppleDouble already might be inaccesible, so we must run as id 0 */
+    uid = geteuid();
+    if (seteuid(0)) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno));
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    /* Open EA stuff */
+    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else
+            return AFPERR_MISC;
+    }
+
+    /* Set mode on EA header */
+    if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL), strerror(errno));
+        switch (errno) {
+        case EPERM:
+        case EACCES:
+            ret = AFPERR_ACCESS;
+            goto exit;
+        default:
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    /* Set mode on EA files */
+    int count = 0;
+    while (count < ea.ea_count) {
+        eaname = (*ea.ea_entries)[count].ea_name;
+        /*
+         * Be careful with EA names from the EA header!
+         * Eg NFS users might have access to them, can inject paths using ../ or /.....
+         * FIXME:
+         * Until the EA code escapes / in EA name requests from the client, these therefor wont work.
+         */
+        if ((eaname_safe = strrchr(eaname, '/'))) {
+            LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname);
+            eaname = eaname_safe;
+        }
+        eaname = ea_path(&ea, eaname);
+        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
+            switch (errno) {
+            case EPERM:
+            case EACCES:
+                ret = AFPERR_ACCESS;
+                goto exit;
+            default:
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            continue;
+        }
+
+        count++;
+    }
+
+exit:
+    if (seteuid(uid) < 0) {
+        LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
+        exit(EXITERR_SYS);
+    }
+
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): error closing ea handle", name);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
index b160646e2b076fc0cb95239806f903e655f379f2..a3d5dbdfc35312484bc9acb255414a1dfa997645 100644 (file)
@@ -917,10 +917,10 @@ struct vfs_ops netatalk_ea_adouble = {
     /* vfs_chown:         */ ea_chown,
     /* vfs_renamedir:     */ NULL, /* ok */
     /* vfs_deletecurdir:  */ NULL, /* ok */
-    /* vfs_setfilmode:    */ NULL,
-    /* vfs_setdirmode:    */ NULL,
-    /* vfs_setdirunixmode:*/ NULL,
-    /* vfs_setdirowner:   */ NULL,
+    /* vfs_setfilmode:    */ ea_chmod_file,
+    /* vfs_setdirmode:    */ NULL, /* ok */
+    /* vfs_setdirunixmode:*/ ea_chmod_dir,
+    /* vfs_setdirowner:   */ NULL, /* ok */
     /* vfs_deletefile:    */ ea_deletefile,
     /* vfs_renamefile:    */ ea_renamefile,
     /* vfs_copyfile       */ ea_copyfile,