]> arthur.barton.de Git - netatalk.git/commitdiff
Add negative UUID caching, enhance local UUID handling
authorFrank Lahm <franklahm@googlemail.com>
Tue, 17 May 2011 14:56:44 +0000 (16:56 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Tue, 17 May 2011 14:56:44 +0000 (16:56 +0200)
NEWS
bin/misc/uuidtest.c
etc/afpd/acls.c
etc/afpd/afp_dsi.c
etc/afpd/directory.c
include/atalk/uuid.h
libatalk/acl/cache.c
libatalk/acl/cache.h
libatalk/acl/uuid.c

diff --git a/NEWS b/NEWS
index 4ea4a49eb6be6971ce6eb576f87769641cd2aa6b..b7bf9d05e0743d72e815791e0997037ccf985bb3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Changes in 2.2
 * UPD: afpd: only forward SIGTERM and SIGUSR1 from parent to childs
 * UPD: afpd: use internal function instead of popening du -sh in order to
        calculate the used size of a volume for option "volsizelimit"
+* UPD: afpd: Add negative UUID caching, enhance local UUID handling
 * FIX: afpd: configuration reload with SIGHUP
 * FIX: afpd: crashes in the dircache
 * FIX: afpd: Correct afp logout vs dsi eof behaviour
index b12585ee9b7e57a2a7e57fdff81330d7e3de218f..0efc3318c6a45d0fe25c85b3cdf5016b9c548789 100644 (file)
@@ -123,15 +123,15 @@ int main( int argc, char **argv)
             ret = getnamefromuuid( uuid, &name, &type);
             if (ret == 0) {
                 switch (type) {
-                case UUID_LOCAL:
-                    printf("local UUID: %s\n", optarg);
-                    break;
                 case UUID_USER:
                     printf("UUID: %s ==> User: %s\n", optarg, name);
                     break;
                 case UUID_GROUP:
                     printf("UUID: %s ==> Group: %s\n", optarg, name);
                     break;
+                default:
+                    printf("???: %s\n", optarg);
+                    break;
                 }
                 free(name);
             } else {
index 4dd127b1fb33ef2e8e61f5089c34bb1076d3ea95..74f7f0a5f7461c491d04c46a76c1f0c32e6b0faa 100644 (file)
@@ -638,10 +638,6 @@ static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
          /* uid/gid */
         EC_ZERO_LOG(getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype));
         switch (uuidtype) {
-        case UUID_LOCAL:
-            free(name);
-            name = NULL;
-            continue;
         case UUID_USER:
             EC_NULL_LOG(pwd = getpwnam(name));
             tag = ACL_USER;
@@ -654,6 +650,8 @@ static int map_aces_darwin_to_posix(const darwin_ace_t *darwin_aces,
             id = (uid_t)(grp->gr_gid);
             LOG(log_debug, logtype_afpd, "map_ace: name: %s, gid: %u", name, id);
             break;
+        default:
+            continue;
         }
         free(name);
         name = NULL;
@@ -1128,9 +1126,7 @@ static int check_acl_access(const struct vol *vol,
         LOG(log_warning, logtype_afpd, "check_access: afp_access not supported for groups");
         EC_STATUS(AFPERR_MISC);
         goto EC_CLEANUP;
-
-    case UUID_LOCAL:
-        LOG(log_warning, logtype_afpd, "check_access: local UUID");
+    default:
         EC_STATUS(AFPERR_MISC);
         goto EC_CLEANUP;
     }
index 7b10ad0c0ed2a625f96af9060613ef7060153afb..c9c3da92e2c8cc97282268393165dab09ce3267d 100644 (file)
@@ -31,6 +31,7 @@
 #include <atalk/dsi.h>
 #include <atalk/compat.h>
 #include <atalk/util.h>
+#include <atalk/uuid.h>
 
 #include "globals.h"
 #include "switch.h"
@@ -524,6 +525,7 @@ void afp_over_dsi(AFPObj *obj)
             debug_request = 0;
 
             dircache_dump();
+            uuidcache_dump();
 
             if (debugging) {
                 if (obj->options.logconfig)
index a8ae9e1080709bfe9782b99ac0ab91e6dd9c027f..40c2cc427b3343f92b0db9abc855652bd6f42f31 100644 (file)
@@ -2511,9 +2511,6 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             rbuf += sizeof( id );
             *rbuflen = 2 * sizeof( id );
             break;
-        case UUID_LOCAL:
-            free(name);
-            return (AFPERR_NOITEM);
         default:
             return AFPERR_MISC;
         }
index a9432675af5dd2dac68dd0d5352676a6a0d9213e..ebaf2b851d392e9115356a8487eb878f6de60a11 100644 (file)
 typedef unsigned char *uuidp_t;
 typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
 
-typedef enum {UUID_USER = 1, UUID_GROUP, UUID_LOCAL} uuidtype_t;
+typedef enum {UUID_USER   = 0,
+              UUID_GROUP  = 1,
+              UUID_ENOENT = 4} /* used as bit flag */
+    uuidtype_t;
+#define UUIDTYPESTR_MASK 3
 extern char *uuidtype[];
 
 /* afp_options.c needs these. defined in libatalk/ldap.c */
@@ -46,5 +50,5 @@ extern int getnamefromuuid( const uuidp_t uuidp, char **name, uuidtype_t *type);
 extern void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id);
 extern const char *uuid_bin2string(unsigned char *uuid);
 extern void uuid_string2bin( const char *uuidstring, uuidp_t uuid);
-
+extern void uuidcache_dump(void);
 #endif /* AFP_UUID_H */
index 585bb4801e8d4a727531f6ef3a4bff19f9d7c001..9fe8405ff72a3e9b9e749cbbeb8b97ce5e559d8f 100644 (file)
@@ -44,7 +44,7 @@ cacheduser_t *uuidcache[256];   /* indexed by hash of uuid */
  * helper function
  ********************************************************/
 
-static int dumpcache() {
+void uuidcache_dump(void) {
     int i;
     int ret = 0;
     cacheduser_t *entry;
@@ -59,8 +59,14 @@ static int dumpcache() {
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
-                LOG(log_debug9, logtype_default, "namecache{%d}: name:%s, uuid:%s, type: %s, cached: %s",
-                    i, entry->name, uuid_bin2string(entry->uuid), uuidtype[entry->type], timestr);
+                LOG(log_debug, logtype_default,
+                    "namecache{%d}: name:%s, uuid:%s, type%s: %s, cached: %s",
+                    i,
+                    entry->name,
+                    uuid_bin2string(entry->uuid),
+                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+                    uuidtype[entry->type & UUIDTYPESTR_MASK],
+                    timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
@@ -74,13 +80,17 @@ static int dumpcache() {
                     continue;
                 if (strftime(timestr, 200, "%c", tmp) == 0)
                     continue;
-                LOG(log_debug9, logtype_default, "uuidcache{%d}: uuid:%s, name:%s, type: %s, cached: %s",
-                    i, uuid_bin2string(entry->uuid), entry->name, uuidtype[entry->type], timestr);
+                LOG(log_debug, logtype_default,
+                    "uuidcache{%d}: uuid:%s, name:%s, type%s: %s, cached: %s",
+                    i,
+                    uuid_bin2string(entry->uuid),
+                    entry->name,
+                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+                    uuidtype[entry->type & UUIDTYPESTR_MASK],
+                    timestr);
             } while ((entry = entry->next) != NULL);
         }
     }
-
-    return ret;
 }
 
 /* hash string it into unsigned char */
@@ -121,10 +131,6 @@ int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t
     cacheduser_t *cacheduser = NULL;
     unsigned char hash;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     /* allocate mem and copy values */
     name = malloc(strlen(inname)+1);
     if (!name) {
@@ -181,26 +187,25 @@ cleanup:
             free(cacheduser);
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return ret;
 }
 
-/* 
- * Caller provides buffer uuid for result
+/*!
+ * Search cache by name and uuid type
+ *
+ * @args name     (r)  name to search
+ * @args type     (rw) type (user or group) of name, returns found type here which might
+ *                     mark it as a negative entry
+ * @args uuid     (w)  found uuid is returned here
+ * @returns       0 on sucess, entry found
+ *                -1 no entry found
  */
-int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
+int search_cachebyname(const char *name, uuidtype_t *type, uuidp_t uuid) {
     int ret;
     unsigned char hash;
     cacheduser_t *entry;
     time_t tim;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     hash = hashstring((unsigned char *)name);
 
     if (namecache[hash] == NULL)
@@ -209,11 +214,11 @@ int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
     entry = namecache[hash];
     while (entry) {
         ret = strcmp(entry->name, name);
-        if (ret == 0 && type == entry->type) {
+        if (ret == 0 && *type == (entry->type & UUIDTYPESTR_MASK)) {
             /* found, now check if expired */
             tim = time(NULL);
             if ((tim - entry->creationtime) > CACHESECONDS) {
-                LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
+                LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\"%s\"", entry->name);
                 /* remove item */
                 if (entry->prev) {
                     /* 2nd to last in queue */
@@ -229,23 +234,16 @@ int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
                 free(entry->name);
                 free(entry->uuid);
                 free(entry);
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return -1;
             } else {
                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
-#ifdef DEBUG
-                dumpcache();
-#endif
+                *type = entry->type;
                 return 0;
             }
         }
         entry = entry->next;
     }
-#ifdef DEBUG
-    dumpcache();
-#endif
+
     return -1;
 }
 
@@ -258,10 +256,6 @@ int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
     cacheduser_t *entry;
     time_t tim;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     hash = hashuuid(uuidp);
 
     if (! uuidcache[hash])
@@ -288,27 +282,17 @@ int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
                 free(entry->name);
                 free(entry->uuid);
                 free(entry);
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return -1;
             } else {
                 *name = malloc(strlen(entry->name)+1);
                 strcpy(*name, entry->name);
                 *type = entry->type;
-#ifdef DEBUG
-                dumpcache();
-#endif
                 return 0;
             }
         }
         entry = entry->next;
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return -1;
 }
 
