]> arthur.barton.de Git - netatalk.git/commitdiff
Fixes
authorFrank Lahm <franklahm@googlemail.com>
Sun, 25 Dec 2011 12:34:00 +0000 (13:34 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Sun, 25 Dec 2011 12:34:00 +0000 (13:34 +0100)
etc/afpd/fork.c
include/atalk/adouble.h
libatalk/adouble/ad_open.c

index d3c4b531bd2d4f036caef5fbc877315335f3175c..4ba0caf9de0f5e44c66d246f6cf0f7bf3b854e85 100644 (file)
@@ -323,7 +323,8 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     ret = AFPERR_NOOBJ;
     if (access & OPENACC_WR) {
         /* try opening in read-write mode */
-        if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR) < 0) {
+        if (ad_open(ofork->of_ad, upath,
+                    adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
@@ -333,14 +334,16 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
             case ENOENT:
                 if (fork == OPENFORK_DATA) {
                     /* try to open only the data fork */
-                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDWR) < 0) {
+                    if (ad_open(ofork->of_ad, upath,
+                                ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
                         goto openfork_err;
                     }
                     adflags = ADFLAGS_DF;
                 } else {
                     /* here's the deal. we only try to create the resource
                      * fork if the user wants to open it for write acess. */
-                    if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) < 0)
+                    if (ad_open(ofork->of_ad, upath,
+                                adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
                         goto openfork_err;
                     ofork->of_flags |= AFPFORK_OPEN;
                 }
@@ -368,17 +371,18 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     } else {
         /* try opening in read-only mode */
         ret = AFPERR_NOOBJ;
-        if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY) < 0) {
+        /* we need w access for setting deny mode fcntl excl lock */
+        if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
+                goto openfork_err;
             case EACCES:
                 goto openfork_err;
-                break;
             case ENOENT:
                 /* see if client asked for a read only data fork */
                 if (fork == OPENFORK_DATA) {
-                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY) < 0) {
+                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
                         goto openfork_err;
                     }
                     adflags = ADFLAGS_DF;
index 777cbe80efbc492e2128c325f619a4362aa3a67e..d4558f5ec6a6c2b1c8c42d60a0120e9d40124518 100644 (file)
@@ -214,12 +214,17 @@ struct adouble {
 #define ADFLAGS_DIR       (1<<3)
 #define ADFLAGS_NOHF      (1<<4)  /* not an error if no ressource fork */
 #define ADFLAGS_CHECK_OF  (1<<6)  /* check for open forks from us and other afpd's */
-
-#define ADFLAGS_RDWR      (1<<7)  /* open read/write */
-#define ADFLAGS_RDONLY    (1<<8)  /* open read only */
-#define ADFLAGS_CREATE    (1<<9)  /* create file, open called with O_CREAT */
-#define ADFLAGS_EXCL      (1<<10)  /* exclusive open, open called with O_EXCL */
-#define ADFLAGS_TRUNC     (1<<11) /* truncate, open called with O_TRUNC */
+#define ADFLAGS_SETSHRMD  (1<<7)  /* setting share mode must be done with excl fcnt lock,
+                                     which implies that the file must be openend rw.
+                                     If it can't be opened rw (eg EPERM or EROFS) it will
+                                     be opened ro and the fcntl locks will be shared, that
+                                     at least prevent other users who have rw access to the
+                                     file from placing excl locks. */
+#define ADFLAGS_RDWR      (1<<8)  /* open read/write */
+#define ADFLAGS_RDONLY    (1<<9)  /* open read only */
+#define ADFLAGS_CREATE    (1<<10)  /* create file, open called with O_CREAT */
+#define ADFLAGS_EXCL      (1<<11)  /* exclusive open, open called with O_EXCL */
+#define ADFLAGS_TRUNC     (1<<12) /* truncate, open called with O_TRUNC */
 
 #define ADVOL_NODEV      (1 << 0)
 #define ADVOL_CACHE      (1 << 1)
index f039da9fa37dcb77e24814dc7ab6cc7cc83bace9..d4011a9c4d0a314c0ee9172fb07f30b23e8ea586 100644 (file)
@@ -575,7 +575,9 @@ static int ad2openflags(int adflags)
 
     if (adflags & ADFLAGS_RDWR)
         oflags |= O_RDWR;
-    if (adflags & ADFLAGS_RDONLY)
+    if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_SETSHRMD))
+        oflags |= O_RDWR;
+    else
         oflags |= O_RDONLY;
     if (adflags & ADFLAGS_CREATE)
         oflags |= O_CREAT;
