]> arthur.barton.de Git - netatalk.git/commitdiff
LDAP: Support for Active Directory objectGUID
authorThomas Johnson <NTmatter@gmail.com>
Sun, 15 Jul 2012 15:55:20 +0000 (17:55 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 25 Jul 2012 09:39:00 +0000 (11:39 +0200)
Adds optional "ldap uuid encoding = string | ms-guid" parameter to afp.conf,
allowing for usage of the binary objectGUID fields from Active Directory.

If left unspecified, "string" is the default, which passes through the ASCII
UUID returned by most other LDAP stores. If set to ms-guid, the internal UUID
representation is converted to and from the binary format used in the
objectGUID attribute found on objects in Active Directory when interacting
with the server.

include/atalk/ldapconfig.h
libatalk/acl/ldap.c

index 90a1c95b6eddb3a450d9e6f272f7277a78f17f4f..16e5484f6dd24822874f465a221918bac251ab9d 100644 (file)
@@ -20,6 +20,12 @@ extern char *ldap_uuid_string;
 extern char *ldap_name_attr;
 extern char *ldap_group_attr;
 extern char *ldap_uid_attr;
 extern char *ldap_name_attr;
 extern char *ldap_group_attr;
 extern char *ldap_uid_attr;
+extern int  ldap_uuid_encoding;
+
+typedef enum {
+       LDAP_UUID_ENCODING_STRING = 0, /* Plain ASCII string */
+       LDAP_UUID_ENCODING_MSGUID = 1  /* Raw byte array, from Active Directory objectGUID */
+} ldap_uuid_encoding_type;
 
 struct ldap_pref {
     const void *pref;
 
 struct ldap_pref {
     const void *pref;
@@ -35,6 +41,8 @@ struct pref_array {
     int  value;         /* corresponding value */
 };
 
     int  value;         /* corresponding value */
 };
 
+
+
 /* For parsing */
 extern struct ldap_pref ldap_prefs[];
 extern struct pref_array prefs_array[];
 /* For parsing */
 extern struct ldap_pref ldap_prefs[];
 extern struct pref_array prefs_array[];
index 062bab72acbb5d487bc9cfec403b4dd21f9808cd..8743bafeabcd90b7f0e16afd6fa79bf3738b332a 100644 (file)
@@ -53,6 +53,7 @@ char *ldap_uuid_string;
 char *ldap_name_attr;
 char *ldap_group_attr;
 char *ldap_uid_attr;
 char *ldap_name_attr;
 char *ldap_group_attr;
 char *ldap_uid_attr;
+int  ldap_uuid_encoding;
 
 struct ldap_pref ldap_prefs[] = {
     {&ldap_server,     "ldap server",      0, 0, -1},
 
 struct ldap_pref ldap_prefs[] = {
     {&ldap_server,     "ldap server",      0, 0, -1},
@@ -68,6 +69,7 @@ struct ldap_pref ldap_prefs[] = {
     {&ldap_name_attr,  "ldap name attr",   0, 0, -1},
     {&ldap_group_attr, "ldap group attr",  0, 0, -1},
     {&ldap_uid_attr,   "ldap uid attr",    0, 0,  0},
     {&ldap_name_attr,  "ldap name attr",   0, 0, -1},
     {&ldap_group_attr, "ldap group attr",  0, 0, -1},
     {&ldap_uid_attr,   "ldap uid attr",    0, 0,  0},
+    {&ldap_uuid_encoding,"ldap uuid encoding", 1, 1,  0},
     {NULL,             NULL,               0, 0, -1}
 };
 
     {NULL,             NULL,               0, 0, -1}
 };
 
@@ -81,6 +83,8 @@ struct pref_array prefs_array[] = {
     {"ldap groupscope",  "base",   LDAP_SCOPE_BASE},
     {"ldap groupscope",  "one",    LDAP_SCOPE_ONELEVEL},
     {"ldap groupscope",  "sub",    LDAP_SCOPE_SUBTREE},
     {"ldap groupscope",  "base",   LDAP_SCOPE_BASE},
     {"ldap groupscope",  "one",    LDAP_SCOPE_ONELEVEL},
     {"ldap groupscope",  "sub",    LDAP_SCOPE_SUBTREE},
+    {"ldap uuid encoding", "ms-guid",    LDAP_UUID_ENCODING_MSGUID},
+    {"ldap uuid encoding", "string", LDAP_UUID_ENCODING_STRING},
     {NULL,               NULL,     0}
 };
 
     {NULL,               NULL,     0}
 };
 
@@ -116,7 +120,7 @@ static int ldap_getattr_fromfilter_withbase_scope( const char *searchbase,
     static LDAP *ld     = NULL;
     LDAPMessage* msg    = NULL;
     LDAPMessage* entry  = NULL;
     static LDAP *ld     = NULL;
     LDAPMessage* msg    = NULL;
     LDAPMessage* entry  = NULL;
-    char **attribute_values = NULL;
+    struct berval **attribute_values = NULL;
     struct timeval timeout;
 
     LOG(log_maxdebug, logtype_afpd,"ldap: BEGIN");
     struct timeval timeout;
 
     LOG(log_maxdebug, logtype_afpd,"ldap: BEGIN");
@@ -199,27 +203,30 @@ retry:
         ret = -1;
         goto cleanup;
     }
         ret = -1;
         goto cleanup;
     }
-    attribute_values = ldap_get_values(ld, entry, attributes[0]);
+
+    attribute_values = ldap_get_values_len(ld, entry, attributes[0]);
     if (attribute_values == NULL) {
     if (attribute_values == NULL) {
-        LOG(log_error, logtype_default, "ldap: ldap_get_values error");
+        LOG(log_error, logtype_default, "ldap: ldap_get_values_len error");
         ret = -1;
         goto cleanup;
     }
 
     LOG(log_maxdebug, logtype_afpd,"ldap: search result: %s: %s",
         ret = -1;
         goto cleanup;
     }
 
     LOG(log_maxdebug, logtype_afpd,"ldap: search result: %s: %s",
-        attributes[0], attribute_values[0]);
+        attributes[0], attribute_values[0]->bv_val);
+
+    /* allocate and copy result */
+    *result = calloc(1, attribute_values[0]->bv_len + 1);
+    memcpy(*result, attribute_values[0]->bv_val, attribute_values[0]->bv_len + 1);
 
 
-    /* allocate result */
-    *result = strdup(attribute_values[0]);
     if (*result == NULL) {
     if (*result == NULL) {
-        LOG(log_error, logtype_default, "ldap: strdup error: %s",strerror(errno));
+        LOG(log_error, logtype_default, "ldap: memcopy error: %s", strerror(errno));
         ret = -1;
         goto cleanup;
     }
 
 cleanup:
     if (attribute_values)
         ret = -1;
         goto cleanup;
     }
 
 cleanup:
     if (attribute_values)
-        ldap_value_free(attribute_values);
+        ldap_value_free_len(attribute_values);
     /* FIXME: is there another way to free entry ? */
     while (entry != NULL)
         entry = ldap_next_entry(ld, entry);
     /* FIXME: is there another way to free entry ? */
     while (entry != NULL)
         entry = ldap_next_entry(ld, entry);
@@ -288,8 +295,26 @@ int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string)
     } else  { /* type hopefully == UUID_USER */
         ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, uuid_string);
     }
     } else  { /* type hopefully == UUID_USER */
         ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, uuid_string);
     }