@@ -320,10 +304,6 @@ int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const
     cacheduser_t *entry;
     unsigned char hash;
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     /* allocate mem and copy values */
     name = malloc(strlen(inname)+1);
     if (!name) {
@@ -380,9 +360,5 @@ cleanup:
             free(cacheduser);
     }
 
-#ifdef DEBUG
-    dumpcache();
-#endif
-
     return ret;
 }
index 7db8ecdc92453930e721232fba2d82db32652d78..252d7da2681742cda7772c43eb793f76204853ab 100644 (file)
  * Interface
  ********************************************************/
 
-/* 
- *   name: search for this name
- *   type: of type USER or GROUP
- *   uuid: if found copies uuid into this buffer
- * returns 0 on success, !=0 if not found or on errors
- */
-extern int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid);
-
-/* 
- *   inname: name
- *   inuuid: uuid
- *   type: USER or GROUP
- *   (uid: unused)
- * returns 0 on success, !=0 on memory errors
- */
+extern int search_cachebyname( const char *name, uuidtype_t *type, uuidp_t uuid);
 extern int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid);
-
-/* same as above but for the uuid cache */
 extern int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type);
 extern int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid);
 
index 074d9deb8a76c1da0343292b6250d940ee09d5c2..397d3b8483be09a318dd344c68a812690f27d34f 100644 (file)
@@ -33,7 +33,7 @@
 #include "aclldap.h"
 #include "cache.h"
 