@@ -624,16 +626,29 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble
     ad->ad_data_fork.adf_fd = open(path, oflags, admode);
 
     if (ad->ad_data_fork.adf_fd == -1) {
-        if (errno != OPEN_NOFOLLOW_ERRNO)
+        switch (errno) {
+        case EPERM:
+        case EROFS:
+            if ((adflags & ADFLAGS_SETSHRMD) && (adflags & ADFLAGS_RDONLY)) {
+                oflags &= ~O_RDWR;
+                oflags |= O_RDONLY;
+                if ((ad->ad_data_fork.adf_fd = open(path, oflags, admode)) == -1)
+                    return -1;
+                break;
+            }
             return -1;
-
-        ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
-        if ((lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN)) <= 0) {
-            free(ad->ad_data_fork.adf_syml);
+        case OPEN_NOFOLLOW_ERRNO:
+            ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
+            if ((lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN)) <= 0) {
+                free(ad->ad_data_fork.adf_syml);
+                return -1;
+            }
+            ad->ad_data_fork.adf_syml[lsz] = 0;
+            ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+            break;
+        default:
             return -1;
         }
-        ad->ad_data_fork.adf_syml[lsz] = 0;
-        ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
     }
 
     if (!st_invalid)
@@ -674,43 +689,58 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou
     ad_p = ad->ad_ops->ad_path(path, adflags);
     oflags = O_NOFOLLOW | ad2openflags(adflags);
     nocreatflags = oflags & ~(O_CREAT | O_EXCL);
+
     ad->ad_mdp->adf_fd = open(ad_p, nocreatflags);
 
-    if ( ad->ad_mdp->adf_fd < 0 ) {
-        if (!(errno == ENOENT && (oflags & O_CREAT)))
-            return ad_error(ad, adflags);
-        /*
-         * We're expecting to create a new adouble header file here
-         * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
-         */
-        LOG(log_debug, logtype_default, "ad_open(\"%s\"): creating adouble file",
-            fullpathname(path));
-        admode = mode;
-        errno = 0;
-        st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
-        if ((ad->ad_options & ADVOL_UNIXPRIV))
-            admode = mode;
-        admode = ad_hf_mode(admode);
-        if (errno == ENOENT) {
-            if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
-                return ad_error(ad, adflags);
+    if (ad->ad_mdp->adf_fd < 0) {
+        switch (errno) {
+        case EPERM:
+        case EROFS:
+            if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_SETSHRMD)) {
+                nocreatflags &= ~O_RDWR;
+                nocreatflags |= O_RDONLY;
+                if ((ad->ad_mdp->adf_fd = open(ad_p, nocreatflags)) == -1)
+                    return -1;
+                break;
             }
+            return -1;
+        case ENOENT:
+            if (!(oflags & O_CREAT))
+                return ad_error(ad, adflags);
+            /*
+             * We're expecting to create a new adouble header file here
+             * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
+             */
+            LOG(log_debug, logtype_default, "ad_open(\"%s\"): creating adouble file",
+                fullpathname(path));
             admode = mode;
+            errno = 0;
             st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
             if ((ad->ad_options & ADVOL_UNIXPRIV))
                 admode = mode;
             admode = ad_hf_mode(admode);
-        }
+            if (errno == ENOENT) {
+                if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+                    return ad_error(ad, adflags);
+                }
+                admode = mode;
+                st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+                if ((ad->ad_options & ADVOL_UNIXPRIV))
+                    admode = mode;
+                admode = ad_hf_mode(admode);
+            }
 
-        /* retry with O_CREAT */
-        ad->ad_mdp->adf_fd = open(ad_p, oflags, admode);
-        if ( ad->ad_mdp->adf_fd < 0 )
-            return ad_error(ad, adflags);
+            /* retry with O_CREAT */
+            ad->ad_mdp->adf_fd = open(ad_p, oflags, admode);
+            if ( ad->ad_mdp->adf_fd < 0 )
+                return ad_error(ad, adflags);
 
-        ad->ad_mdp->adf_flags = oflags;
-        /* just created, set owner if admin owner (root) */
-        if (!st_invalid)
-            ad_chown(ad_p, &st_dir);
+            ad->ad_mdp->adf_flags = oflags;
+            /* just created, set owner if admin owner (root) */
+            if (!st_invalid)
+                ad_chown(ad_p, &st_dir);
+            break;
+        }
     } else {
         ad->ad_mdp->adf_flags = nocreatflags;
         if (fstat(ad->ad_mdp->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
@@ -1162,7 +1192,7 @@ int ad_metadata(const char *name, int flags, struct adouble *adp)
 
     oflags = (flags & ADFLAGS_DIR) | ADFLAGS_HF | ADFLAGS_RDONLY;
 
-    if ((ret = ad_open(adp, name, oflags)) < 0 && errno == EACCES) {
+    if ((ret = ad_open(adp, name, oflags | ADFLAGS_SETSHRMD)) < 0 && errno == EACCES) {
         uid = geteuid();
         if (seteuid(0)) {
             LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));