X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=libatalk%2Facl%2Fldap.c;h=e805a990542deb3c883a4419e1757c101977867c;hb=6821c9c1b67181b020f375bab7ac8061b0dcbec2;hp=724ac4d5ba8e59d59bf4aa2f73c2cc3450165765;hpb=85a8591621dc4c47417402a24df31e40bd7cae15;p=netatalk.git diff --git a/libatalk/acl/ldap.c b/libatalk/acl/ldap.c index 724ac4d5..e805a990 100644 --- a/libatalk/acl/ldap.c +++ b/libatalk/acl/ldap.c @@ -23,6 +23,7 @@ #include #include #include +#include #define LDAP_DEPRECATED 1 #include @@ -30,6 +31,7 @@ #include #include #include /* For struct ldap_pref */ +#include typedef enum { KEEPALIVE = 1 @@ -49,36 +51,48 @@ int ldap_userscope; char *ldap_groupbase; int ldap_groupscope; char *ldap_uuid_attr; +char *ldap_uuid_string; char *ldap_name_attr; char *ldap_group_attr; char *ldap_uid_attr; +char *ldap_userfilter; +char *ldap_groupfilter; +int ldap_uuid_encoding; struct ldap_pref ldap_prefs[] = { - {&ldap_server, "ldap_server", 0, 0, -1}, - {&ldap_auth_method,"ldap_auth_method", 1, 1, -1}, - {&ldap_auth_dn, "ldap_auth_dn", 0, 0, 0}, - {&ldap_auth_pw, "ldap_auth_pw", 0, 0, 0}, - {&ldap_userbase, "ldap_userbase", 0, 0, -1}, - {&ldap_userscope, "ldap_userscope", 1 ,1, -1}, - {&ldap_groupbase, "ldap_groupbase", 0, 0, -1}, - {&ldap_groupscope, "ldap_groupscope", 1 ,1, -1}, - {&ldap_uuid_attr, "ldap_uuid_attr", 0, 0, -1}, - {&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}, - {NULL, NULL, 0, 0, -1} + /* pointer to pref, prefname, strorint, intfromarray, valid, valid_save */ + {&ldap_server, "ldap server", 0, 0, -1, -1}, + {&ldap_auth_method, "ldap auth method", 1, 1, -1, -1}, + {&ldap_auth_dn, "ldap auth dn", 0, 0, 0, 0}, + {&ldap_auth_pw, "ldap auth pw", 0, 0, 0, 0}, + {&ldap_userbase, "ldap userbase", 0, 0, -1, -1}, + {&ldap_userscope, "ldap userscope", 1 ,1, -1, -1}, + {&ldap_groupbase, "ldap groupbase", 0, 0, -1, -1}, + {&ldap_groupscope, "ldap groupscope", 1 ,1, -1, -1}, + {&ldap_uuid_attr, "ldap uuid attr", 0, 0, -1, -1}, + {&ldap_uuid_string, "ldap uuid string", 0, 0, 0, 0}, + {&ldap_name_attr, "ldap name attr", 0, 0, -1, -1}, + {&ldap_group_attr, "ldap group attr", 0, 0, -1, -1}, + {&ldap_uid_attr, "ldap uid attr", 0, 0, 0, 0}, + {&ldap_uuid_encoding, "ldap uuid encoding", 1, 1, 0, 0}, + {&ldap_userfilter, "ldap user filter", 0, 0, 0, 0}, + {&ldap_groupfilter, "ldap group filter", 0, 0, 0, 0}, + {&ldap_auth_pw, "ldap auth pw", 0, 0, 0, 0}, + {NULL, NULL, 0, 0, 0, 0} }; struct pref_array prefs_array[] = { - {"ldap_auth_method", "none", LDAP_AUTH_NONE}, - {"ldap_auth_method", "simple", LDAP_AUTH_SIMPLE}, - {"ldap_auth_method", "sasl", LDAP_AUTH_SASL}, - {"ldap_userscope", "base", LDAP_SCOPE_BASE}, - {"ldap_userscope", "one", LDAP_SCOPE_ONELEVEL}, - {"ldap_userscope", "sub", LDAP_SCOPE_SUBTREE}, - {"ldap_groupscope", "base", LDAP_SCOPE_BASE}, - {"ldap_groupscope", "one", LDAP_SCOPE_ONELEVEL}, - {"ldap_groupscope", "sub", LDAP_SCOPE_SUBTREE}, + {"ldap auth method", "none", LDAP_AUTH_NONE}, + {"ldap auth method", "simple", LDAP_AUTH_SIMPLE}, + {"ldap auth method", "sasl", LDAP_AUTH_SASL}, + {"ldap userscope", "base", LDAP_SCOPE_BASE}, + {"ldap userscope", "one", LDAP_SCOPE_ONELEVEL}, + {"ldap userscope", "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} }; @@ -114,7 +128,7 @@ static int ldap_getattr_fromfilter_withbase_scope( const char *searchbase, 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"); @@ -197,27 +211,30 @@ retry: 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) { - 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", - 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) { - 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) - 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); @@ -245,6 +262,69 @@ cleanup: return ret; } +/*! + * Generate LDAP filter string for UUID query + + * @param[in] uuidstr the UUID as string + * @param[in] attr_filter optional attribute + * @returns pointer to static filter string + */ +static char *gen_uuid_filter(const char *uuidstr_in, const char *attr_filter) +{ + EC_INIT; + int len; + const char *uuidstr = uuidstr_in; + +#define MAX_FILTER_SIZE 512 + static char filter[MAX_FILTER_SIZE]; + char stripped[MAX_FILTER_SIZE]; + +#define LDAP_BIN_UUID_LEN 49 /* LDAP Binary Notation is \XX * 16 bytes of UUID + terminator = 49 */ + char ldap_bytes[LDAP_BIN_UUID_LEN]; + + if (ldap_uuid_encoding == LDAP_UUID_ENCODING_MSGUID) { + /* Convert to LDAP-safe binary encoding for direct query of AD objectGUID attribute */ + int i = 0, 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++; + } + + snprintf(ldap_bytes, LDAP_BIN_UUID_LEN, + "\\%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]); + uuidstr = ldap_bytes; + } + + if (attr_filter) { + len = snprintf(filter, 256, "(&(%s=%s)(%s))", ldap_uuid_attr, uuidstr, attr_filter); + } else { + len = snprintf(filter, 256, "%s=%s", ldap_uuid_attr, uuidstr); + } + +EC_CLEANUP: + if (ret != 0) + return NULL; + return filter; +} + /******************************************************** * Interface ********************************************************/ @@ -286,8 +366,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); } + 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; } @@ -303,37 +401,50 @@ int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string) * returns 0 on success, -1 on errror */ int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type) { - int ret; - int len; - char filter[256]; /* this should really be enough. we dont want to malloc everything! */ + EC_INIT; + char *filter; char *attributes[] = { NULL, NULL}; if (!ldap_config_valid) - return -1; + EC_FAIL; + + /* + * Search groups first as group acls are probably used more often. + * Note the special case of AD where users and groups are stored + * under the same subtree. + */ - /* make filter */ - 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; - } - /* search groups first. group acls are probably used more often */ attributes[0] = ldap_group_attr; - ret = ldap_getattr_fromfilter_withbase_scope( ldap_groupbase, filter, attributes, ldap_groupscope, KEEPALIVE, name); - if (ret == -1) - return -1; + EC_NULL( filter = gen_uuid_filter(uuidstr, ldap_groupfilter) ); + EC_NEG1( ret = ldap_getattr_fromfilter_withbase_scope( + ldap_groupbase, + filter, + attributes, + ldap_groupscope, + KEEPALIVE, + name) ); if (ret == 1) { *type = UUID_GROUP; - return 0; + EC_EXIT_STATUS(0); } attributes[0] = ldap_name_attr; - ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, name); + EC_NULL( filter = gen_uuid_filter(uuidstr, ldap_userfilter) ); + EC_NEG1( ret = ldap_getattr_fromfilter_withbase_scope( + ldap_userbase, + filter, + attributes, + ldap_userscope, + KEEPALIVE, + name) ); if (ret == 1) { *type = UUID_USER; - return 0; + EC_EXIT_STATUS(0); } - return -1; + EC_FAIL; + +EC_CLEANUP: + EC_EXIT; } #endif /* HAVE_LDAP */