• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/acl/
1/*
2  Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
3
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.
8
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.
13*/
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif /* HAVE_CONFIG_H */
18
19#ifdef HAVE_LDAP
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/time.h>
24#include <string.h>
25#include <errno.h>
26#define LDAP_DEPRECATED 1
27#include <ldap.h>
28
29#include <atalk/logger.h>
30#include <atalk/afp.h>
31#include <atalk/uuid.h>
32#include <atalk/ldapconfig.h>   /* For struct ldap_pref */
33
34typedef enum {
35    KEEPALIVE = 1
36} ldapcon_t;
37
38/********************************************************
39 * LDAP config stuff. Filled by libatalk/acl/ldap_config.c
40 ********************************************************/
41int ldap_config_valid;
42
43char *ldap_server;
44int  ldap_auth_method;
45char *ldap_auth_dn;
46char *ldap_auth_pw;
47char *ldap_userbase;
48int  ldap_userscope;
49char *ldap_groupbase;
50int  ldap_groupscope;
51char *ldap_uuid_attr;
52char *ldap_name_attr;
53char *ldap_group_attr;
54char *ldap_uid_attr;
55
56struct 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}
70};
71
72struct 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},
82    {NULL,               NULL,     0}
83};
84
85/********************************************************
86 * Static helper function
87 ********************************************************/
88
89/*
90 * ldap_getattr_fromfilter_withbase_scope():
91 *   conflags: KEEPALIVE
92 *   scope: LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
93 *   result: return unique search result here, allocated here, caller must free
94 *
95 * returns: -1 on error
96 *           0 nothing found
97 *           1 successfull search, result int 'result'
98 *
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.
102 */
103static int ldap_getattr_fromfilter_withbase_scope( const char *searchbase,
104                                                   const char *filter,
105                                                   char *attributes[],
106                                                   int scope,
107                                                   ldapcon_t conflags,
108                                                   char **result) {
109    int ret;
110    int ldaperr;
111    int retrycount = 0;
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;
119
120    LOG(log_maxdebug, logtype_afpd,"ldap: BEGIN");
121
122    timeout.tv_sec = 3;
123    timeout.tv_usec = 0;
124
125    /* init LDAP if necessary */
126retry:
127    ret = 0;
128
129    if (ld == NULL) {
130        LOG(log_maxdebug, logtype_default, "ldap: server: \"%s\"",
131            ldap_server);
132        if ((ld = ldap_init(ldap_server, LDAP_PORT)) == NULL ) {
133            LOG(log_error, logtype_default, "ldap: ldap_init error: %s",
134                strerror(errno));
135            return -1;
136        }
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!");
141            free(ld);
142            ld = NULL;
143            return -1;
144        }
145    }
146
147    /* connect */
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\'",
152                    ldap_auth_method);
153                free(ld);
154                ld = NULL;
155                return -1;
156            }
157            ldapconnected = 1;
158
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);
164                free(ld);
165                ld = NULL;
166                return -1;
167            }
168            ldapconnected = 1;
169        }
170    }
171
172    LOG(log_maxdebug, logtype_afpd, "ldap: start search: base: %s, filter: %s, attr: %s",
173        searchbase, filter, attributes[0]);
174
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);
182        ret = -1;
183        goto cleanup;
184    }
185
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) {
190        ret = 0;
191        goto cleanup;
192    }
193
194    entry = ldap_first_entry(ld, msg);
195    if (entry == NULL) {
196        LOG(log_error, logtype_default, "ldap: ldap_first_entry error");
197        ret = -1;
198        goto cleanup;
199    }
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");
203        ret = -1;
204        goto cleanup;
205    }
206
207    LOG(log_maxdebug, logtype_afpd,"ldap: search result: %s: %s",
208        attributes[0], attribute_values[0]);
209
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));
214        ret = -1;
215        goto cleanup;
216    }
217
218cleanup:
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);
224    if (msg)
225        ldap_msgfree(msg);
226
227    if (ldapconnected) {
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));
232                return -1;
233            }
234            ld = NULL;
235            ldapconnected = 0;
236
237            /* In case of error we try twice */
238            if (ret == -1) {
239                retrycount++;
240                if (retrycount < 2)
241                    goto retry;
242            }
243        }
244    }
245    return ret;
246}
247
248/********************************************************
249 * Interface
250 ********************************************************/
251
252/*!
253 * Search UUID for name in LDAP
254 *
255 * Caller must free uuid_string when done with it
256 *
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
260 *
261 * @returns 0 on success, -1 on error or not found
262 */
263int ldap_getuuidfromname( const char *name, uuidtype_t type, char **uuid_string) {
264    int ret;
265    int len;
266    char filter[256];           /* this should really be enough. we dont want to malloc everything! */
267    char *attributes[]  = { ldap_uuid_attr, NULL};
268    char *ldap_attr;
269
270    if (!ldap_config_valid)
271        return -1;
272
273    /* make filter */
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);
281        return -1;
282    }
283
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);
288    }
289    if (ret != 1)
290        return -1;
291    return 0;
292}
293
294/*
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
298 *
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
302 *
303 * returns 0 on success, -1 on errror
304 */
305int ldap_getnamefromuuid( const char *uuidstr, char **name, uuidtype_t *type) {
306    int ret;
307    int len;
308    char filter[256];       /* this should really be enough. we dont want to malloc everything! */
309    char *attributes[]  = { NULL, NULL};
310
311    if (!ldap_config_valid)
312        return -1;
313
314    /* make filter */
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);
318        return -1;
319    }
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);
323    if (ret == -1)
324        return -1;
325    if (ret == 1) {
326        *type = UUID_GROUP;
327        return 0;
328    }
329
330    attributes[0] = ldap_name_attr;
331    ret = ldap_getattr_fromfilter_withbase_scope( ldap_userbase, filter, attributes, ldap_userscope, KEEPALIVE, name);
332    if (ret == 1) {
333        *type = UUID_USER;
334        return 0;
335    }
336
337    return -1;
338}
339#endif  /* HAVE_LDAP */
340