]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/acl/uuid.c
Merge master
[netatalk.git] / libatalk / acl / uuid.c
index 010de4db7869701efc1b30472cbe082faf91f00a..4fad0407ae5b1fa60a8ea2243d68037313b79608 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <arpa/inet.h>
 
 #include <atalk/logger.h>
 #include <atalk/afp.h>
 #include "aclldap.h"
 #include "cache.h"
 
-char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
+char *uuidtype[] = {"USER", "GROUP", "LOCAL"};
 
 /********************************************************
  * Public helper function
  ********************************************************/
 
-/* 
+static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef,
+                                           0xab, 0xcd, 0xef,
+                                           0xab, 0xcd, 0xef,
+                                           0xab, 0xcd, 0xef};
+
+static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
+                                          0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa};
+
+void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id)
+{
+    uint32_t tmp;
+
+    switch (type) {
+    case UUID_GROUP:
+        memcpy(buf, local_group_uuid, 12);
+        break;
+    case UUID_USER:
+    default:
+        memcpy(buf, local_user_uuid, 12);
+        break;
+    }
+
+    tmp = htonl(id);
+    memcpy(buf + 12, &tmp, 4);
+
+    return;
+}
+
+/*
  * convert ascii string that can include dashes to binary uuid.
  * caller must provide a buffer.
  */
-void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
+void uuid_string2bin( const char *uuidstring, unsigned char *uuid) {
     int nibble = 1;
     int i = 0;
     unsigned char c, val = 0;
@@ -69,29 +101,22 @@ 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(char *uuid) {
+const char *uuid_bin2string(const unsigned char *uuid) {
     static char uuidstring[UUID_STRINGSIZE + 1];
-    char ascii[16] = { "0123456789ABCDEF" };
-    int nibble = 1;
+
     int i = 0;
-    int c;
-    
+    unsigned char c;
+
     while (i < UUID_STRINGSIZE) {
         c = *uuid;
-        if (nibble)
-            c = c >> 4;
-        else {
-            c &= 0x0f;
-            uuid++;
-        }
-        uuidstring[i] = ascii[c];
-        nibble ^= 1;
-        i++;
+        uuid++;
+        sprintf(uuidstring + i, "%02X", c);
+        i += 2;
         if (i==8 || i==13 || i==18 || i==23)
             uuidstring[i++] = '-';
     }
@@ -108,41 +133,79 @@ const char *uuid_bin2string(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 getuuidfromname( const char *name, uuidtype_t type, unsigned char *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, &mytype, uuid);
 
-    ret = search_cachebyname( name, type, 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 */
-        ret = ldap_getuuidfromname( name, type, &uuid_string);
-        if (ret != 0) {
-            LOG(log_note, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
+#ifdef HAVE_LDAP
+        if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
+            uuid_string2bin( uuid_string, uuid);
+            LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s",
+                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);
-            goto cleanup;
         }
-        uuid_string2bin( uuid_string, uuid);
-        add_cachebyname( name, uuid, type, 0);
-        LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s",name, uuidtype[type], uuid_string);
+#endif
+        if (ret != 0) {
+            /* Build a local UUID */
+            if (type == UUID_USER) {
+                struct passwd *pwd;
+                if ((pwd = getpwnam(name)) == NULL) {
+                    LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
+                        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));
+                }
+            } else {
+                struct group *grp;
+                if ((grp = getgrnam(name)) == NULL) {
+                    LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
+                        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));
+                }
+            }
+        }
+        add_cachebyname(name, uuid, mytype, 0);
     }
 
 cleanup:
+#ifdef HAVE_LDAP
     if (uuid_string) free(uuid_string);
+#endif
     return ret;
 }
 
-static char local_group_uuid[] = {0xab, 0xcd, 0xef,
-                                  0xab, 0xcd, 0xef,
-                                  0xab, 0xcd, 0xef, 
-                                  0xab, 0xcd, 0xef};
-
-static char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
-                                 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa};
 
 /*
  * uuidp: pointer to a uuid
@@ -153,37 +216,73 @@ static char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
  * 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;
+    }
 
-        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;
+    /* 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 */
+            add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+            ret = -1;
+        } else {
+            *name = strdup(pwd->pw_name);
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            ret = 0;
+        }
+        LOG(log_debug, logtype_afpd,
+            "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s",
+            uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
+        return ret;
+    } 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 */
+            add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+            ret = -1;
+        } else {
+            *name = strdup(grp->gr_name);
+            add_cachebyuuid(uuidp, *name, *type, 0);
+            ret = 0;
         }
-        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]);
+        return ret;
     }
 
-cleanup:
-    return ret;
+#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));
+        add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
+        return -1;
+    }
+#endif
+
+    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;
 }