2 $Id: ldap.c,v 1.2 2009-11-27 15:16:26 franklahm Exp $
3 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
18 #endif /* HAVE_CONFIG_H */
27 #include <atalk/logger.h>
28 #include <atalk/afp.h>
29 #include <atalk/uuid.h>
30 #include <atalk/ldapconfig.h> /* For struct ldap_pref */
36 /********************************************************
37 * LDAP config stuff. Filled by etc/afpd/acl_config.c
38 ********************************************************/
39 int ldap_config_valid;
49 char *ldap_group_attr;
52 struct ldap_pref ldap_prefs[] = {
53 {&ldap_server, "ldap_server", 0, 0, -1},
54 {&ldap_auth_method,"ldap_auth_method", 1, 1, -1},
55 {&ldap_auth_dn, "ldap_auth_dn", 0, 0, 0},
56 {&ldap_auth_pw, "ldap_auth_pw", 0, 0, 0},
57 {&ldap_userbase, "ldap_userbase", 0, 0, -1},
58 {&ldap_groupbase, "ldap_groupbase", 0, 0, -1},
59 {&ldap_uuid_attr, "ldap_uuid_attr", 0, 0, -1},
60 {&ldap_name_attr, "ldap_name_attr", 0, 0, -1},
61 {&ldap_group_attr, "ldap_group_attr", 0, 0, -1},
62 {&ldap_uid_attr, "ldap_uid_attr", 0, 0, 0},
63 {NULL, NULL, 0, 0, -1}
66 struct pref_array prefs_array[] = {
67 {"ldap_auth_method", "none", LDAP_AUTH_NONE},
68 {"ldap_auth_method", "simple", LDAP_AUTH_SIMPLE},
69 {"ldap_auth_method", "sasl", LDAP_AUTH_SASL},
73 /********************************************************
74 * Static helper function
75 ********************************************************/
78 * ldap_getattr_fromfilter_withbase_scope():
80 * scope: LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
81 * result: return unique search result here, allocated here, caller must free
83 * All connection managment to the LDAP server is done here. Just set KEEPALIVE if you know
84 * you will be dispatching more than one search in a row, then don't set it with the last search.
85 * You MUST dispatch the queries timely, otherwise the LDAP handle might timeout.
87 static int ldap_getattr_fromfilter_withbase_scope( const char *searchbase,
95 int desired_version = LDAP_VERSION3;
96 static int ldapconnected = 0;
97 static LDAP *ld = NULL;
98 LDAPMessage* msg = NULL;
99 LDAPMessage* entry = NULL;
101 char **attribute_values;
102 struct timeval timeout;
104 // LOG(log_debug, logtype_afpd,"ldap_getattr_fromfilter_withbase_scope: BEGIN");
109 /* init LDAP if necessary */
110 if (!ldapconnected) {
111 // LOG(log_debug, logtype_default, "ldap_getattr_fromfilter_withbase_scope: LDAP server: \'%s\'", ldap_server);
112 if ((ld = ldap_init(ldap_server, LDAP_PORT)) == NULL ) {
113 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: ldap_init error");
116 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) != 0) {
117 /* LDAP_OPT_SUCCESS is not in the proposed standard, so we check for 0
118 http://tools.ietf.org/id/draft-ietf-ldapext-ldap-c-api-05.txt */
119 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: ldap_set_option failed!");
126 if (!ldapconnected) {
127 if (LDAP_AUTH_NONE == ldap_auth_method) {
128 if (ldap_bind_s(ld, "", "", LDAP_AUTH_SIMPLE) != LDAP_SUCCESS ) {
129 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: ldap_bind failed!");
130 LOG(log_error, logtype_default, "ldap_auth_method: \'%d\'", ldap_auth_method);
135 } else if (LDAP_AUTH_SIMPLE == ldap_auth_method) {
136 if (ldap_bind_s(ld, ldap_auth_dn, ldap_auth_pw, ldap_auth_method) != LDAP_SUCCESS ) {
137 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: ldap_bind failed!");
138 LOG(log_error, logtype_default, "ldap_auth_dn: \'%s\', ldap_auth_pw: \'%s\', ldap_auth_method: \'%d\'",
139 ldap_auth_dn, ldap_auth_pw, ldap_auth_method);
146 // LOG(log_debug, logtype_afpd,"LDAP start search: base: %s, filter: %s, attr: %s", searchbase, filter, attributes[0]);
148 /* start LDAP search */
149 ldaperr = ldap_search_st(ld, searchbase, scope, filter, attributes, 0, &timeout, &msg);
150 if (ldaperr != LDAP_SUCCESS) {
151 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: ldap_search_st failed: %s", ldap_err2string(ldaperr));
156 /* parse search result */
157 // LOG(log_debug, logtype_default, "ldap_getuuidfromname: got %d entries from ldap search", ldap_count_entries(ld, msg));
158 if (ldap_count_entries(ld, msg) != 1) {
162 entry = ldap_first_entry(ld, msg);
164 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: error in ldap_first_entry");
168 attribute_values = ldap_get_values(ld, entry, attributes[0]);
169 if (attribute_values == NULL) {
170 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: error in ldap_get_values");
175 // LOG(log_debug, logtype_afpd,"LDAP Search result: %s: %s", attributes[0], attribute_values[0]);
177 /* allocate place for uuid as string */
178 *result = calloc( 1, strlen(attribute_values[0]) + 1);
179 if (*result == NULL) {
180 LOG(log_error, logtype_default, "ldap_getattr_fromfilter_withbase_scope: %s: error calloc'ing",strerror(errno));
185 strcpy( *result, attribute_values[0]);
186 ldap_value_free(attribute_values);
188 /* FIXME: is there another way to free entry ? */
189 while (entry != NULL)
190 entry = ldap_next_entry(ld, entry);
196 if ((ldapconnected && !(conflags & KEEPALIVE)) || (*result != NULL)) {
197 ldapconnected = 0; /* regardless of unbind errors */
198 // LOG(log_debug, logtype_default,"LDAP unbind!");
199 if (ldap_unbind_s(ld) != 0) {
200 LOG(log_error, logtype_default, "ldap_unbind_s: %s\n", ldap_err2string(ldaperr));
208 /********************************************************
210 ********************************************************/
212 int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string) {
215 char filter[256]; /* this should really be enough. we dont want to malloc everything! */
216 char *attributes[] = { ldap_uuid_attr, NULL};
220 if (type == UUID_GROUP)
221 ldap_attr = ldap_group_attr;
222 else /* type hopefully == UUID_USER */
223 ldap_attr = ldap_name_attr;
224 len = snprintf( filter, 256, "%s=%s", ldap_attr, name);
225 if (len >= 256 || len == -1) {
226 LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter error:%d, \"%s\"", len, filter);
230 if (type == UUID_GROUP) {
231 ret = ldap_getattr_fromfilter_withbase_scope( ldap_groupbase, filter, attributes, LDAP_SCOPE_ONELEVEL, KEEPALIVE, uuid_string);
232 } else { /* type hopefully == UUID_USER */
233 ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, LDAP_SCOPE_ONELEVEL, 0, uuid_string);
238 int ldap_getnamefromuuid( char *uuidstr, char **name, uuidtype_t *type) {
241 char filter[256]; /* this should really be enough. we dont want to malloc everything! */
242 char *attributes[] = { NULL, NULL};
245 len = snprintf( filter, 256, "%s=%s", ldap_uuid_attr, uuidstr);
246 if (len >= 256 || len == -1) {
247 LOG(log_error, logtype_default, "ldap_getnamefromuuid: filter overflow:%d, \"%s\"", len, filter);
250 /* search groups first. group acls are probably used more often */
251 attributes[0] = ldap_group_attr;
252 ret = ldap_getattr_fromfilter_withbase_scope( ldap_groupbase, filter, attributes, LDAP_SCOPE_ONELEVEL, KEEPALIVE, name);
257 attributes[0] = ldap_name_attr;
258 ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, LDAP_SCOPE_ONELEVEL, 0, name);