-char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
+char *uuidtype[] = {"USER", "GROUP", "LOCAL"};
 
 /********************************************************
  * Public helper function
@@ -41,7 +41,7 @@ char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
 
 static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef,
                                            0xab, 0xcd, 0xef,
-                                           0xab, 0xcd, 0xef, 
+                                           0xab, 0xcd, 0xef,
                                            0xab, 0xcd, 0xef};
 
 static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
@@ -67,7 +67,7 @@ void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id)
     return;
 }
 
-/* 
+/*
  * convert ascii string that can include dashes to binary uuid.
  * caller must provide a buffer.
  */
@@ -100,9 +100,9 @@ void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
 
 }
 
-/*! 
+/*!
  * Convert 16 byte binary uuid to neat ascii represantation including dashes.
- * 
+ *
  * Returns pointer to static buffer.
  */
 const char *uuid_bin2string(unsigned char *uuid) {
@@ -132,24 +132,34 @@ const char *uuid_bin2string(unsigned char *uuid) {
  *   type: and type (UUID_USER or UUID_GROUP)
  *   uuid: pointer to uuid_t storage that the caller must provide
  * returns 0 on success !=0 on errror
- */  
+ */
 int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
     int ret = 0;
+    uuidtype_t mytype = type;
+    char nulluuid[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
 #ifdef HAVE_LDAP
     char *uuid_string = NULL;
 #endif
-    ret = search_cachebyname( name, type, uuid);
+
+    ret = search_cachebyname(name, &mytype, uuid);
+
     if (ret == 0) {
         /* found in cache */
-        LOG(log_debug, logtype_afpd, "getuuidfromname{cache}: name: %s, type: %s -> UUID: %s",
-            name, uuidtype[type], uuid_bin2string(uuid));
+        LOG(log_debug, logtype_afpd,
+            "getuuidfromname{cache}: name: %s, type%s: %s -> UUID: %s",
+            name,
+            (mytype & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+            uuidtype[type & UUIDTYPESTR_MASK],
+            uuid_bin2string(uuid));
+        if ((mytype & UUID_ENOENT) == UUID_ENOENT)
+            return -1;
     } else  {
         /* if not found in cache */
 #ifdef HAVE_LDAP
         if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
             uuid_string2bin( uuid_string, uuid);
             LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
-                name, uuidtype[type], uuid_bin2string(uuid));
+                name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
         } else {
             LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
                 name, type);
@@ -161,24 +171,31 @@ int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
                 struct passwd *pwd;
                 if ((pwd = getpwnam(name)) == NULL) {
                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
-                        name, uuidtype[type]);
-                    goto cleanup;
+                        name, uuidtype[type & UUIDTYPESTR_MASK]);
+                    mytype |= UUID_ENOENT;
+                    memcpy(uuid, nulluuid, 16);
+                } else {
+                    localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
+                    ret = 0;
+                    LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                        name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
                 }
-                localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
             } else {
                 struct group *grp;
                 if ((grp = getgrnam(name)) == NULL) {
                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
-                        name, uuidtype[type]);
-                    goto cleanup;
+                        name, uuidtype[type & UUIDTYPESTR_MASK]);
+                    mytype |= UUID_ENOENT;
+                    memcpy(uuid, nulluuid, 16);
+                } else {
+                    localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
+                    ret = 0;
+                    LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
+                        name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
                 }