+
     if (ret != 1)
         return -1;
     if (ret != 1)
         return -1;
+
+    if(ldap_uuid_encoding == LDAP_UUID_ENCODING_MSGUID) {
+        /* Convert byte array to UUID string (no dashes) */
+        unsigned char* uuid_bytes = (unsigned char*) *uuid_string;
+        *uuid_string = malloc(37);
+        snprintf(*uuid_string, 37,
+            "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+            uuid_bytes[3], uuid_bytes[2], uuid_bytes[1], uuid_bytes[0], /* Data1 */
+            uuid_bytes[5], uuid_bytes[4], /* Data2 */
+            uuid_bytes[7], uuid_bytes[6], /* Data3 */
+            uuid_bytes[8], uuid_bytes[9], /* Data4 - High Bytes */
+            uuid_bytes[10], uuid_bytes[11], uuid_bytes[12], /* Data4 - Low Bytes */
+            uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]);
+        free(uuid_bytes);
+        LOG(log_error, logtype_default, "ldap_getnamefromuuid: uuid_string: %s", *uuid_string);
+    }
+
     return 0;
 }
 
     return 0;
 }
 
@@ -313,8 +338,47 @@ int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type) {
     if (!ldap_config_valid)
         return -1;
 
     if (!ldap_config_valid)
         return -1;
 
-    /* make filter */
-    len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, uuidstr);
+    if(ldap_uuid_encoding == LDAP_UUID_ENCODING_MSGUID) {
+        /* Convert to LDAP-safe binary encoding for direct query of AD objectGUID attribute */
+        char* stripped = malloc(strlen(uuidstr));
+
+        int i = 0;
+        int s = 0;
+        char c;
+        while(c = uuidstr[i]) {
+            if((c >='a' && c <= 'f')
+                || (c >= 'A' && c <= 'F')
+                || (c >= '0' && c <= '9')) {
+                stripped[s++] = toupper(c);
+            }
+            i++;
+        }
+
+        /* LDAP Binary Notation is \XX * 16 bytes of UUID + terminator = 49 */
+        char* ldap_bytes = malloc(49);
+        snprintf(ldap_bytes, 49,
+            "\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c"
+            "\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c\\%c%c",
+            /* Data1 (uint32) */
+            stripped[6], stripped[7], stripped[4], stripped[5],
+            stripped[2], stripped[3], stripped[0], stripped[1],
+            /* Data2 (uint16) */
+            stripped[10], stripped[11], stripped[8], stripped[9],
+            /* Data3 (uint16) */
+            stripped[14], stripped[15], stripped[12], stripped[13],
+            /* Data4 (uint64) */
+            stripped[16], stripped[17], stripped[18], stripped[19],
+            stripped[20], stripped[21], stripped[22], stripped[23],
+            stripped[24], stripped[25], stripped[26], stripped[27],
+            stripped[28], stripped[29], stripped[30], stripped[31]);
+        len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, ldap_bytes);
+
+        free(ldap_bytes);
+        free(stripped);
+    } else {
+        len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, uuidstr);
+    }
+
     if (len >= 256 || len == -1) {
         LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter overflow:%d, \"%s\"", len, filter);
         return -1;
     if (len >= 256 || len == -1) {
         LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter overflow:%d, \"%s\"", len, filter);
         return -1;