2 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 #endif /* HAVE_CONFIG_H */
26 #define LDAP_DEPRECATED 1
29 #include <atalk/logger.h>
30 #include <atalk/afp.h>
31 #include <atalk/uuid.h>
32 #include <atalk/ldapconfig.h> /* For struct ldap_pref */
38 /********************************************************
39 * LDAP config stuff. Filled by libatalk/acl/ldap_config.c
40 ********************************************************/
41 int ldap_config_valid;
53 char *ldap_group_attr;
56 struct ldap_pref ldap_prefs[] = {
57 {&ldap_server, "ldap_server", 0, 0, -1},
58 {&ldap_auth_method,"ldap_auth_method", 1, 1, -1},
59 {&ldap_auth_dn, "ldap_auth_dn", 0, 0, 0},
60 {&ldap_auth_pw, "ldap_auth_pw", 0, 0, 0},
61 {&ldap_userbase, "ldap_userbase", 0, 0, -1},
62 {&ldap_userscope, "ldap_userscope", 1 ,1, -1},
63 {&ldap_groupbase, "ldap_groupbase", 0, 0, -1},
64 {&ldap_groupscope, "ldap_groupscope", 1 ,1, -1},
65 {&ldap_uuid_attr, "ldap_uuid_attr", 0, 0, -1},
66 {&ldap_name_attr, "ldap_name_attr", 0, 0, -1},
67 {&ldap_group_attr, "ldap_group_attr", 0, 0, -1},
68 {&ldap_uid_attr, "ldap_uid_attr", 0, 0, 0},
69 {NULL, NULL, 0, 0, -1}
72 struct pref_array prefs_array[] = {
73 {"ldap_auth_method", "none", LDAP_AUTH_NONE},
74 {"ldap_auth_method", "simple", LDAP_AUTH_SIMPLE},
75 {"ldap_auth_method", "sasl", LDAP_AUTH_SASL},
76 {"ldap_userscope", "base", LDAP_SCOPE_BASE},
77 {"ldap_userscope", "one", LDAP_SCOPE_ONELEVEL},
78 {"ldap_userscope", "sub", LDAP_SCOPE_SUBTREE},
79 {"ldap_groupscope", "base", LDAP_SCOPE_BASE},
80 {"ldap_groupscope", "one", LDAP_SCOPE_ONELEVEL},
81 {"ldap_groupscope", "sub", LDAP_SCOPE_SUBTREE},
85 /********************************************************
86 * Static helper function
87 ********************************************************/
90 * ldap_getattr_fromfilter_withbase_scope():
92 * scope: LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
93 * result: return unique search result here, allocated here, caller must free
95 * returns: -1 on error
97 * 1 successfull search, result int 'result'
99 * All connection managment to the LDAP server is done here. Just set KEEPALIVE if you know
100 * you will be dispatching more than one search in a row, then don't set it with the last search.
101 * You MUST dispatch the queries timely, otherwise the LDAP handle might timeout.
103 static int ldap_getattr_fromfilter_withbase_scope( const char *searchbase,
112 int desired_version = LDAP_VERSION3;
113 static int ldapconnected = 0;
114 static LDAP *ld = NULL;
115 LDAPMessage* msg = NULL;
116 LDAPMessage* entry = NULL;
117 char **attribute_values = NULL;
118 struct timeval timeout;
120 LOG(log_maxdebug, logtype_afpd,"ldap: BEGIN");
125 /* init LDAP if necessary */
130 LOG(log_maxdebug, logtype_default, "ldap: server: \"%s\"",
132 if ((ld = ldap_init(ldap_server, LDAP_PORT)) == NULL ) {
133 LOG(log_error, logtype_default, "ldap: ldap_init error: %s",
137 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) != 0) {
138 /* LDAP_OPT_SUCCESS is not in the proposed standard, so we check for 0
139 http://tools.ietf.org/id/draft-ietf-ldapext-ldap-c-api-05.txt */
140 LOG(log_error, logtype_default, "ldap: ldap_set_option failed!");
148 if (!ldapconnected) {
149 if (LDAP_AUTH_NONE == ldap_auth_method) {
150 if (ldap_bind_s(ld, "", "", LDAP_AUTH_SIMPLE) != LDAP_SUCCESS ) {
151 LOG(log_error, logtype_default, "ldap: ldap_bind failed, auth_method: \'%d\'",
159 } else if (LDAP_AUTH_SIMPLE == ldap_auth_method) {
160 if (ldap_bind_s(ld, ldap_auth_dn, ldap_auth_pw, ldap_auth_method) != LDAP_SUCCESS ) {
161 LOG(log_error, logtype_default,
162 "ldap: ldap_bind failed: ldap_auth_dn: \'%s\', ldap_auth_pw: \'%s\', ldap_auth_method: \'%d\'",
163 ldap_auth_dn, ldap_auth_pw, ldap_auth_method);
172 LOG(log_maxdebug, logtype_afpd, "ldap: start search: base: %s, filter: %s, attr: %s",
173 searchbase, filter, attributes[0]);
175 /* start LDAP search */
176 ldaperr = ldap_search_st(ld, searchbase, scope, filter, attributes, 0, &timeout, &msg);
177 LOG(log_maxdebug, logtype_default, "ldap: ldap_search_st returned: %s",
178 ldap_err2string(ldaperr));
179 if (ldaperr != LDAP_SUCCESS) {
180 LOG(log_error, logtype_default, "ldap: ldap_search_st failed: %s, retrycount: %i",
181 ldap_err2string(ldaperr), retrycount);
186 /* parse search result */
187 LOG(log_maxdebug, logtype_default, "ldap: got %d entries from ldap search",
188 ldap_count_entries(ld, msg));
189 if ((ret = ldap_count_entries(ld, msg)) != 1) {
194 entry = ldap_first_entry(ld, msg);
196 LOG(log_error, logtype_default, "ldap: ldap_first_entry error");
200 attribute_values = ldap_get_values(ld, entry, attributes[0]);
201 if (attribute_values == NULL) {
202 LOG(log_error, logtype_default, "ldap: ldap_get_values error");
207 LOG(log_maxdebug, logtype_afpd,"ldap: search result: %s: %s",
208 attributes[0], attribute_values[0]);
210 /* allocate result */
211 *result = strdup(attribute_values[0]);
212 if (*result == NULL) {
213 LOG(log_error, logtype_default, "ldap: strdup error: %s",strerror(errno));
219 if (attribute_values)
220 ldap_value_free(attribute_values);
221 /* FIXME: is there another way to free entry ? */
222 while (entry != NULL)
223 entry = ldap_next_entry(ld, entry);
228 if ((ret == -1) || !(conflags & KEEPALIVE)) {
229 LOG(log_maxdebug, logtype_default,"ldap: unbind");
230 if (ldap_unbind_s(ld) != 0) {
231 LOG(log_error, logtype_default, "ldap: unbind: %s\n", ldap_err2string(ldaperr));
237 /* In case of error we try twice */
248 /********************************************************
250 ********************************************************/
253 * Search UUID for name in LDAP
255 * Caller must free uuid_string when done with it
257 * @param name (r) name to search
258 * @param type (r) type of USER or GROUP
259 * @param uuid_string (w) result as pointer to allocated UUID-string
261 * @returns 0 on success, -1 on error or not found
263 int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string) {
266 char filter[256]; /* this should really be enough. we dont want to malloc everything! */
267 char *attributes[] = { ldap_uuid_attr, NULL};
270 if (!ldap_config_valid)
274 if (type == UUID_GROUP)
275 ldap_attr = ldap_group_attr;
276 else /* type hopefully == UUID_USER */
277 ldap_attr = ldap_name_attr;
278 len = snprintf( filter, 256, "%s=%s", ldap_attr, name);
279 if (len >= 256 || len == -1) {
280 LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter error:%d, \"%s\"", len, filter);
284 if (type == UUID_GROUP) {
285 ret = ldap_getattr_fromfilter_withbase_scope( ldap_groupbase, filter, attributes, ldap_groupscope, KEEPALIVE, uuid_string);
286 } else { /* type hopefully == UUID_USER */
287 ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, uuid_string);
295 * LDAP search wrapper
296 * returns allocated storage in name, caller must free it
297 * returns 0 on success, -1 on error or not found
299 * @param uuidstr (r) uuid to search as ascii string
300 * @param name (w) return pointer to name as allocated string
301 * @param type (w) return type: USER or GROUP
303 * returns 0 on success, -1 on errror
305 int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type) {
308 char filter[256]; /* this should really be enough. we dont want to malloc everything! */
309 char *attributes[] = { NULL, NULL};
311 if (!ldap_config_valid)
315 len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, uuidstr);
316 if (len >= 256 || len == -1) {
317 LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter overflow:%d, \"%s\"", len, filter);
320 /* search groups first. group acls are probably used more often */
321 attributes[0] = ldap_group_attr;
322 ret = ldap_getattr_fromfilter_withbase_scope( ldap_groupbase, filter, attributes, ldap_groupscope, KEEPALIVE, name);
330 attributes[0] = ldap_name_attr;
331 ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, name);
339 #endif /* HAVE_LDAP */