-                localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
             }
-            LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
-                name, uuidtype[type], uuid_bin2string(uuid));
         }
-        ret = 0;
-        add_cachebyname( name, uuid, type, 0);
+        add_cachebyname(name, uuid, mytype, 0);
     }
 
 cleanup:
@@ -198,39 +215,72 @@ cleanup:
  * Caller must free name appropiately.
  */
 int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
-    int ret;
+    int ret = 0;
+    uid_t uid;
+    gid_t gid;
+    struct passwd *pwd;
+    struct group *grp;
 
-    ret = search_cachebyuuid( uuidp, name, type);
-    if (ret == 0) {
+    if (search_cachebyuuid(uuidp, name, type) == 0) {
         /* found in cache */
-        LOG(log_debug9, logtype_afpd, "getnamefromuuid{cache}: UUID: %s -> name: %s, type:%s",
-            uuid_bin2string(uuidp), *name, uuidtype[*type]);
-    } else {
-        /* not found in cache */
-
-        /* Check if UUID is a client local one */
-        if (memcmp(uuidp, local_user_uuid, 12) == 0
-            || memcmp(uuidp, local_group_uuid, 12) == 0) {
-            LOG(log_debug, logtype_afpd, "getnamefromuuid: local UUID: %" PRIu32 "",
-                ntohl(*(uint32_t *)(uuidp + 12)));
-            *type = UUID_LOCAL;
-            *name = strdup("UUID_LOCAL");
-            return 0;
+        LOG(log_debug, logtype_afpd,
+            "getnamefromuuid{cache}: UUID: %s -> name: %s, type%s: %s",
+            uuid_bin2string(uuidp),
+            *name,
+            (*type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
+            uuidtype[(*type) & UUIDTYPESTR_MASK]);
+        if ((*type & UUID_ENOENT) == UUID_ENOENT)
+            return -1;
+        return 0;
+    }
+
+    /* not found in cache */
+
+    /* Check if UUID is a client local one */
+    if (memcmp(uuidp, local_user_uuid, 12) == 0) {
+        *type = UUID_USER;
+        uid = ntohl(*(uint32_t *)(uuidp + 12));
+        if ((pwd = getpwuid(uid)) == NULL) {
+            /* not found, add negative entry to cache */
+            *type |= UUID_ENOENT;
+            *name = "UUID_ENOENT";
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            return -1;
+        }
+        *name = pwd->pw_name;
+        add_cachebyuuid(uuidp, *name, *type, 0);
+        return 0;
+    } else if (memcmp(uuidp, local_group_uuid, 12) == 0) {
+        *type = UUID_GROUP;
+        gid = ntohl(*(uint32_t *)(uuidp + 12));
+        if ((grp = getgrgid(gid)) == NULL) {
+            /* not found, add negative entry to cache */
+            *type |= UUID_ENOENT;
+            *name = "UUID_ENOENT";
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            return -1;
         }
+        *name = grp->gr_name;
+        add_cachebyuuid(uuidp, *name, *type, 0);
+        return 0;
+    }
 
 #ifdef HAVE_LDAP
-        ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
-        if (ret != 0) {
-            LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
-                uuid_bin2string(uuidp));
-            goto cleanup;
-        }
-        add_cachebyuuid( uuidp, *name, *type, 0);
-        LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
-            uuid_bin2string(uuidp), *name, uuidtype[*type]);
-#endif
+    ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
+    if (ret != 0) {
+        LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
+            uuid_bin2string(uuidp));
+        *type |= UUID_ENOENT;
+        *name = "UUID_ENOENT";
+        add_cachebyuuid(uuidp, *name, *type, 0);
+        return -1;
     }
+#endif
 
-cleanup:
-    return ret;
+    add_cachebyuuid(uuidp, *name, *type, 0);
+
+    LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
+        uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
+
+    return 0;
 }