~ubuntu-branches/ubuntu/precise/autofs5/precise

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-get-qdn-fail.patch/modules/lookup_ldap.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-07-03 14:35:46 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110703143546-nej26krjij0rf792
Tags: 5.0.6-0ubuntu1
* New upstream release:
  - Dropped upstream patches 
  - Refreshed debian/patches/17ld.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * lookup_ldap.c - Module for Linux automountd to access automount
3
 
 *                 maps in LDAP directories.
4
 
 *
5
 
 *   Copyright 2001-2003 Ian Kent <raven@themaw.net>
6
 
 *
7
 
 *   This program is free software; you can redistribute it and/or modify
8
 
 *   it under the terms of the GNU General Public License as published by
9
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
10
 
 *   USA; either version 2 of the License, or (at your option) any later
11
 
 *   version.
12
 
 *
13
 
 *   This program is distributed in the hope that it will be useful,
14
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 *   GNU General Public License for more details.
17
 
 *
18
 
 */
19
 
 
20
 
#include <sys/types.h>
21
 
#include <sys/stat.h>
22
 
#include <ctype.h>
23
 
#include <string.h>
24
 
#include <stdlib.h>
25
 
#include <time.h>
26
 
#include <signal.h>
27
 
#include <netinet/in.h>
28
 
#include <arpa/nameser.h>
29
 
#include <resolv.h>
30
 
#include <lber.h>
31
 
#include <ldap.h>
32
 
 
33
 
#define MODULE_LOOKUP
34
 
#include "automount.h"
35
 
#include "nsswitch.h"
36
 
#include "lookup_ldap.h"
37
 
 
38
 
#define MAPFMT_DEFAULT "sun"
39
 
 
40
 
#define MODPREFIX "lookup(ldap): "
41
 
 
42
 
int lookup_version = AUTOFS_LOOKUP_VERSION;     /* Required by protocol */
43
 
 
44
 
static struct ldap_schema common_schema[] = {
45
 
        {"nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry"},
46
 
        {"automountMap", "ou", "automount", "cn", "automountInformation"},
47
 
        {"automountMap", "automountMapName", "automount", "automountKey", "automountInformation"},
48
 
};
49
 
static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
50
 
 
51
 
struct ldap_search_params {
52
 
        struct autofs_point *ap;
53
 
        LDAP *ldap;
54
 
        char *query, **attrs;
55
 
        struct berval *cookie;
56
 
        int morePages;
57
 
        ber_int_t totalCount;
58
 
        LDAPMessage *result;
59
 
        time_t age;
60
 
};
61
 
 
62
 
static int decode_percent_hack(const char *, char **);
63
 
 
64
 
#ifndef HAVE_LDAP_CREATE_PAGE_CONTROL
65
 
int ldap_create_page_control(LDAP *ldap, ber_int_t pagesize,
66
 
                             struct berval *cookie, char isCritical,
67
 
                             LDAPControl **output)
68
 
{
69
 
        BerElement *ber;
70
 
        int rc;
71
 
 
72
 
        if (!ldap || !output)
73
 
                return LDAP_PARAM_ERROR;
74
 
 
75
 
        ber = ber_alloc_t(LBER_USE_DER);
76
 
        if (!ber)
77
 
                return LDAP_NO_MEMORY;
78
 
 
79
 
        if (ber_printf(ber, "{io}", pagesize,
80
 
                        (cookie && cookie->bv_val) ? cookie->bv_val : "",
81
 
                        (cookie && cookie->bv_val) ? cookie->bv_len : 0)
82
 
                                == LBER_ERROR) {
83
 
                ber_free(ber, 1);
84
 
                return LDAP_ENCODING_ERROR;
85
 
        }
86
 
 
87
 
        rc = ldap_create_control(LDAP_CONTROL_PAGEDRESULTS, ber, isCritical, output);
88
 
 
89
 
        return rc;
90
 
}
91
 
#endif /* HAVE_LDAP_CREATE_PAGE_CONTROL */
92
 
 
93
 
#ifndef HAVE_LDAP_PARSE_PAGE_CONTROL
94
 
int ldap_parse_page_control(LDAP *ldap, LDAPControl **controls,
95
 
                            ber_int_t *totalcount, struct berval **cookie)
96
 
{
97
 
        int i, rc;
98
 
        BerElement *theBer;
99
 
        LDAPControl *listCtrlp;
100
 
 
101
 
        for (i = 0; controls[i] != NULL; i++) {
102
 
                if (strcmp(controls[i]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0) {
103
 
                        listCtrlp = controls[i];
104
 
 
105
 
                        theBer = ber_init(&listCtrlp->ldctl_value);
106
 
                        if (!theBer)
107
 
                                return LDAP_NO_MEMORY;
108
 
 
109
 
                        rc = ber_scanf(theBer, "{iO}", totalcount, cookie);
110
 
                        if (rc == LBER_ERROR) {
111
 
                                ber_free(theBer, 1);
112
 
                                return LDAP_DECODING_ERROR;
113
 
                        }
114
 
 
115
 
                        ber_free(theBer, 1);
116
 
                        return LDAP_SUCCESS;
117
 
                }
118
 
        }
119
 
 
120
 
        return LDAP_CONTROL_NOT_FOUND;
121
 
}
122
 
#endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */
123
 
 
124
 
static void uris_mutex_lock(struct lookup_context *ctxt)
125
 
{
126
 
        int status = pthread_mutex_lock(&ctxt->uris_mutex);
127
 
        if (status)
128
 
                fatal(status);
129
 
        return;
130
 
}
131
 
 
132
 
static void uris_mutex_unlock(struct lookup_context *ctxt)
133
 
{
134
 
        int status = pthread_mutex_unlock(&ctxt->uris_mutex);
135
 
        if (status)
136
 
                fatal(status);
137
 
        return;
138
 
}
139
 
 
140
 
int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
141
 
{
142
 
        int rv;
143
 
 
144
 
        if (ctxt->version == 2)
145
 
                rv = ldap_simple_bind_s(ldap, ctxt->base, NULL);
146
 
        else
147
 
                rv = ldap_simple_bind_s(ldap, NULL, NULL);
148
 
 
149
 
        if (rv != LDAP_SUCCESS) {
150
 
                if (!ctxt->uris) {
151
 
                        crit(logopt, MODPREFIX
152
 
                             "Unable to bind to the LDAP server: "
153
 
                             "%s, error %s", ctxt->server ? "" : "(default)",
154
 
                             ldap_err2string(rv));
155
 
                } else {
156
 
                        info(logopt, MODPREFIX "Unable to bind to the LDAP server: "
157
 
                             "%s, error %s", uri, ldap_err2string(rv));
158
 
                }
159
 
                return -1;
160
 
        }
161
 
 
162
 
        return 0;
163
 
}
164
 
 
165
 
int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
166
 
{
167
 
        int rv;
168
 
 
169
 
#ifdef WITH_SASL
170
 
        /*
171
 
         * The OpenSSL library can't handle having its message and error
172
 
         * string database loaded multiple times and segfaults if the
173
 
         * TLS environment is not reset at the right times. As there
174
 
         * is no ldap_stop_tls call in the openldap library we have
175
 
         * to do the job ourselves, here and in lookup_done when the
176
 
         * module is closed.
177
 
         */
178
 
        if (ctxt->use_tls == LDAP_TLS_RELEASE) {
179
 
                ERR_remove_state(0);
180
 
                ctxt->use_tls = LDAP_TLS_INIT;
181
 
        }
182
 
        autofs_sasl_unbind(ctxt);
183
 
#endif
184
 
 
185
 
        rv = ldap_unbind_ext(ldap, NULL, NULL);
186
 
        if (rv != LDAP_SUCCESS)
187
 
                error(logopt, "unbind failed: %s", ldap_err2string(rv));
188
 
 
189
 
        return rv;
190
 
}
191
 
 
192
 
LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
193
 
{
194
 
        LDAP *ldap = NULL;
195
 
        struct timeval timeout     = { ctxt->timeout, 0 };
196
 
        struct timeval net_timeout = { ctxt->network_timeout, 0 };
197
 
        int rv;
198
 
 
199
 
        ctxt->version = 3;
200
 
 
201
 
        /* Initialize the LDAP context. */
202
 
        rv = ldap_initialize(&ldap, uri);
203
 
        if (rv != LDAP_OPT_SUCCESS) {
204
 
                info(logopt, MODPREFIX
205
 
                     "couldn't initialize LDAP connection to %s",
206
 
                     uri ? uri : "default");
207
 
                return NULL;
208
 
        }
209
 
 
210
 
        /* Use LDAPv3 */
211
 
        rv = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ctxt->version);
212
 
        if (rv != LDAP_OPT_SUCCESS) {
213
 
                /* fall back to LDAPv2 */
214
 
                ldap_unbind_ext(ldap, NULL, NULL);
215
 
                rv = ldap_initialize(&ldap, uri);
216
 
                if (rv != LDAP_OPT_SUCCESS) {
217
 
                        crit(logopt, MODPREFIX "couldn't initialize LDAP");
218
 
                        return NULL;
219
 
                }
220
 
                ctxt->version = 2;
221
 
        }
222
 
 
223
 
 
224
 
        if (ctxt->timeout != -1) {
225
 
                /* Set synchronous call timeout */
226
 
                rv = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &timeout);
227
 
                if (rv != LDAP_OPT_SUCCESS)
228
 
                        info(logopt, MODPREFIX
229
 
                             "failed to set synchronous call timeout to %d",
230
 
                             timeout.tv_sec);
231
 
        }
232
 
 
233
 
        /* Sane network timeout */
234
 
        rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &net_timeout);
235
 
        if (rv != LDAP_OPT_SUCCESS)
236
 
                info(logopt, MODPREFIX "failed to set connection timeout to %d",
237
 
                     net_timeout.tv_sec);
238
 
 
239
 
#ifdef WITH_SASL
240
 
        if (ctxt->use_tls) {
241
 
                if (ctxt->version == 2) {
242
 
                        if (ctxt->tls_required) {
243
 
                                error(logopt, MODPREFIX
244
 
                                    "TLS required but connection is version 2");
245
 
                                ldap_unbind_ext(ldap, NULL, NULL);
246
 
                                return NULL;
247
 
                        }
248
 
                        return ldap;
249
 
                }
250
 
 
251
 
                rv = ldap_start_tls_s(ldap, NULL, NULL);
252
 
                if (rv != LDAP_SUCCESS) {
253
 
                        unbind_ldap_connection(logopt, ldap, ctxt);
254
 
                        if (ctxt->tls_required) {
255
 
                                error(logopt, MODPREFIX
256
 
                                      "TLS required but START_TLS failed: %s",
257
 
                                      ldap_err2string(rv));
258
 
                                return NULL;
259
 
                        }
260
 
                        ctxt->use_tls = LDAP_TLS_DONT_USE;
261
 
                        ldap = init_ldap_connection(logopt, uri, ctxt);
262
 
                        if (ldap)
263
 
                                ctxt->use_tls = LDAP_TLS_INIT;
264
 
                        return ldap;
265
 
                }
266
 
                ctxt->use_tls = LDAP_TLS_RELEASE;
267
 
        }
268
 
#endif
269
 
 
270
 
        return ldap;
271
 
}
272
 
 
273
 
static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
274
 
{
275
 
        char buf[MAX_ERR_BUF];
276
 
        char *query, *dn, *qdn;
277
 
        LDAPMessage *result, *e;
278
 
        struct ldap_searchdn *sdns = NULL;
279
 
        char *attrs[2];
280
 
        struct berval **value;
281
 
        int scope;
282
 
        int rv, l;
283
 
 
284
 
        attrs[0] = (char *) key;
285
 
        attrs[1] = NULL;
286
 
 
287
 
        if (!ctxt->mapname && !ctxt->base) {
288
 
                error(logopt, MODPREFIX "no master map to lookup");
289
 
                return 0;
290
 
        }
291
 
 
292
 
        /* Build a query string. */
293
 
        l = strlen("(objectclass=)") + strlen(class) + 1;
294
 
        if (ctxt->mapname)
295
 
                l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
296
 
 
297
 
        query = malloc(l);
298
 
        if (query == NULL) {
299
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
300
 
                crit(logopt, MODPREFIX "malloc: %s", estr);
301
 
                return NSS_STATUS_UNAVAIL;
302
 
        }
303
 
 
304
 
        /*
305
 
         * If we have a master mapname construct a query using it
306
 
         * otherwise assume the base dn will catch it.
307
 
         */
308
 
        if (ctxt->mapname) {
309
 
                if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
310
 
                     key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
311
 
                        debug(logopt,
312
 
                              MODPREFIX "error forming query string");
313
 
                        free(query);
314
 
                        return 0;
315
 
                }
316
 
                scope = LDAP_SCOPE_SUBTREE;
317
 
        } else {
318
 
                if (sprintf(query, "(objectclass=%s)", class) >= l) {
319
 
                        debug(logopt,
320
 
                              MODPREFIX "error forming query string");
321
 
                        free(query);
322
 
                        return 0;
323
 
                }
324
 
                scope = LDAP_SCOPE_SUBTREE;
325
 
        }
326
 
 
327
 
        if (!ctxt->base) {
328
 
                sdns = defaults_get_searchdns();
329
 
                if (sdns) {
330
 
                        if (ctxt->sdns)
331
 
                                defaults_free_searchdns(ctxt->sdns);
332
 
                        ctxt->sdns = sdns;
333
 
                }
334
 
        }
335
 
 
336
 
        dn = NULL;
337
 
        if (!ctxt->sdns) {
338
 
                rv = ldap_search_s(ldap, ctxt->base,
339
 
                                   scope, query, attrs, 0, &result);
340
 
                if ((rv != LDAP_SUCCESS) || !result) {
341
 
                        error(logopt,
342
 
                              MODPREFIX "query failed for %s: %s",
343
 
                              query, ldap_err2string(rv));
344
 
                        free(query);
345
 
                        return 0;
346
 
                }
347
 
 
348
 
                e = ldap_first_entry(ldap, result);
349
 
                if (e && (value = ldap_get_values_len(ldap, e, key))) {
350
 
                        ldap_value_free_len(value);
351
 
                        dn = ldap_get_dn(ldap, e);
352
 
                        debug(logopt, MODPREFIX "found query dn %s", dn);
353
 
                } else {
354
 
                        debug(logopt,
355
 
                              MODPREFIX "query succeeded, no matches for %s",
356
 
                              query);
357
 
                        ldap_msgfree(result);
358
 
                        free(query);
359
 
                        return 0;
360
 
                }
361
 
        } else {
362
 
                struct ldap_searchdn *this = ctxt->sdns;
363
 
 
364
 
                debug(logopt, MODPREFIX "check search base list");
365
 
 
366
 
                result = NULL;
367
 
                while (this) {
368
 
                        rv = ldap_search_s(ldap, this->basedn,
369
 
                                           scope, query, attrs, 0, &result);
370
 
                        if ((rv == LDAP_SUCCESS) && result) {
371
 
                                debug(logopt, MODPREFIX
372
 
                                      "found search base under %s",
373
 
                                      this->basedn);
374
 
 
375
 
                                e = ldap_first_entry(ldap, result);
376
 
                                if (e && (value = ldap_get_values_len(ldap, e, key))) {
377
 
                                        ldap_value_free_len(value);
378
 
                                        dn = ldap_get_dn(ldap, e);
379
 
                                        debug(logopt, MODPREFIX "found query dn %s", dn);
380
 
                                        break;
381
 
                                } else {
382
 
                                        debug(logopt,
383
 
                                              MODPREFIX "query succeeded, no matches for %s",
384
 
                                              query);
385
 
                                        ldap_msgfree(result);
386
 
                                        result = NULL;
387
 
                                }
388
 
                        } else {
389
 
                                error(logopt,
390
 
                                      MODPREFIX "query failed for search dn %s: %s",
391
 
                                      this->basedn, ldap_err2string(rv));
392
 
                                if (result) {
393
 
                                        ldap_msgfree(result);
394
 
                                        result = NULL;
395
 
                                }
396
 
                        }
397
 
 
398
 
                        this = this->next;
399
 
                }
400
 
 
401
 
                if (!result) {
402
 
                        error(logopt,
403
 
                              MODPREFIX "failed to find query dn under search base dns");
404
 
                        free(query);
405
 
                        return 0;
406
 
                }
407
 
        }
408
 
 
409
 
        free(query);
410
 
        qdn = strdup(dn);
411
 
        ldap_memfree(dn);
412
 
        ldap_msgfree(result);
413
 
        if (!qdn)
414
 
                return 0;
415
 
 
416
 
        if (ctxt->qdn)
417
 
                free(ctxt->qdn);
418
 
 
419
 
        ctxt->qdn = qdn;
420
 
 
421
 
        return 1;
422
 
}
423
 
 
424
 
static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
425
 
{
426
 
        struct ldap_schema *schema;
427
 
        char *mc, *ma, *ec, *ea, *va;
428
 
 
429
 
        mc = strdup(s->map_class);
430
 
        if (!mc)
431
 
                return NULL;
432
 
 
433
 
        ma = strdup(s->map_attr);
434
 
        if (!ma) {
435
 
                free(mc);
436
 
                return NULL;
437
 
        }
438
 
 
439
 
        ec = strdup(s->entry_class);
440
 
        if (!ec) {
441
 
                free(mc);
442
 
                free(ma);
443
 
                return NULL;
444
 
        }
445
 
 
446
 
        ea = strdup(s->entry_attr);
447
 
        if (!ea) {
448
 
                free(mc);
449
 
                free(ma);
450
 
                free(ec);
451
 
                return NULL;
452
 
        }
453
 
 
454
 
        va = strdup(s->value_attr);
455
 
        if (!va) {
456
 
                free(mc);
457
 
                free(ma);
458
 
                free(ec);
459
 
                free(ea);
460
 
                return NULL;
461
 
        }
462
 
 
463
 
        schema = malloc(sizeof(struct ldap_schema));
464
 
        if (!schema) {
465
 
                free(mc);
466
 
                free(ma);
467
 
                free(ec);
468
 
                free(ea);
469
 
                free(va);
470
 
                return NULL;
471
 
        }
472
 
 
473
 
        schema->map_class = mc;
474
 
        schema->map_attr = ma;
475
 
        schema->entry_class = ec;
476
 
        schema->entry_attr = ea;
477
 
        schema->value_attr = va;
478
 
 
479
 
        return schema;
480
 
}
481
 
 
482
 
static int find_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
483
 
{
484
 
        struct ldap_schema *schema;
485
 
        unsigned int i;
486
 
 
487
 
        if (ctxt->schema)
488
 
                return 0;
489
 
 
490
 
        for (i = 0; i < common_schema_count; i++) {
491
 
                const char *class = common_schema[i].map_class;
492
 
                const char *key = common_schema[i].map_attr;
493
 
                if (get_query_dn(logopt, ldap, ctxt, class, key)) {
494
 
                        schema = alloc_common_schema(&common_schema[i]);
495
 
                        if (!schema) {
496
 
                                error(logopt, MODPREFIX "failed to allocate schema");
497
 
                                return 0;
498
 
                        }
499
 
                        ctxt->schema = schema;
500
 
                        return 1;
501
 
                }
502
 
        }
503
 
 
504
 
        return 0;
505
 
}
506
 
 
507
 
static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
508
 
{
509
 
        char *host = NULL, *nhost;
510
 
        int rv, need_base = 1;
511
 
 
512
 
#ifdef WITH_SASL
513
 
        debug(logopt, MODPREFIX "auth_required: %d, sasl_mech %s",
514
 
              ctxt->auth_required, ctxt->sasl_mech);
515
 
 
516
 
        if (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT)) {
517
 
                rv = autofs_sasl_bind(logopt, ldap, ctxt);
518
 
                debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
519
 
        } else {
520
 
                rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
521
 
                debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
522
 
        }
523
 
#else
524
 
        rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
525
 
        debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
526
 
#endif
527
 
 
528
 
        if (rv != 0)
529
 
                return 0;
530
 
 
531
 
        rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
532
 
        if (rv != LDAP_SUCCESS || !host) {
533
 
                debug(logopt, "failed to get hostname for connection");
534
 
                return 0;
535
 
        }
536
 
 
537
 
        nhost = strdup(host);
538
 
        if (!nhost) {
539
 
                debug(logopt, "failed to alloc context for hostname");
540
 
                return 0;
541
 
        }
542
 
        ldap_memfree(host);
543
 
 
544
 
        if (!ctxt->cur_host) {
545
 
                ctxt->cur_host = nhost;
546
 
                /* Check if schema defined in conf first time only */
547
 
                ctxt->schema = defaults_get_schema();
548
 
        } else {
549
 
                /* If connection host has changed update */
550
 
                if (strcmp(ctxt->cur_host, nhost)) {
551
 
                        free(ctxt->cur_host);
552
 
                        ctxt->cur_host = nhost;
553
 
                } else {
554
 
                        free(nhost);
555
 
                        need_base = 0;
556
 
                }
557
 
        }
558
 
 
559
 
        if (ctxt->schema && !need_base)
560
 
                return 1;
561
 
 
562
 
        /*
563
 
         * If the schema isn't defined in the configuration then check for
564
 
         * presence of a map dn with a the common schema. Then calculate the
565
 
         * base dn for searches.
566
 
         */
567
 
        if (!ctxt->schema) {
568
 
                if (!find_query_dn(logopt, ldap, ctxt)) {
569
 
                        warn(logopt,
570
 
                              MODPREFIX "failed to find valid query dn");
571
 
                        return 0;
572
 
                }
573
 
        } else {
574
 
                const char *class = ctxt->schema->map_class;
575
 
                const char *key = ctxt->schema->map_attr;
576
 
                if (!get_query_dn(logopt, ldap, ctxt, class, key)) {
577
 
                        error(logopt, MODPREFIX "failed to get query dn");
578
 
                        return 0;
579
 
                }
580
 
        }
581
 
 
582
 
        return 1;
583
 
}
584
 
 
585
 
static LDAP *do_connect(unsigned logopt, const char *uri, struct lookup_context *ctxt)
586
 
{
587
 
        LDAP *ldap;
588
 
 
589
 
        ldap = init_ldap_connection(logopt, uri, ctxt);
590
 
        if (!ldap)
591
 
                return NULL;
592
 
 
593
 
        if (!do_bind(logopt, ldap, uri, ctxt)) {
594
 
                unbind_ldap_connection(logopt, ldap, ctxt);
595
 
                return NULL;
596
 
        }
597
 
 
598
 
        return ldap;
599
 
}
600
 
 
601
 
static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_context *ctxt)
602
 
{
603
 
        LDAP *ldap;
604
 
 
605
 
        ldap = do_connect(logopt, uri, ctxt);
606
 
        if (!ldap) {
607
 
                warn(logopt,
608
 
                     MODPREFIX "couldn't connect to server %s",
609
 
                     uri ? uri : "default");
610
 
                return NULL;
611
 
        }
612
 
 
613
 
        return ldap;
614
 
}
615
 
 
616
 
static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
617
 
{
618
 
        LDAP *ldap = NULL;
619
 
        struct ldap_uri *this;
620
 
        struct list_head *p, *first;
621
 
        struct dclist *dclist = NULL;
622
 
        char *uri = NULL;
623
 
 
624
 
        uris_mutex_lock(ctxt);
625
 
        if (ctxt->dclist) {
626
 
                dclist = ctxt->dclist;
627
 
                if (ctxt->dclist->expire < time(NULL)) {
628
 
                        free_dclist(ctxt->dclist);
629
 
                        ctxt->dclist = NULL;
630
 
                        dclist = NULL;
631
 
                }
632
 
        }
633
 
        if (!ctxt->uri)
634
 
                first = ctxt->uris;
635
 
        else
636
 
                first = &ctxt->uri->list;
637
 
        uris_mutex_unlock(ctxt);
638
 
 
639
 
 
640
 
        /* Try each uri, save point in server list upon success */
641
 
        p = first->next;
642
 
        while(p != first) {
643
 
                /* Skip list head */
644
 
                if (p == ctxt->uris) {
645
 
                        p = p->next;
646
 
                        continue;
647
 
                }
648
 
                this = list_entry(p, struct ldap_uri, list);
649
 
                if (!strstr(this->uri, ":///"))
650
 
                        uri = strdup(this->uri);
651
 
                else {
652
 
                        if (dclist)
653
 
                                uri = strdup(dclist->uri);
654
 
                        else {
655
 
                                struct dclist *tmp;
656
 
                                tmp = get_dc_list(logopt, this->uri);
657
 
                                if (!tmp) {
658
 
                                        p = p->next;
659
 
                                        continue;
660
 
                                }
661
 
                                dclist = tmp;
662
 
                                uri = strdup(dclist->uri);
663
 
                        }
664
 
                }
665
 
                if (!uri) {
666
 
                        if (dclist) {
667
 
                                free_dclist(dclist);
668
 
                                dclist = NULL;
669
 
                        }
670
 
                        p = p->next;
671
 
                        continue;
672
 
                }
673
 
                debug(logopt, "trying server uri %s", uri);
674
 
                ldap = connect_to_server(logopt, uri, ctxt);
675
 
                if (ldap) {
676
 
                        info(logopt, "connected to uri %s", uri);
677
 
                        free(uri);
678
 
                        break;
679
 
                }
680
 
                free(uri);
681
 
                uri = NULL;
682
 
                if (dclist) {
683
 
                        free_dclist(dclist);
684
 
                        dclist = NULL;
685
 
                }
686
 
                p = p->next;
687
 
        }
688
 
 
689
 
        uris_mutex_lock(ctxt);
690
 
        if (ldap)
691
 
                ctxt->uri = this;
692
 
        if (dclist) {
693
 
                if (!ctxt->dclist)
694
 
                        ctxt->dclist = dclist;
695
 
                else {
696
 
                        if (ctxt->dclist != dclist) {
697
 
                                free_dclist(ctxt->dclist);
698
 
                                ctxt->dclist = dclist;
699
 
                        }
700
 
                }
701
 
        }
702
 
        uris_mutex_unlock(ctxt);
703
 
 
704
 
        return ldap;
705
 
}
706
 
 
707
 
static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
708
 
{
709
 
        LDAP *ldap;
710
 
        char *uri;
711
 
 
712
 
        if (ctxt->server || !ctxt->uris) {
713
 
                ldap = do_connect(logopt, ctxt->server, ctxt);
714
 
#ifdef WITH_SASL
715
 
                /* Dispose of the sasl authentication connection and try again. */
716
 
                if (!ldap) {
717
 
                        autofs_sasl_dispose(ctxt);
718
 
                        ldap = connect_to_server(logopt, ctxt->server, ctxt);
719
 
                }
720
 
#endif
721
 
                return ldap;
722
 
        }
723
 
 
724
 
        uris_mutex_lock(ctxt);
725
 
        if (ctxt->dclist)
726
 
                uri = strdup(ctxt->dclist->uri);
727
 
        else if (ctxt->uri)
728
 
                uri = strdup(ctxt->uri->uri);
729
 
        else {
730
 
                uris_mutex_unlock(ctxt);
731
 
                goto find_server;
732
 
        }
733
 
        uris_mutex_unlock(ctxt);
734
 
 
735
 
        if (!uri) {
736
 
                char buf[MAX_ERR_BUF];
737
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
738
 
                crit(logopt, MODPREFIX "strdup: %s", estr);
739
 
                return NULL;
740
 
        }
741
 
 
742
 
        ldap = do_connect(logopt, uri, ctxt);
743
 
#ifdef WITH_SASL
744
 
        /*
745
 
         * Dispose of the sasl authentication connection and try the
746
 
         * current server again before trying other servers in the list.
747
 
         */
748
 
        if (!ldap) {
749
 
                autofs_sasl_dispose(ctxt);
750
 
                ldap = connect_to_server(logopt, uri, ctxt);
751
 
        }
752
 
#endif
753
 
        free(uri);
754
 
 
755
 
        if (ldap)
756
 
                return ldap;
757
 
 
758
 
        /* Failed to connect, try to find a new server */
759
 
 
760
 
#ifdef WITH_SASL
761
 
        autofs_sasl_dispose(ctxt);
762
 
#endif
763
 
 
764
 
find_server:
765
 
        /* Current server failed connect, try the rest */
766
 
        ldap = find_server(logopt, ctxt);
767
 
        if (!ldap)
768
 
                error(logopt, MODPREFIX "failed to find available server");
769
 
 
770
 
        return ldap;
771
 
}
772
 
 
773
 
#ifdef WITH_SASL
774
 
int get_property(unsigned logopt, xmlNodePtr node, const char *prop, char **value)
775
 
{
776
 
        xmlChar *ret;
777
 
        xmlChar *property = (xmlChar *) prop;
778
 
 
779
 
        if (!(ret = xmlGetProp(node, property))) {
780
 
                *value = NULL;
781
 
                return 0;
782
 
        }
783
 
 
784
 
        if (!(*value = strdup((char *) ret))) {
785
 
                logerr(MODPREFIX "strdup failed with %d", errno);
786
 
                xmlFree(ret);
787
 
                return -1;
788
 
        }
789
 
 
790
 
        xmlFree(ret);
791
 
        return 0;
792
 
}
793
 
 
794
 
/*
795
 
 *  For plain text, login and digest-md5 authentication types, we need
796
 
 *  user and password credentials.
797
 
 */
798
 
int authtype_requires_creds(const char *authtype)
799
 
{
800
 
        if (!strncmp(authtype, "PLAIN", strlen("PLAIN")) ||
801
 
            !strncmp(authtype, "DIGEST-MD5", strlen("DIGEST-MD5")) ||
802
 
            !strncmp(authtype, "LOGIN", strlen("LOGIN")))
803
 
                return 1;
804
 
        return 0;
805
 
}
806
 
 
807
 
/*
808
 
 *  Returns:
809
 
 *    -1  --  The permission on the file are not correct or
810
 
 *            the xml document was mal-formed
811
 
 *     0  --  The file was non-existent
812
 
 *            the file was empty
813
 
 *            the file contained valid data, which was filled into 
814
 
 *            ctxt->sasl_mech, ctxt->user, and ctxt->secret
815
 
 *
816
 
 *  The idea is that a -1 return value should abort the program.  A 0
817
 
 *  return value requires more checking.  If ctxt->authtype is filled in,
818
 
 *  then no further action is necessary.  If it is not, the caller is free
819
 
 *  to then use another method to determine how to connect to the server.
820
 
 */
821
 
int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
822
 
{
823
 
        int          ret = 0, fallback = 0;
824
 
        unsigned int auth_required = LDAP_AUTH_NOTREQUIRED;
825
 
        unsigned int tls_required = 0, use_tls = 0;
826
 
        struct stat  st;
827
 
        xmlDocPtr    doc = NULL;
828
 
        xmlNodePtr   root = NULL;
829
 
        char         *authrequired, *auth_conf, *authtype;
830
 
        char         *user = NULL, *secret = NULL;
831
 
        char         *client_princ = NULL, *client_cc = NULL;
832
 
        char         *usetls, *tlsrequired;
833
 
 
834
 
        authtype = user = secret = NULL;
835
 
 
836
 
        auth_conf = (char *) defaults_get_auth_conf_file();
837
 
        if (!auth_conf) {
838
 
                error(logopt,
839
 
                      MODPREFIX "failed to get auth config file name.");
840
 
                return 0;
841
 
        }
842
 
 
843
 
        /*
844
 
         *  Here we check that the config file exists, and that we have
845
 
         *  permission to read it.  The XML library does not specify why a
846
 
         *  parse happens to fail, so we have to do all of this checking
847
 
         *  beforehand.
848
 
         */
849
 
        memset(&st, 0, sizeof(st));
850
 
        if (stat(auth_conf, &st) == -1 || st.st_size == 0) {
851
 
                /* Auth config doesn't exist so disable TLS and auth */
852
 
                if (errno == ENOENT) {
853
 
                        ctxt->auth_conf = auth_conf;
854
 
                        ctxt->use_tls = LDAP_TLS_DONT_USE;
855
 
                        ctxt->tls_required = LDAP_TLS_DONT_USE;
856
 
                        ctxt->auth_required = LDAP_AUTH_NOTREQUIRED;
857
 
                        ctxt->sasl_mech = NULL;
858
 
                        ctxt->user = NULL;
859
 
                        ctxt->secret = NULL;
860
 
                        ctxt->client_princ = NULL;
861
 
                        return 0;
862
 
                }
863
 
                error(logopt,
864
 
                      MODPREFIX "stat(2) failed with error %s.",
865
 
                      strerror(errno));
866
 
                return 0;
867
 
        }
868
 
 
869
 
        if (!S_ISREG(st.st_mode) ||
870
 
            st.st_uid != 0 || st.st_gid != 0 ||
871
 
            (st.st_mode & 0x01ff) != 0600) {
872
 
                error(logopt, MODPREFIX
873
 
                      "Configuration file %s exists, but is not usable. "
874
 
                      "Please make sure that it is owned by root, group "
875
 
                      "is root, and the mode is 0600.",
876
 
                      auth_conf);
877
 
                return -1;
878
 
        }
879
 
 
880
 
        doc = xmlParseFile(auth_conf);
881
 
        if (!doc) {
882
 
                error(logopt, MODPREFIX
883
 
                     "xmlParseFile failed for %s.", auth_conf);
884
 
                goto out;
885
 
        }
886
 
 
887
 
        root = xmlDocGetRootElement(doc);
888
 
        if (!root) {
889
 
                debug(logopt, MODPREFIX
890
 
                      "empty xml document (%s).", auth_conf);
891
 
                fallback = 1;
892
 
                goto out;
893
 
        }
894
 
 
895
 
        if (xmlStrcmp(root->name, (const xmlChar *)"autofs_ldap_sasl_conf")) {
896
 
                error(logopt, MODPREFIX
897
 
                      "The root node of the XML document %s is not "
898
 
                      "autofs_ldap_sasl_conf.", auth_conf);
899
 
                goto out;
900
 
        }
901
 
 
902
 
        ret = get_property(logopt, root, "usetls", &usetls);
903
 
        if (ret != 0) {
904
 
                error(logopt,
905
 
                      MODPREFIX
906
 
                      "Failed read the usetls property from "
907
 
                      "the configuration file %s.", auth_conf);
908
 
                goto out;
909
 
        }
910
 
 
911
 
        if (!usetls || ctxt->port == LDAPS_PORT)
912
 
                use_tls = LDAP_TLS_DONT_USE;
913
 
        else {
914
 
                if (!strcasecmp(usetls, "yes"))
915
 
                        use_tls = LDAP_TLS_INIT;
916
 
                else if (!strcasecmp(usetls, "no"))
917
 
                        use_tls = LDAP_TLS_DONT_USE;
918
 
                else {
919
 
                        error(logopt,
920
 
                              MODPREFIX
921
 
                              "The usetls property must have value "
922
 
                              "\"yes\" or \"no\".");
923
 
                        ret = -1;
924
 
                        goto out;
925
 
                }
926
 
                free(usetls);
927
 
        }
928
 
 
929
 
        ret = get_property(logopt, root, "tlsrequired", &tlsrequired);
930
 
        if (ret != 0) {
931
 
                error(logopt,
932
 
                      MODPREFIX
933
 
                      "Failed read the tlsrequired property from "
934
 
                      "the configuration file %s.", auth_conf);
935
 
                goto out;
936
 
        }
937
 
 
938
 
        if (!tlsrequired)
939
 
                tls_required = LDAP_TLS_DONT_USE;
940
 
        else {
941
 
                if (!strcasecmp(tlsrequired, "yes"))
942
 
                        tls_required = LDAP_TLS_REQUIRED;
943
 
                else if (!strcasecmp(tlsrequired, "no"))
944
 
                        tls_required = LDAP_TLS_DONT_USE;
945
 
                else {
946
 
                        error(logopt,
947
 
                              MODPREFIX
948
 
                              "The tlsrequired property must have value "
949
 
                              "\"yes\" or \"no\".");
950
 
                        ret = -1;
951
 
                        goto out;
952
 
                }
953
 
                free(tlsrequired);
954
 
        }
955
 
 
956
 
        ret = get_property(logopt, root, "authrequired", &authrequired);
957
 
        if (ret != 0) {
958
 
                error(logopt,
959
 
                      MODPREFIX
960
 
                      "Failed read the authrequired property from "
961
 
                      "the configuration file %s.", auth_conf);
962
 
                goto out;
963
 
        }
964
 
 
965
 
        if (!authrequired)
966
 
                auth_required = LDAP_AUTH_NOTREQUIRED;
967
 
        else {
968
 
                if (!strcasecmp(authrequired, "yes"))
969
 
                        auth_required = LDAP_AUTH_REQUIRED;
970
 
                else if (!strcasecmp(authrequired, "no"))
971
 
                        auth_required = LDAP_AUTH_NOTREQUIRED;
972
 
                else if (!strcasecmp(authrequired, "autodetect"))
973
 
                        auth_required = LDAP_AUTH_AUTODETECT;
974
 
                else {
975
 
                        error(logopt,
976
 
                              MODPREFIX
977
 
                              "The authrequired property must have value "
978
 
                              "\"yes\", \"no\" or \"autodetect\".");
979
 
                        ret = -1;
980
 
                        goto out;
981
 
                }
982
 
                free(authrequired);
983
 
        }
984
 
 
985
 
        ret = get_property(logopt, root, "authtype", &authtype);
986
 
        if (ret != 0) {
987
 
                error(logopt,
988
 
                      MODPREFIX
989
 
                      "Failed read the authtype property from the "
990
 
                      "configuration file %s.", auth_conf);
991
 
                goto out;
992
 
        }
993
 
 
994
 
        if (authtype && authtype_requires_creds(authtype)) {
995
 
                ret = get_property(logopt, root, "user",  &user);
996
 
                ret |= get_property(logopt, root, "secret", &secret);
997
 
                if (ret != 0 || (!user || !secret)) {
998
 
                        error(logopt,
999
 
                              MODPREFIX
1000
 
                              "%s authentication type requires a username "
1001
 
                              "and a secret.  Please fix your configuration "
1002
 
                              "in %s.", authtype, auth_conf);
1003
 
                        free(authtype);
1004
 
                        if (user)
1005
 
                                free(user);
1006
 
                        if (secret)
1007
 
                                free(secret);
1008
 
 
1009
 
                        ret = -1;
1010
 
                        goto out;
1011
 
                }
1012
 
        }
1013
 
 
1014
 
        /*
1015
 
         * We allow the admin to specify the principal to use for the
1016
 
         * client.  The default is "autofsclient/hostname@REALM".
1017
 
         */
1018
 
        (void)get_property(logopt, root, "clientprinc", &client_princ);
1019
 
        (void)get_property(logopt, root, "credentialcache", &client_cc);
1020
 
 
1021
 
        ctxt->auth_conf = auth_conf;
1022
 
        ctxt->use_tls = use_tls;
1023
 
        ctxt->tls_required = tls_required;
1024
 
        ctxt->auth_required = auth_required;
1025
 
        ctxt->sasl_mech = authtype;
1026
 
        if (!authtype && (auth_required & LDAP_AUTH_REQUIRED))
1027
 
                ctxt->auth_required |= LDAP_AUTH_AUTODETECT;
1028
 
        ctxt->user = user;
1029
 
        ctxt->secret = secret;
1030
 
        ctxt->client_princ = client_princ;
1031
 
        ctxt->client_cc = client_cc;
1032
 
 
1033
 
        debug(logopt, MODPREFIX
1034
 
              "ldap authentication configured with the following options:");
1035
 
        debug(logopt, MODPREFIX
1036
 
              "use_tls: %u, "
1037
 
              "tls_required: %u, "
1038
 
              "auth_required: %u, "
1039
 
              "sasl_mech: %s",
1040
 
              use_tls, tls_required, auth_required, authtype);
1041
 
        debug(logopt, MODPREFIX
1042
 
              "user: %s, "
1043
 
              "secret: %s, "
1044
 
              "client principal: %s "
1045
 
              "credential cache: %s",
1046
 
              user, secret ? "specified" : "unspecified",
1047
 
              client_princ, client_cc);
1048
 
 
1049
 
out:
1050
 
        xmlFreeDoc(doc);
1051
 
 
1052
 
        if (fallback)
1053
 
                return 0;
1054
 
 
1055
 
        return ret;
1056
 
}
1057
 
#endif
1058
 
 
1059
 
/*
1060
 
 *  Take an input string as specified in the master map, and break it
1061
 
 *  down into a server name and basedn.
1062
 
 */
1063
 
static int parse_server_string(unsigned logopt, const char *url, struct lookup_context *ctxt)
1064
 
{
1065
 
        char buf[MAX_ERR_BUF], *tmp = NULL, proto[9];
1066
 
        const char *ptr, *name;
1067
 
        int l, al_len;
1068
 
 
1069
 
        memset(proto, 0, 9);
1070
 
        ptr = url;
1071
 
 
1072
 
        debug(logopt, MODPREFIX
1073
 
              "Attempting to parse LDAP information from string \"%s\".", ptr);
1074
 
 
1075
 
        ctxt->port = LDAP_PORT;
1076
 
        if (!strncmp(ptr, "ldap:", 5) || !strncmp(ptr, "ldaps:", 6)) {
1077
 
                if (*(ptr + 4) == 's') {
1078
 
                        ctxt->port = LDAPS_PORT;
1079
 
                        memcpy(proto, ptr, 6);
1080
 
                        strcat(proto, "//");
1081
 
                        ptr += 6;
1082
 
                } else {
1083
 
                        memcpy(proto, ptr, 5);
1084
 
                        strcat(proto, "//");
1085
 
                        ptr += 5;
1086
 
                }
1087
 
        }
1088
 
 
1089
 
        if (!strncmp(ptr, "//", 2)) {
1090
 
                const char *s = ptr + 2;
1091
 
                const char *q = NULL;
1092
 
 
1093
 
                /* Isolate the server(s). */
1094
 
                if ((q = strchr(s, '/'))) {
1095
 
                        l = q - s;
1096
 
                        if (*proto) {
1097
 
                                al_len = l + strlen(proto) + 2;
1098
 
                                tmp = malloc(al_len);
1099
 
                        } else {
1100
 
                                al_len = l + 1;
1101
 
                                tmp = malloc(al_len);
1102
 
                        }
1103
 
                        if (!tmp) {
1104
 
                                char *estr;
1105
 
                                estr = strerror_r(errno, buf, sizeof(buf));
1106
 
                                logerr(MODPREFIX "malloc: %s", estr);
1107
 
                                return 0;
1108
 
                        }
1109
 
                        ctxt->server = tmp;
1110
 
                        memset(ctxt->server, 0, al_len);
1111
 
                        if (*proto) {
1112
 
                                strcpy(ctxt->server, proto);
1113
 
                                memcpy(ctxt->server + strlen(proto), s, l);
1114
 
                                strcat(ctxt->server, "/");
1115
 
                        } else
1116
 
                                memcpy(ctxt->server, s, l);
1117
 
                        ptr = q + 1;
1118
 
                } else {
1119
 
                        crit(logopt,
1120
 
                             MODPREFIX "invalid LDAP map syntax %s", ptr);
1121
 
                        return 0;
1122
 
/* TODO: why did I put this here, the parser shouldn't let this by
1123
 
                        l = strlen(ptr);
1124
 
                        tmp = malloc(l + 1);
1125
 
                        if (!tmp) {
1126
 
                                char *estr;
1127
 
                                estr = strerror_r(errno, buf, sizeof(buf));
1128
 
                                crit(logopt, MODPREFIX "malloc: %s", estr);
1129
 
                                return 0;
1130
 
                        }
1131
 
                        ctxt->server = tmp;
1132
 
                        memset(ctxt->server, 0, l + 1);
1133
 
                        memcpy(ctxt->server, s, l);
1134
 
*/
1135
 
                }
1136
 
        } else if (strchr(ptr, ':') != NULL || *ptr == '[') {
1137
 
                const char *q = NULL;
1138
 
 
1139
 
                /* Isolate the server. Include the port spec */
1140
 
                if (*ptr != '[')
1141
 
                        q = strchr(ptr, ':');
1142
 
                else {
1143
 
                        q = ++ptr;
1144
 
                        while (*q == ':' || isxdigit(*q))
1145
 
                                q++;
1146
 
                        if (*q != ']') {
1147
 
                                crit(logopt, MODPREFIX
1148
 
                                     "invalid LDAP map syntax %s", ptr);
1149
 
                                return 0;
1150
 
                        }
1151
 
                        q++;
1152
 
                        if (*q == ':')
1153
 
                                q++;
1154
 
                }
1155
 
 
1156
 
                if (isdigit(*q))
1157
 
                        while (isdigit(*q))
1158
 
                                q++;
1159
 
 
1160
 
                if (*q != ':') {
1161
 
                        crit(logopt,
1162
 
                             MODPREFIX "invalid LDAP map syntax %s", ptr);
1163
 
                        return 0;
1164
 
                }
1165
 
 
1166
 
                l = q - ptr;
1167
 
                if (*proto) {
1168
 
                        al_len = l + strlen(proto) + 2;
1169
 
                        tmp = malloc(al_len);
1170
 
                } else {
1171
 
                        al_len = l + 1;
1172
 
                        tmp = malloc(al_len);
1173
 
                }
1174
 
                /* Isolate the server's name. */
1175
 
                if (!tmp) {
1176
 
                        char *estr;
1177
 
                        estr = strerror_r(errno, buf, sizeof(buf));
1178
 
                        logerr(MODPREFIX "malloc: %s", estr);
1179
 
                        return 0;
1180
 
                }
1181
 
                ctxt->server = tmp;
1182
 
                memset(ctxt->server, 0, al_len);
1183
 
                if (*proto) {
1184
 
                        strcpy(ctxt->server, proto);
1185
 
                        memcpy(ctxt->server + strlen(proto), ptr, l);
1186
 
                        strcat(ctxt->server, "/");
1187
 
                } else
1188
 
                        memcpy(ctxt->server, ptr, l);
1189
 
                ptr += l + 1;
1190
 
        }
1191
 
 
1192
 
        /* TODO: why did I do this - how can the map name "and" base dn be missing? */
1193
 
        if (!ptr)
1194
 
                goto done;
1195
 
 
1196
 
        /*
1197
 
         * For nss support we can have a map name with no
1198
 
         * type or dn info. If present a base dn must have
1199
 
         * at least an "=" and a "," to be at all functional.
1200
 
         * If a dn is given it must be fully specified or
1201
 
         * the later LDAP calls will fail.
1202
 
         */
1203
 
        l = strlen(ptr);
1204
 
        if ((name = strchr(ptr, '='))) {
1205
 
                char *base;
1206
 
 
1207
 
                /*
1208
 
                 * An '=' with no ',' means a mapname has been given so just
1209
 
                 * grab it alone to keep it independent of schema otherwize
1210
 
                 * we expect a full dn.
1211
 
                 */
1212
 
                if (!strchr(ptr, ',')) {
1213
 
                        char *map = strdup(name + 1);
1214
 
                        if (map)
1215
 
                                ctxt->mapname = map;
1216
 
                        else {
1217
 
                                char *estr;
1218
 
                                estr = strerror_r(errno, buf, sizeof(buf));
1219
 
                                logerr(MODPREFIX "strdup: %s", estr);
1220
 
                                if (ctxt->server)
1221
 
                                        free(ctxt->server);
1222
 
                                return 0;
1223
 
                        }
1224
 
                        
1225
 
                } else {
1226
 
                        base = malloc(l + 1);
1227
 
                        if (!base) {
1228
 
                                char *estr;
1229
 
                                estr = strerror_r(errno, buf, sizeof(buf));
1230
 
                                logerr(MODPREFIX "malloc: %s", estr);
1231
 
                                if (ctxt->server)
1232
 
                                        free(ctxt->server);
1233
 
                                return 0;
1234
 
                        }
1235
 
                        ctxt->base = base;
1236
 
                        memset(ctxt->base, 0, l + 1);
1237
 
                        memcpy(ctxt->base, ptr, l);
1238
 
                }
1239
 
        } else {
1240
 
                char *map = malloc(l + 1);
1241
 
                if (!map) {
1242
 
                        char *estr;
1243
 
                        estr = strerror_r(errno, buf, sizeof(buf));
1244
 
                        logerr(MODPREFIX "malloc: %s", estr);
1245
 
                        if (ctxt->server)
1246
 
                                free(ctxt->server);
1247
 
                        return 0;
1248
 
                }
1249
 
                ctxt->mapname = map;
1250
 
                memset(ctxt->mapname, 0, l + 1);
1251
 
                memcpy(map, ptr, l);
1252
 
        }
1253
 
 
1254
 
        if (!ctxt->server && *proto) {
1255
 
                if (!strncmp(proto, "ldaps", 5)) {
1256
 
                        info(logopt, MODPREFIX
1257
 
                             "server must be given to force ldaps, connection "
1258
 
                             "will use LDAP client configured protocol");
1259
 
                }
1260
 
        }
1261
 
done:
1262
 
        if (ctxt->mapname)
1263
 
                debug(logopt, MODPREFIX "mapname %s", ctxt->mapname);
1264
 
        else
1265
 
                debug(logopt, MODPREFIX "server \"%s\", base dn \"%s\"",
1266
 
                        ctxt->server ? ctxt->server : "(default)",
1267
 
                        ctxt->base);
1268
 
 
1269
 
        return 1;
1270
 
}
1271
 
 
1272
 
static void free_context(struct lookup_context *ctxt)
1273
 
{
1274
 
        int ret;
1275
 
 
1276
 
        if (ctxt->schema) {
1277
 
                free(ctxt->schema->map_class);
1278
 
                free(ctxt->schema->map_attr);
1279
 
                free(ctxt->schema->entry_class);
1280
 
                free(ctxt->schema->entry_attr);
1281
 
                free(ctxt->schema->value_attr);
1282
 
                free(ctxt->schema);
1283
 
        }
1284
 
        if (ctxt->auth_conf)
1285
 
                free(ctxt->auth_conf);
1286
 
        if (ctxt->sasl_mech)
1287
 
                free(ctxt->sasl_mech);
1288
 
        if (ctxt->user)
1289
 
                free(ctxt->user);
1290
 
        if (ctxt->secret)
1291
 
                free(ctxt->secret);
1292
 
        if (ctxt->client_princ)
1293
 
                free(ctxt->client_princ);
1294
 
        if (ctxt->client_cc)
1295
 
                free(ctxt->client_cc);
1296
 
        if (ctxt->mapname)
1297
 
                free(ctxt->mapname);
1298
 
        if (ctxt->qdn)
1299
 
                free(ctxt->qdn);
1300
 
        if (ctxt->server)
1301
 
                free(ctxt->server);
1302
 
        if (ctxt->cur_host)
1303
 
                free(ctxt->cur_host);
1304
 
        if (ctxt->base)
1305
 
                free(ctxt->base);
1306
 
        if (ctxt->uris)
1307
 
                defaults_free_uris(ctxt->uris);
1308
 
        ret = pthread_mutex_destroy(&ctxt->uris_mutex);
1309
 
        if (ret)
1310
 
                fatal(ret);
1311
 
        if (ctxt->sdns)
1312
 
                defaults_free_searchdns(ctxt->sdns);
1313
 
        if (ctxt->dclist)
1314
 
                free_dclist(ctxt->dclist);
1315
 
        free(ctxt);
1316
 
 
1317
 
        return;
1318
 
}
1319
 
 
1320
 
static void validate_uris(struct list_head *list)
1321
 
{
1322
 
        struct list_head *next;
1323
 
 
1324
 
        next = list->next;
1325
 
        while (next != list) {
1326
 
                struct ldap_uri *this;
1327
 
 
1328
 
                this = list_entry(next, struct ldap_uri, list);
1329
 
                next = next->next;
1330
 
 
1331
 
                /* At least we get some basic validation */
1332
 
                if (!ldap_is_ldap_url(this->uri)) {
1333
 
                        list_del(&this->list);
1334
 
                        free(this->uri);
1335
 
                        free(this);
1336
 
                }
1337
 
        }
1338
 
 
1339
 
        return;                 
1340
 
}
1341
 
 
1342
 
/*
1343
 
 * This initializes a context (persistent non-global data) for queries to
1344
 
 * this module.  Return zero if we succeed.
1345
 
 */
1346
 
int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **context)
1347
 
{
1348
 
        struct lookup_context *ctxt;
1349
 
        char buf[MAX_ERR_BUF];
1350
 
        int ret;
1351
 
 
1352
 
        *context = NULL;
1353
 
 
1354
 
        /* If we can't build a context, bail. */
1355
 
        ctxt = malloc(sizeof(struct lookup_context));
1356
 
        if (!ctxt) {
1357
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
1358
 
                logerr(MODPREFIX "malloc: %s", estr);
1359
 
                return 1;
1360
 
        }
1361
 
        memset(ctxt, 0, sizeof(struct lookup_context));
1362
 
 
1363
 
        ret = pthread_mutex_init(&ctxt->uris_mutex, NULL);
1364
 
        if (ret) {
1365
 
                error(LOGOPT_ANY, MODPREFIX "failed to init uris mutex");
1366
 
                free(ctxt);
1367
 
                return 1;
1368
 
        }
1369
 
 
1370
 
        /* If a map type isn't explicitly given, parse it like sun entries. */
1371
 
        if (mapfmt == NULL)
1372
 
                mapfmt = MAPFMT_DEFAULT;
1373
 
 
1374
 
        /*
1375
 
         * Parse out the server name and base dn, and fill them
1376
 
         * into the proper places in the lookup context structure.
1377
 
         */
1378
 
        if (!parse_server_string(LOGOPT_NONE, argv[0], ctxt)) {
1379
 
                error(LOGOPT_ANY, MODPREFIX "cannot parse server string");
1380
 
                free_context(ctxt);
1381
 
                return 1;
1382
 
        }
1383
 
 
1384
 
        ctxt->timeout = defaults_get_ldap_timeout();
1385
 
        ctxt->network_timeout = defaults_get_ldap_network_timeout();
1386
 
 
1387
 
        if (!ctxt->server) {
1388
 
                struct list_head *uris = defaults_get_uris();
1389
 
                if (uris) {
1390
 
                        validate_uris(uris);
1391
 
                        if (!list_empty(uris))
1392
 
                                ctxt->uris = uris;
1393
 
                        else {
1394
 
                                error(LOGOPT_ANY,
1395
 
                                      "no valid uris found in config list"
1396
 
                                      ", using default system config");
1397
 
                                free(uris);
1398
 
                        }
1399
 
                }
1400
 
        }
1401
 
 
1402
 
#ifdef WITH_SASL
1403
 
        /*
1404
 
         *  First, check to see if a preferred authentication method was
1405
 
         *  specified by the user.  parse_ldap_config will return error
1406
 
         *  if the permissions on the file were incorrect, or if the
1407
 
         *  specified authentication type is not valid.
1408
 
         */
1409
 
        ret = parse_ldap_config(LOGOPT_NONE, ctxt);
1410
 
        if (ret) {
1411
 
                free_context(ctxt);
1412
 
                return 1;
1413
 
        }
1414
 
 
1415
 
        /* Init the sasl callbacks */
1416
 
        if (!autofs_sasl_client_init(LOGOPT_NONE)) {
1417
 
                error(LOGOPT_ANY, "failed to init sasl client");
1418
 
                free_context(ctxt);
1419
 
                return 1;
1420
 
        }
1421
 
#endif
1422
 
 
1423
 
        /* Open the parser, if we can. */
1424
 
        ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
1425
 
        if (!ctxt->parse) {
1426
 
                free_context(ctxt);
1427
 
                logerr(MODPREFIX "failed to open parse context");
1428
 
                return 1;
1429
 
        }
1430
 
        *context = ctxt;
1431
 
 
1432
 
        return 0;
1433
 
}
1434
 
 
1435
 
int lookup_read_master(struct master *master, time_t age, void *context)
1436
 
{
1437
 
        struct lookup_context *ctxt = (struct lookup_context *) context;
1438
 
        unsigned int timeout = master->default_timeout;
1439
 
        unsigned int logging = master->default_logging;
1440
 
        unsigned int logopt = master->logopt;
1441
 
        int rv, l, count;
1442
 
        char buf[MAX_ERR_BUF];
1443
 
        char parse_buf[PARSE_MAX_BUF];
1444
 
        char *query;
1445
 
        LDAPMessage *result, *e;
1446
 
        char *class, *info, *entry;
1447
 
        char **keyValue = NULL;
1448
 
        char **values = NULL;
1449
 
        char *attrs[3];
1450
 
        int scope = LDAP_SCOPE_SUBTREE;
1451
 
        LDAP *ldap;
1452
 
 
1453
 
        /* Initialize the LDAP context. */
1454
 
        ldap = do_reconnect(logopt, ctxt);
1455
 
        if (!ldap)
1456
 
                return NSS_STATUS_UNAVAIL;
1457
 
 
1458
 
        class = ctxt->schema->entry_class;
1459
 
        entry = ctxt->schema->entry_attr;
1460
 
        info = ctxt->schema->value_attr;
1461
 
 
1462
 
        attrs[0] = entry;
1463
 
        attrs[1] = info;
1464
 
        attrs[2] = NULL;
1465
 
 
1466
 
        l = strlen("(objectclass=)") + strlen(class) + 1;
1467
 
 
1468
 
        query = malloc(l);
1469
 
        if (query == NULL) {
1470
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
1471
 
                logerr(MODPREFIX "malloc: %s", estr);
1472
 
                return NSS_STATUS_UNAVAIL;
1473
 
        }
1474
 
 
1475
 
        if (sprintf(query, "(objectclass=%s)", class) >= l) {
1476
 
                error(logopt, MODPREFIX "error forming query string");
1477
 
                free(query);
1478
 
                return NSS_STATUS_UNAVAIL;
1479
 
        }
1480
 
 
1481
 
        /* Look around. */
1482
 
        debug(logopt,
1483
 
              MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
1484
 
 
1485
 
        rv = ldap_search_s(ldap, ctxt->qdn, scope, query, attrs, 0, &result);
1486
 
 
1487
 
        if ((rv != LDAP_SUCCESS) || !result) {
1488
 
                error(logopt, MODPREFIX "query failed for %s: %s",
1489
 
                      query, ldap_err2string(rv));
1490
 
                unbind_ldap_connection(logging, ldap, ctxt);
1491
 
                free(query);
1492
 
                return NSS_STATUS_NOTFOUND;
1493
 
        }
1494
 
 
1495
 
        e = ldap_first_entry(ldap, result);
1496
 
        if (!e) {
1497
 
                debug(logopt,
1498
 
                      MODPREFIX "query succeeded, no matches for %s",
1499
 
                      query);
1500
 
                ldap_msgfree(result);
1501
 
                unbind_ldap_connection(logging, ldap, ctxt);
1502
 
                free(query);
1503
 
                return NSS_STATUS_NOTFOUND;
1504
 
        } else
1505
 
                debug(logopt, MODPREFIX "examining entries");
1506
 
 
1507
 
        while (e) {
1508
 
                char *key = NULL;
1509
 
                int dec_len, i;
1510
 
 
1511
 
                keyValue = ldap_get_values(ldap, e, entry);
1512
 
 
1513
 
                if (!keyValue || !*keyValue) {
1514
 
                        e = ldap_next_entry(ldap, e);
1515
 
                        continue;
1516
 
                }
1517
 
 
1518
 
                /*
1519
 
                 * By definition keys must be unique within
1520
 
                 * each map entry
1521
 
                 */
1522
 
                count = ldap_count_values(keyValue);
1523
 
                if (strcasecmp(class, "nisObject")) {
1524
 
                        if (count > 1) {
1525
 
                                error(logopt, MODPREFIX
1526
 
                                      "key %s has duplicates - ignoring",
1527
 
                                      *keyValue);
1528
 
                                goto next;
1529
 
                        }
1530
 
                        key = strdup(keyValue[0]);
1531
 
                        if (!key) {
1532
 
                                error(logopt, MODPREFIX
1533
 
                                      "failed to dup map key %s - ignoring",
1534
 
                                      *keyValue);
1535
 
                                goto next;
1536
 
                        }
1537
 
                } else if (count == 1) {
1538
 
                        dec_len = decode_percent_hack(keyValue[0], &key);
1539
 
                        if (dec_len < 0) {
1540
 
                                error(logopt, MODPREFIX
1541
 
                                      "invalid map key %s - ignoring",
1542
 
                                      *keyValue);
1543
 
                                goto next;
1544
 
                        }
1545
 
                } else {
1546
 
                        dec_len = decode_percent_hack(keyValue[0], &key);
1547
 
                        if (dec_len < 0) {
1548
 
                                error(logopt, MODPREFIX
1549
 
                                      "invalid map key %s - ignoring",
1550
 
                                      *keyValue);
1551
 
                                goto next;
1552
 
                        }
1553
 
 
1554
 
                        for (i = 1; i < count; i++) {
1555
 
                                char *k;
1556
 
                                dec_len = decode_percent_hack(keyValue[i], &k);
1557
 
                                if (dec_len < 0) {
1558
 
                                        error(logopt, MODPREFIX
1559
 
                                              "invalid map key %s - ignoring",
1560
 
                                              *keyValue);
1561
 
                                        goto next;
1562
 
                                }
1563
 
                                if (strcmp(key, k)) {
1564
 
                                        error(logopt, MODPREFIX
1565
 
                                              "key entry mismatch %s - ignoring",
1566
 
                                              *keyValue);
1567
 
                                        free(k);
1568
 
                                        goto next;
1569
 
                                }
1570
 
                                free(k);
1571
 
                        }
1572
 
                }
1573
 
 
1574
 
                /*
1575
 
                 * Ignore keys beginning with '+' as plus map
1576
 
                 * inclusion is only valid in file maps.
1577
 
                 */
1578
 
                if (*key == '+') {
1579
 
                        warn(logopt,
1580
 
                             MODPREFIX
1581
 
                             "ignoreing '+' map entry - not in file map");
1582
 
                        goto next;
1583
 
                }
1584
 
 
1585
 
                values = ldap_get_values(ldap, e, info);
1586
 
                if (!values || !*values) {
1587
 
                        debug(logopt,
1588
 
                              MODPREFIX "no %s defined for %s", info, query);
1589
 
                        goto next;
1590
 
                }
1591
 
 
1592
 
                /*
1593
 
                 * We require that there be only one value per key.
1594
 
                 */
1595
 
                count = ldap_count_values(values);
1596
 
                if (count > 1) {
1597
 
                        error(logopt,
1598
 
                              MODPREFIX
1599
 
                              "one value per key allowed in master map");
1600
 
                        ldap_value_free(values);
1601
 
                        goto next;
1602
 
                }
1603
 
 
1604
 
                if (snprintf(parse_buf, sizeof(parse_buf), "%s %s",
1605
 
                             key, *values) >= sizeof(parse_buf)) {
1606
 
                        error(logopt, MODPREFIX "map entry too long");
1607
 
                        ldap_value_free(values);
1608
 
                        goto next;
1609
 
                }
1610
 
                ldap_value_free(values);
1611
 
 
1612
 
                master_parse_entry(parse_buf, timeout, logging, age);
1613
 
next:
1614
 
                ldap_value_free(keyValue);
1615
 
                if (key)
1616
 
                        free(key);
1617
 
                e = ldap_next_entry(ldap, e);
1618
 
        }
1619
 
 
1620
 
        /* Clean up. */
1621
 
        ldap_msgfree(result);
1622
 
        unbind_ldap_connection(logopt, ldap, ctxt);
1623
 
        free(query);
1624
 
 
1625
 
        return NSS_STATUS_SUCCESS;
1626
 
}
1627
 
 
1628
 
static int get_percent_decoded_len(const char *name)
1629
 
{
1630
 
        int escapes = 0;
1631
 
        int escaped = 0;
1632
 
        const char *tmp = name;
1633
 
        int look_for_close = 0;
1634
 
 
1635
 
        while (*tmp) {
1636
 
                if (*tmp == '%') {
1637
 
                        /* assume escapes aren't interpreted inside brackets */
1638
 
                        if (look_for_close) {
1639
 
                                tmp++;
1640
 
                                continue;
1641
 
                        }
1642
 
                        /* check for escaped % */
1643
 
                        if (escaped) {
1644
 
                                tmp++;
1645
 
                                escaped = 0;
1646
 
                                continue;
1647
 
                        }
1648
 
                        escapes++;
1649
 
                        tmp++;
1650
 
                        if (*tmp == '[') {
1651
 
                                escapes++;
1652
 
                                tmp++;
1653
 
                                look_for_close = 1;
1654
 
                        } else
1655
 
                                escaped = 1;
1656
 
                } else if (*tmp == ']' && look_for_close) {
1657
 
                        escaped = 0;
1658
 
                        escapes++;
1659
 
                        tmp++;
1660
 
                        look_for_close = 0;
1661
 
                } else {
1662
 
                        tmp++;
1663
 
                        escaped = 0;
1664
 
                }
1665
 
        }
1666
 
 
1667
 
        assert(strlen(name) > escapes);
1668
 
        return strlen(name) - escapes;
1669
 
}
1670
 
 
1671
 
/*
1672
 
 * Try to catch heap corruption if our logic happens to be incorrect.
1673
 
 */
1674
 
static void validate_string_len(const char *orig, char *start,
1675
 
                                char *end, unsigned int len)
1676
 
{
1677
 
        debug(LOGOPT_NONE, MODPREFIX "string %s encoded as %s", orig, start);
1678
 
        /* make sure we didn't overflow the allocated space */
1679
 
        if (end - start > len + 1) {
1680
 
                crit(LOGOPT_ANY, MODPREFIX "orig %s, len %d", orig, len);
1681
 
                crit(LOGOPT_ANY, MODPREFIX "en/decoded %s, len %d", start,
1682
 
                     end - start);
1683
 
        }
1684
 
        assert(end-start <= len + 1);
1685
 
}
1686
 
 
1687
 
/*
1688
 
 * Deal with encode and decode of % hack.
1689
 
 * Return
1690
 
 * 0 => % hack not present.
1691
 
 * -1 => syntax error or alloc fail.
1692
 
 * 1 transofrmed value returned.
1693
 
 */
1694
 
/*
1695
 
 * Assumptions: %'s must be escaped by %'s.  %'s are not used to escape
1696
 
 * anything else except capital letters (so you can't escape a closing
1697
 
 * bracket, for example).
1698
 
 */
1699
 
static int decode_percent_hack(const char *name, char **key)
1700
 
{
1701
 
        const char *tmp;
1702
 
        char *ptr, *new;
1703
 
        unsigned int len;
1704
 
        int escaped = 0, look_for_close = 0;
1705
 
 
1706
 
        if (!key)
1707
 
                return -1;
1708
 
 
1709
 
        *key = NULL;
1710
 
 
1711
 
        len = get_percent_decoded_len(name);
1712
 
        new = malloc(len + 1);
1713
 
        if (!new)
1714
 
                return -1;
1715
 
 
1716
 
        ptr = new;
1717
 
        tmp = name;
1718
 
        while (*tmp) {
1719
 
                if (*tmp == '%') {
1720
 
                        if (escaped) {
1721
 
                                *ptr++ = *tmp++;
1722
 
                                if (!look_for_close)
1723
 
                                        escaped = 0;
1724
 
                                continue;
1725
 
                        }
1726
 
                        tmp++;
1727
 
                        if (*tmp == '[') {
1728
 
                                tmp++;
1729
 
                                look_for_close = 1;
1730
 
                                escaped = 1;
1731
 
                        } else
1732
 
                                escaped = 1;
1733
 
                } else if (*tmp == ']' && look_for_close) {
1734
 
                        tmp++;
1735
 
                        look_for_close = 0;
1736
 
                } else {
1737
 
                        escaped = 0;
1738
 
                        *ptr++ = *tmp++;
1739
 
                }
1740
 
        }
1741
 
        *ptr = '\0';
1742
 
        *key = new;
1743
 
 
1744
 
        validate_string_len(name, new, ptr, len);
1745
 
        return strlen(new);
1746
 
}
1747
 
 
1748
 
/*
1749
 
 * Calculate the length of a string replacing all capital letters with %letter.
1750
 
 * For example:
1751
 
 * Sale -> %Sale
1752
 
 * SALE -> %S%A%L%E
1753
 
 */
1754
 
static int get_encoded_len_escaping_every_cap(const char *name)
1755
 
{
1756
 
        const char *tmp;
1757
 
        unsigned int escapes = 0; /* number of % escape characters */
1758
 
 
1759
 
        tmp = name;
1760
 
        while (*tmp) {
1761
 
                /* We'll need to escape percents */
1762
 
                if (*tmp == '%' || isupper(*tmp))
1763
 
                        escapes++;
1764
 
                tmp++;
1765
 
        }
1766
 
 
1767
 
        return strlen(name) + escapes;
1768
 
}
1769
 
 
1770
 
/*
1771
 
 * Calculate the length of a string replacing sequences (1 or more) of capital
1772
 
 * letters with %[letters].  For example:
1773
 
 * FOO ->  %[FOO]
1774
 
 * Work -> %[W]ork
1775
 
 * WorksForMe -> %[W]orks%[F]or%[M]e
1776
 
 * aaBBaa -> aa%[BB]aa
1777
 
 */
1778
 
static int get_encoded_len_escaping_sequences(const char *name)
1779
 
{
1780
 
        const char *tmp;
1781
 
        unsigned int escapes = 0;
1782
 
 
1783
 
        tmp = name;
1784
 
        while (*tmp) {
1785
 
                /* escape percents */
1786
 
                if (*tmp == '%')
1787
 
                        escapes++;
1788
 
                else if (isupper(*tmp)) {
1789
 
                        /* start an escape block %[...] */
1790
 
                        escapes += 3;  /* %[] */
1791
 
                        while (*tmp && isupper(*tmp))
1792
 
                                tmp++;
1793
 
                        continue;
1794
 
                }
1795
 
                tmp++;
1796
 
        }
1797
 
 
1798
 
        return strlen(name) + escapes;
1799
 
}
1800
 
 
1801
 
static void encode_individual(const char *name, char *new, unsigned int len)
1802
 
{
1803
 
        const char *tmp;
1804
 
        char *ptr;
1805
 
 
1806
 
        ptr = new;
1807
 
        tmp = name;
1808
 
        while (*tmp) {
1809
 
                if (*tmp == '%' || isupper(*tmp))
1810
 
                        *ptr++ = '%';
1811
 
                *ptr++ = *tmp++;
1812
 
        }
1813
 
        *ptr = '\0';
1814
 
        validate_string_len(name, new, ptr, len);
1815
 
}
1816
 
 
1817
 
static void encode_sequence(const char *name, char *new, unsigned int len)
1818
 
{
1819
 
        const char *tmp;
1820
 
        char *ptr;
1821
 
 
1822
 
        ptr = new;
1823
 
        tmp = name;
1824
 
        while (*tmp) {
1825
 
                if (*tmp == '%') {
1826
 
                        *ptr++ = '%';
1827
 
                        *ptr++ = *tmp++;
1828
 
                } else if (isupper(*tmp)) {
1829
 
                        *ptr++ = '%';
1830
 
                        *ptr++ = '[';
1831
 
                        *ptr++ = *tmp++;
1832
 
 
1833
 
                        while (*tmp && isupper(*tmp)) {
1834
 
                                *ptr++ = *tmp;
1835
 
                                tmp++;
1836
 
                        }
1837
 
                        *ptr++ = ']';
1838
 
                } else
1839
 
                        *ptr++ = *tmp++;
1840
 
        }
1841
 
        *ptr = '\0';
1842
 
        validate_string_len(name, new, ptr, len);
1843
 
}
1844
 
 
1845
 
/*
1846
 
 * use_class:  1 means encode string as %[CAPITALS], 0 means encode as
1847
 
 * %C%A%P%I%T%A%L%S
1848
 
 */
1849
 
static int encode_percent_hack(const char *name, char **key, unsigned int use_class)
1850
 
{
1851
 
        unsigned int len = 0;
1852
 
 
1853
 
        if (!key)
1854
 
                return -1;
1855
 
 
1856
 
        if (use_class)
1857
 
                len = get_encoded_len_escaping_sequences(name);
1858
 
        else
1859
 
                len = get_encoded_len_escaping_every_cap(name);
1860
 
 
1861
 
        /* If there is no escaping to be done, return 0 */
1862
 
        if (len == strlen(name))
1863
 
                return 0;
1864
 
 
1865
 
        *key = malloc(len + 1);
1866
 
        if (!*key)
1867
 
                return -1;
1868
 
 
1869
 
        if (use_class)
1870
 
                encode_sequence(name, *key, len);
1871
 
        else
1872
 
                encode_individual(name, *key, len);
1873
 
 
1874
 
        if (strlen(*key) != len)
1875
 
                crit(LOGOPT_ANY, MODPREFIX "encoded key length mismatch: key "
1876
 
                     "%s len %d strlen %d", *key, len, strlen(*key));
1877
 
 
1878
 
        return strlen(*key);
1879
 
}
1880
 
 
1881
 
static int do_paged_query(struct ldap_search_params *sp, struct lookup_context *ctxt)
1882
 
{
1883
 
        struct autofs_point *ap = sp->ap;
1884
 
        LDAPControl *pageControl=NULL, *controls[2] = { NULL, NULL };
1885
 
        LDAPControl **returnedControls = NULL;
1886
 
        static ber_int_t pageSize = 1000;
1887
 
        static char pagingCriticality = 'T';
1888
 
        int rv, scope = LDAP_SCOPE_SUBTREE;
1889
 
 
1890
 
        if (sp->morePages == TRUE)
1891
 
                goto do_paged;
1892
 
 
1893
 
        rv = ldap_search_s(sp->ldap, ctxt->qdn, scope, sp->query, sp->attrs, 0, &sp->result);
1894
 
        if ((rv != LDAP_SUCCESS) || !sp->result) {
1895
 
                /*
1896
 
                 * Check for Size Limit exceeded and force run through loop
1897
 
                 * and requery using page control.
1898
 
                 */
1899
 
                if (rv == LDAP_SIZELIMIT_EXCEEDED)
1900
 
                        sp->morePages = TRUE;
1901
 
                else {
1902
 
                        debug(ap->logopt,
1903
 
                              MODPREFIX "query failed for %s: %s",
1904
 
                              sp->query, ldap_err2string(rv));
1905
 
                        return rv;
1906
 
                }
1907
 
        }
1908
 
        return rv;
1909
 
 
1910
 
do_paged:
1911
 
        /* we need to use page controls so requery LDAP */
1912
 
        debug(ap->logopt, MODPREFIX "geting page of results");
1913
 
 
1914
 
        rv = ldap_create_page_control(sp->ldap, pageSize, sp->cookie,
1915
 
                                      pagingCriticality, &pageControl);
1916
 
        if (rv != LDAP_SUCCESS) {
1917
 
                warn(ap->logopt, MODPREFIX "failed to create page control");
1918
 
                return rv;
1919
 
        }
1920
 
 
1921
 
        /* Insert the control into a list to be passed to the search. */
1922
 
        controls[0] = pageControl;
1923
 
 
1924
 
        /* Search for entries in the directory using the parmeters. */
1925
 
        rv = ldap_search_ext_s(sp->ldap,
1926
 
                               ctxt->qdn, scope, sp->query, sp->attrs,
1927
 
                               0, controls, NULL, NULL, 0, &sp->result);
1928
 
        if ((rv != LDAP_SUCCESS) && (rv != LDAP_PARTIAL_RESULTS)) {
1929
 
                debug(ap->logopt,
1930
 
                      MODPREFIX "query failed for %s: %s",
1931
 
                      sp->query, ldap_err2string(rv));
1932
 
                ldap_control_free(pageControl);
1933
 
                return rv;
1934
 
        }
1935
 
 
1936
 
        /* Parse the results to retrieve the contols being returned. */
1937
 
        rv = ldap_parse_result(sp->ldap, sp->result,
1938
 
                               NULL, NULL, NULL, NULL,
1939
 
                               &returnedControls, FALSE);
1940
 
        if (sp->cookie != NULL) {
1941
 
                ber_bvfree(sp->cookie);
1942
 
                sp->cookie = NULL;
1943
 
        }
1944
 
 
1945
 
        if (rv != LDAP_SUCCESS) {
1946
 
                debug(ap->logopt,
1947
 
                      MODPREFIX "ldap_parse_result failed with %d", rv);
1948
 
                goto out_free;
1949
 
        }
1950
 
 
1951
 
        /*
1952
 
         * Parse the page control returned to get the cookie and
1953
 
         * determine whether there are more pages.
1954
 
         */
1955
 
        rv = ldap_parse_page_control(sp->ldap,
1956
 
                                     returnedControls, &sp->totalCount,
1957
 
                                     &sp->cookie);
1958
 
        if (sp->cookie && sp->cookie->bv_val && strlen(sp->cookie->bv_val))
1959
 
                sp->morePages = TRUE;
1960
 
        else
1961
 
                sp->morePages = FALSE;
1962
 
 
1963
 
        /* Cleanup the controls used. */
1964
 
        if (returnedControls)
1965
 
                ldap_controls_free(returnedControls);
1966
 
 
1967
 
out_free:
1968
 
        ldap_control_free(pageControl);
1969
 
        return rv;
1970
 
}
1971
 
 
1972
 
static int do_get_entries(struct ldap_search_params *sp, struct map_source *source, struct lookup_context *ctxt)
1973
 
{
1974
 
        struct autofs_point *ap = sp->ap;
1975
 
        struct mapent_cache *mc = source->mc;
1976
 
        char buf[MAX_ERR_BUF];
1977
 
        struct berval **bvKey;
1978
 
        struct berval **bvValues;
1979
 
        LDAPMessage *e;
1980
 
        char *class, *info, *entry;
1981
 
        int rv, ret;
1982
 
        int i, count;
1983
 
 
1984
 
        class = ctxt->schema->entry_class;
1985
 
        entry = ctxt->schema->entry_attr;
1986
 
        info = ctxt->schema->value_attr;
1987
 
 
1988
 
        e = ldap_first_entry(sp->ldap, sp->result);
1989
 
        if (!e) {
1990
 
                debug(ap->logopt,
1991
 
                      MODPREFIX "query succeeded, no matches for %s",
1992
 
                      sp->query);
1993
 
                ret = ldap_parse_result(sp->ldap, sp->result,
1994
 
                                        &rv, NULL, NULL, NULL, NULL, 0);
1995
 
                if (ret == LDAP_SUCCESS)
1996
 
                        return rv;
1997
 
                else
1998
 
                        return LDAP_OPERATIONS_ERROR;
1999
 
        } else
2000
 
                debug(ap->logopt, MODPREFIX "examining entries");
2001
 
 
2002
 
        while (e) {
2003
 
                char *mapent = NULL;
2004
 
                size_t mapent_len = 0;
2005
 
                char *k_val;
2006
 
                ber_len_t k_len;
2007
 
                char *s_key;
2008
 
 
2009
 
                bvKey = ldap_get_values_len(sp->ldap, e, entry);
2010
 
                if (!bvKey || !*bvKey) {
2011
 
                        e = ldap_next_entry(sp->ldap, e);
2012
 
                        if (!e) {
2013
 
                                debug(ap->logopt, MODPREFIX
2014
 
                                      "failed to get next entry for query %s",
2015
 
                                      sp->query);
2016
 
                                ret = ldap_parse_result(sp->ldap,
2017
 
                                                        sp->result, &rv,
2018
 
                                                        NULL, NULL, NULL, NULL, 0);
2019
 
                                if (ret == LDAP_SUCCESS)
2020
 
                                        return rv;
2021
 
                                else
2022
 
                                        return LDAP_OPERATIONS_ERROR;
2023
 
                        }
2024
 
                        continue;
2025
 
                }
2026
 
 
2027
 
                /*
2028
 
                 * By definition keys should be unique within each map entry,
2029
 
                 * but as always there are exceptions.
2030
 
                 */
2031
 
                k_val = NULL;
2032
 
                k_len = 0;
2033
 
 
2034
 
                /*
2035
 
                 * Keys should be unique so, in general, there shouldn't be
2036
 
                 * more than one attribute value. We make an exception for
2037
 
                 * wildcard entries as people may have values for '*' or
2038
 
                 * '/' for compaibility reasons. We use the '/' as the
2039
 
                 * wildcard in LDAP but allow '*' as well to allow for
2040
 
                 * people using older schemas that allow '*' as a key
2041
 
                 * value. Another case where there can be multiple key
2042
 
                 * values is when people have used the "%" hack to specify
2043
 
                 * case matching ctriteria in a case insensitive attribute.
2044
 
                 */
2045
 
                count = ldap_count_values_len(bvKey);
2046
 
                if (count > 1) {
2047
 
                        unsigned int i;
2048
 
 
2049
 
                        /* Check for the "/" and "*" and use as "/" if found */
2050
 
                        for (i = 0; i < count; i++) {
2051
 
                                bvKey[i]->bv_val[bvKey[i]->bv_len] = '\0';
2052
 
 
2053
 
                                /*
2054
 
                                 * If multiple entries are present they could
2055
 
                                 * be the result of people using the "%" hack so
2056
 
                                 * ignore them.
2057
 
                                 */
2058
 
                                if (strchr(bvKey[i]->bv_val, '%'))
2059
 
                                        continue;
2060
 
 
2061
 
                                /* check for wildcard */
2062
 
                                if (bvKey[i]->bv_len == 1 &&
2063
 
                                    (*bvKey[i]->bv_val == '/' ||
2064
 
                                     *bvKey[i]->bv_val == '*')) {
2065
 
                                        /* always use '/' internally */
2066
 
                                        *bvKey[i]->bv_val = '/';
2067
 
                                        k_val = bvKey[i]->bv_val;
2068
 
                                        k_len = 1;
2069
 
                                        break;
2070
 
                                }
2071
 
 
2072
 
                                /*
2073
 
                                 * We have a result from LDAP so this is a
2074
 
                                 * valid entry. Set the result to the LDAP
2075
 
                                 * key that isn't a wildcard and doesn't have
2076
 
                                 * any "%" hack values present. This should be
2077
 
                                 * the case insensitive match string for the
2078
 
                                 * nis schema, the default value.
2079
 
                                 */
2080
 
                                k_val = bvKey[i]->bv_val;
2081
 
                                k_len = bvKey[i]->bv_len;
2082
 
 
2083
 
                                break;
2084
 
                        }
2085
 
 
2086
 
                        if (!k_val) {
2087
 
                                error(ap->logopt,
2088
 
                                      MODPREFIX "invalid entry %.*s - ignoring",
2089
 
                                      bvKey[0]->bv_len, bvKey[0]->bv_val);
2090
 
                                goto next;
2091
 
                        }
2092
 
                } else {
2093
 
                        /* Check for the "*" and use as "/" if found */
2094
 
                        if (bvKey[0]->bv_len == 1 && *bvKey[0]->bv_val == '*')
2095
 
                                *bvKey[0]->bv_val = '/';
2096
 
                        k_val = bvKey[0]->bv_val;
2097
 
                        k_len = bvKey[0]->bv_len;
2098
 
                }
2099
 
 
2100
 
                /*
2101
 
                 * Ignore keys beginning with '+' as plus map
2102
 
                 * inclusion is only valid in file maps.
2103
 
                 */
2104
 
                if (*k_val == '+') {
2105
 
                        warn(ap->logopt,
2106
 
                             MODPREFIX
2107
 
                             "ignoreing '+' map entry - not in file map");
2108
 
                        goto next;
2109
 
                }
2110
 
 
2111
 
                bvValues = ldap_get_values_len(sp->ldap, e, info);
2112
 
                if (!bvValues || !*bvValues) {
2113
 
                        debug(ap->logopt,
2114
 
                              MODPREFIX "no %s defined for %s", info, sp->query);
2115
 
                        goto next;
2116
 
                }
2117
 
 
2118
 
                /*
2119
 
                 * We expect that there will be only one value because
2120
 
                 * questions of order of returned value entries but we
2121
 
                 * accumulate values to support simple multi-mounts.
2122
 
                 *
2123
 
                 * If the ordering of a mount spec with another containing
2124
 
                 * options or the actual order of entries causes problems
2125
 
                 * it won't be supported. Perhaps someone can instruct us
2126
 
                 * how to force an ordering.
2127
 
                 */
2128
 
                count = ldap_count_values_len(bvValues);
2129
 
                for (i = 0; i < count; i++) {
2130
 
                        char *v_val = bvValues[i]->bv_val;
2131
 
                        ber_len_t v_len = bvValues[i]->bv_len;
2132
 
 
2133
 
                        if (!mapent) {
2134
 
                                mapent = malloc(v_len + 1);
2135
 
                                if (!mapent) {
2136
 
                                        char *estr;
2137
 
                                        estr = strerror_r(errno, buf, sizeof(buf));
2138
 
                                        logerr(MODPREFIX "malloc: %s", estr);
2139
 
                                        ldap_value_free_len(bvValues);
2140
 
                                        goto next;
2141
 
                                }
2142
 
                                strncpy(mapent, v_val, v_len);
2143
 
                                mapent[v_len] = '\0';
2144
 
                                mapent_len = v_len;
2145
 
                        } else {
2146
 
                                int new_size = mapent_len + v_len + 2;
2147
 
                                char *new_me;
2148
 
                                new_me = realloc(mapent, new_size);
2149
 
                                if (new_me) {
2150
 
                                        mapent = new_me;
2151
 
                                        strcat(mapent, " ");
2152
 
                                        strncat(mapent, v_val, v_len);
2153
 
                                        mapent[new_size] = '\0';
2154
 
                                        mapent_len = new_size;
2155
 
                                } else {
2156
 
                                        char *estr;
2157
 
                                        estr = strerror_r(errno, buf, sizeof(buf));
2158
 
                                        logerr(MODPREFIX "realloc: %s", estr);
2159
 
                                }
2160
 
                        }
2161
 
                }
2162
 
                ldap_value_free_len(bvValues);
2163
 
 
2164
 
                if (*k_val == '/' && k_len == 1) {
2165
 
                        if (ap->type == LKP_DIRECT)
2166
 
                                goto next;
2167
 
                        *k_val = '*';
2168
 
                }
2169
 
 
2170
 
                if (strcasecmp(class, "nisObject")) {
2171
 
                        s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
2172
 
                        if (!s_key)
2173
 
                                goto next;
2174
 
                } else {
2175
 
                        char *dec_key;
2176
 
                        int dec_len = decode_percent_hack(k_val, &dec_key);
2177
 
 
2178
 
                        if (dec_len < 0) {
2179
 
                                crit(ap->logopt,
2180
 
                                     "could not use percent hack to decode key %s",
2181
 
                                     k_val);
2182
 
                                goto next;
2183
 
                        }
2184
 
 
2185
 
                        if (dec_len == 0)
2186
 
                                s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
2187
 
                        else {
2188
 
                                s_key = sanitize_path(dec_key, dec_len, ap->type, ap->logopt);
2189
 
                                free(dec_key);
2190
 
                        }
2191
 
                        if (!s_key)
2192
 
                                goto next;
2193
 
                }
2194
 
 
2195
 
                cache_writelock(mc);
2196
 
                cache_update(mc, source, s_key, mapent, sp->age);
2197
 
                cache_unlock(mc);
2198
 
 
2199
 
                free(s_key);
2200
 
next:
2201
 
                if (mapent) {
2202
 
                        free(mapent);
2203
 
                        mapent = NULL;
2204
 
                }
2205
 
 
2206
 
                ldap_value_free_len(bvKey);
2207
 
                e = ldap_next_entry(sp->ldap, e);
2208
 
                if (!e) {
2209
 
                        debug(ap->logopt, MODPREFIX
2210
 
                              "failed to get next entry for query %s",
2211
 
                              sp->query);
2212
 
                        ret = ldap_parse_result(sp->ldap,
2213
 
                                                sp->result, &rv,
2214
 
                                                NULL, NULL, NULL, NULL, 0);
2215
 
                        if (ret == LDAP_SUCCESS)
2216
 
                                return rv;
2217
 
                        else
2218
 
                                return LDAP_OPERATIONS_ERROR;
2219
 
                }
2220
 
        }
2221
 
 
2222
 
        return LDAP_SUCCESS;
2223
 
}
2224
 
 
2225
 
 
2226
 
static int read_one_map(struct autofs_point *ap,
2227
 
                        struct lookup_context *ctxt,
2228
 
                        time_t age, int *result_ldap)
2229
 
{
2230
 
        struct map_source *source;
2231
 
        struct ldap_search_params sp;
2232
 
        char buf[MAX_ERR_BUF];
2233
 
        char *class, *info, *entry;
2234
 
        char *attrs[3];
2235
 
        int rv, l;
2236
 
 
2237
 
        source = ap->entry->current;
2238
 
        ap->entry->current = NULL;
2239
 
        master_source_current_signal(ap->entry);
2240
 
 
2241
 
        /*
2242
 
         * If we don't need to create directories then there's no use
2243
 
         * reading the map. We always need to read the whole map for
2244
 
         * direct mounts in order to mount the triggers.
2245
 
         */
2246
 
        if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
2247
 
                return NSS_STATUS_SUCCESS;
2248
 
 
2249
 
        sp.ap = ap;
2250
 
        sp.age = age;
2251
 
 
2252
 
        /* Initialize the LDAP context. */
2253
 
        sp.ldap = do_reconnect(ap->logopt, ctxt);
2254
 
        if (!sp.ldap)
2255
 
                return NSS_STATUS_UNAVAIL;
2256
 
 
2257
 
        class = ctxt->schema->entry_class;
2258
 
        entry = ctxt->schema->entry_attr;
2259
 
        info = ctxt->schema->value_attr;
2260
 
 
2261
 
        attrs[0] = entry;
2262
 
        attrs[1] = info;
2263
 
        attrs[2] = NULL;
2264
 
        sp.attrs = attrs;
2265
 
 
2266
 
        /* Build a query string. */
2267
 
        l = strlen("(objectclass=)") + strlen(class) + 1;
2268
 
 
2269
 
        sp.query = malloc(l);
2270
 
        if (sp.query == NULL) {
2271
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
2272
 
                logerr(MODPREFIX "malloc: %s", estr);
2273
 
                return NSS_STATUS_UNAVAIL;
2274
 
        }
2275
 
 
2276
 
        if (sprintf(sp.query, "(objectclass=%s)", class) >= l) {
2277
 
                error(ap->logopt, MODPREFIX "error forming query string");
2278
 
                free(sp.query);
2279
 
                return NSS_STATUS_UNAVAIL;
2280
 
        }
2281
 
 
2282
 
        /* Look around. */
2283
 
        debug(ap->logopt,
2284
 
              MODPREFIX "searching for \"%s\" under \"%s\"", sp.query, ctxt->qdn);
2285
 
 
2286
 
        sp.cookie = NULL;
2287
 
        sp.morePages = FALSE;
2288
 
        sp.totalCount = 0;
2289
 
        sp.result = NULL;
2290
 
 
2291
 
        do {
2292
 
                rv = do_paged_query(&sp, ctxt);
2293
 
                if (rv == LDAP_SIZELIMIT_EXCEEDED)
2294
 
                {
2295
 
                        debug(ap->logopt, MODPREFIX "result size exceed");
2296
 
                        if (sp.result)
2297
 
                                ldap_msgfree(sp.result);
2298
 
 
2299
 
                        continue;
2300
 
                }
2301
 
 
2302
 
                if (rv != LDAP_SUCCESS || !sp.result) {
2303
 
                        unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
2304
 
                        *result_ldap = rv;
2305
 
                        free(sp.query);
2306
 
                        return NSS_STATUS_UNAVAIL;
2307
 
                }
2308
 
 
2309
 
                rv = do_get_entries(&sp, source, ctxt);
2310
 
                if (rv != LDAP_SUCCESS) {
2311
 
                        ldap_msgfree(sp.result);
2312
 
                        unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
2313
 
                        *result_ldap = rv;
2314
 
                        free(sp.query);
2315
 
                        return NSS_STATUS_NOTFOUND;
2316
 
                }
2317
 
                ldap_msgfree(sp.result);
2318
 
        } while (sp.morePages == TRUE);
2319
 
 
2320
 
        debug(ap->logopt, MODPREFIX "done updating map");
2321
 
 
2322
 
        unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
2323
 
 
2324
 
        source->age = age;
2325
 
        free(sp.query);
2326
 
 
2327
 
        return NSS_STATUS_SUCCESS;
2328
 
}
2329
 
 
2330
 
int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
2331
 
{
2332
 
        struct lookup_context *ctxt = (struct lookup_context *) context;
2333
 
        int rv = LDAP_SUCCESS;
2334
 
        int ret, cur_state;
2335
 
 
2336
 
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
2337
 
        ret = read_one_map(ap, ctxt, age, &rv);
2338
 
        if (ret != NSS_STATUS_SUCCESS) {
2339
 
                switch (rv) {
2340
 
                case LDAP_SIZELIMIT_EXCEEDED:
2341
 
                        crit(ap->logopt, MODPREFIX
2342
 
                             "Unable to download entire LDAP map for: %s",
2343
 
                             ap->path);
2344
 
                case LDAP_UNWILLING_TO_PERFORM:
2345
 
                        pthread_setcancelstate(cur_state, NULL);
2346
 
                        return NSS_STATUS_UNAVAIL;
2347
 
                }
2348
 
        }
2349
 
        pthread_setcancelstate(cur_state, NULL);
2350
 
 
2351
 
        return ret;
2352
 
}
2353
 
 
2354
 
static int lookup_one(struct autofs_point *ap,
2355
 
                char *qKey, int qKey_len, struct lookup_context *ctxt)
2356
 
{
2357
 
        struct map_source *source;
2358
 
        struct mapent_cache *mc;
2359
 
        int rv, i, l, ql, count;
2360
 
        char buf[MAX_ERR_BUF];
2361
 
        time_t age = time(NULL);
2362
 
        char *query;
2363
 
        LDAPMessage *result, *e;
2364
 
        char *class, *info, *entry;
2365
 
        char *enc_key1, *enc_key2;
2366
 
        int enc_len1 = 0, enc_len2 = 0;
2367
 
        struct berval **bvKey;
2368
 
        struct berval **bvValues;
2369
 
        char *attrs[3];
2370
 
        int scope = LDAP_SCOPE_SUBTREE;
2371
 
        LDAP *ldap;
2372
 
        struct mapent *we;
2373
 
        unsigned int wild = 0;
2374
 
        int ret = CHE_MISSING;
2375
 
 
2376
 
        source = ap->entry->current;
2377
 
        ap->entry->current = NULL;
2378
 
        master_source_current_signal(ap->entry);
2379
 
 
2380
 
        mc = source->mc;
2381
 
 
2382
 
        if (ctxt == NULL) {
2383
 
                crit(ap->logopt, MODPREFIX "context was NULL");
2384
 
                return CHE_FAIL;
2385
 
        }
2386
 
 
2387
 
        /* Initialize the LDAP context. */
2388
 
        ldap = do_reconnect(ap->logopt, ctxt);
2389
 
        if (!ldap)
2390
 
                return CHE_UNAVAIL;
2391
 
 
2392
 
        class = ctxt->schema->entry_class;
2393
 
        entry = ctxt->schema->entry_attr;
2394
 
        info = ctxt->schema->value_attr;
2395
 
 
2396
 
        attrs[0] = entry;
2397
 
        attrs[1] = info;
2398
 
        attrs[2] = NULL;
2399
 
 
2400
 
        if (*qKey == '*' && qKey_len == 1)
2401
 
                *qKey = '/';
2402
 
        else if (!strcasecmp(class, "nisObject")) {
2403
 
                enc_len1 = encode_percent_hack(qKey, &enc_key1, 0);
2404
 
                if (enc_len1 < 0) {
2405
 
                        crit(ap->logopt,
2406
 
                             "could not use percent hack encode key %s",
2407
 
                             qKey);
2408
 
                        return CHE_FAIL;
2409
 
                }
2410
 
                if (enc_len1 != 0) {
2411
 
                        enc_len2 = encode_percent_hack(qKey, &enc_key2, 1);
2412
 
                        if (enc_len2 < 0) {
2413
 
                                crit(ap->logopt,
2414
 
                                     "could not use percent hack encode key %s",
2415
 
                                     qKey);
2416
 
                                return CHE_FAIL;
2417
 
                        }
2418
 
                }
2419
 
        }
2420
 
 
2421
 
        /* Build a query string. */
2422
 
        l = strlen(class) + 3*strlen(entry) + strlen(qKey) + 35;
2423
 
        if (enc_len1)
2424
 
                l += 2*strlen(entry) + enc_len1 + enc_len2 + 6;
2425
 
 
2426
 
        query = malloc(l);
2427
 
        if (query == NULL) {
2428
 
                char *estr = strerror_r(errno, buf, sizeof(buf));
2429
 
                crit(ap->logopt, MODPREFIX "malloc: %s", estr);
2430
 
                if (enc_len1) {
2431
 
                        free(enc_key1);
2432
 
                        free(enc_key2);
2433
 
                }
2434
 
                free(query);
2435
 
                return CHE_FAIL;
2436
 
        }
2437
 
 
2438
 
        /*
2439
 
         * Look for an entry in class under ctxt-base
2440
 
         * whose entry is equal to qKey.
2441
 
         */
2442
 
        if (!enc_len1) {
2443
 
                ql = sprintf(query,
2444
 
                        "(&(objectclass=%s)(|(%s=%s)(%s=/)(%s=\\2A)))",
2445
 
                        class, entry, qKey, entry, entry);
2446
 
        } else {
2447
 
                if (enc_len2) {
2448
 
                        ql = sprintf(query,
2449
 
                                "(&(objectclass=%s)"
2450
 
                                "(|(%s=%s)(%s=%s)(%s=%s)(%s=/)(%s=\\2A)))",
2451
 
                                class, entry, qKey,
2452
 
                                entry, enc_key1, entry, enc_key2, entry, entry);
2453
 
                        free(enc_key1);
2454
 
                        free(enc_key2);
2455
 
                } else {
2456
 
                        ql = sprintf(query,
2457
 
                                "(&(objectclass=%s)"
2458
 
                                "(|(%s=%s)(%s=%s)(%s=/)(%s=\\2A)))",
2459
 
                                class, entry, qKey, entry, enc_key1, entry, entry);
2460
 
                        free(enc_key1);
2461
 
                }
2462
 
        }
2463
 
        if (ql >= l) {
2464
 
                error(ap->logopt,
2465
 
                      MODPREFIX "error forming query string");
2466
 
                free(query);
2467
 
                return CHE_FAIL;
2468
 
        }
2469
 
 
2470
 
        debug(ap->logopt,
2471
 
              MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
2472
 
 
2473
 
        rv = ldap_search_s(ldap, ctxt->qdn, scope, query, attrs, 0, &result);
2474
 
 
2475
 
        if ((rv != LDAP_SUCCESS) || !result) {
2476
 
                crit(ap->logopt, MODPREFIX "query failed for %s", query);
2477
 
                unbind_ldap_connection(ap->logopt, ldap, ctxt);
2478
 
                free(query);
2479
 
                return CHE_FAIL;
2480
 
        }
2481
 
 
2482
 
        debug(ap->logopt,
2483
 
              MODPREFIX "getting first entry for %s=\"%s\"", entry, qKey);
2484
 
 
2485
 
        e = ldap_first_entry(ldap, result);
2486
 
        if (!e) {
2487
 
                debug(ap->logopt,
2488
 
                     MODPREFIX "got answer, but no entry for %s", query);
2489
 
                ldap_msgfree(result);
2490
 
                unbind_ldap_connection(ap->logopt, ldap, ctxt);
2491
 
                free(query);
2492
 
                return CHE_MISSING;
2493
 
        }
2494
 
 
2495
 
        while (e) {
2496
 
                char *mapent = NULL;
2497
 
                size_t mapent_len = 0;
2498
 
                char *k_val;
2499
 
                ber_len_t k_len;
2500
 
                char *s_key;
2501
 
 
2502
 
                bvKey = ldap_get_values_len(ldap, e, entry);
2503
 
                if (!bvKey || !*bvKey) {
2504
 
                        e = ldap_next_entry(ldap, e);
2505
 
                        continue;
2506
 
                }
2507
 
 
2508
 
                /*
2509
 
                 * By definition keys should be unique within each map entry,
2510
 
                 * but as always there are exceptions.
2511
 
                 */
2512
 
                k_val = NULL;
2513
 
                k_len = 0;
2514
 
 
2515
 
                /*
2516
 
                 * Keys must be unique so, in general, there shouldn't be
2517
 
                 * more than one attribute value. We make an exception for
2518
 
                 * wildcard entries as people may have values for '*' or
2519
 
                 * '/' for compaibility reasons. We use the '/' as the
2520
 
                 * wildcard in LDAP but allow '*' as well to allow for
2521
 
                 * people using older schemas that allow '*' as a key
2522
 
                 * value. Another case where there can be multiple key
2523
 
                 * values is when people have used the "%" hack to specify
2524
 
                 * case matching ctriteria in a caase insensitive attribute.
2525
 
                 */
2526
 
                count = ldap_count_values_len(bvKey);
2527
 
                if (count > 1) {
2528
 
                        unsigned int i;
2529
 
 
2530
 
                        /* Check for the "/" and "*" and use as "/" if found */
2531
 
                        for (i = 0; i < count; i++) {
2532
 
                                bvKey[i]->bv_val[bvKey[i]->bv_len] = '\0';
2533
 
 
2534
 
                                /*
2535
 
                                 * If multiple entries are present they could
2536
 
                                 * be the result of people using the "%" hack so
2537
 
                                 * ignore them.
2538
 
                                 */
2539
 
                                if (strchr(bvKey[i]->bv_val, '%'))
2540
 
                                        continue;
2541
 
 
2542
 
                                /* check for wildcard */
2543
 
                                if (bvKey[i]->bv_len == 1 &&
2544
 
                                    (*bvKey[i]->bv_val == '/' ||
2545
 
                                     *bvKey[i]->bv_val == '*')) {
2546
 
                                        /* always use '/' internally */
2547
 
                                        *bvKey[i]->bv_val = '/';
2548
 
                                        k_val = bvKey[i]->bv_val;
2549
 
                                        k_len = 1;
2550
 
                                        break;
2551
 
                                }
2552
 
 
2553
 
                                /*
2554
 
                                 * The key was matched by LDAP so this is a
2555
 
                                 * valid entry. Set the result key to the
2556
 
                                 * lookup key to provide the mixed case
2557
 
                                 * matching provided by the "%" hack.
2558
 
                                 */
2559
 
                                k_val = qKey;
2560
 
                                k_len = strlen(qKey);
2561
 
 
2562
 
                                break;
2563
 
                        }
2564
 
 
2565
 
                        if (!k_val) {
2566
 
                                error(ap->logopt,
2567
 
                                        MODPREFIX "no valid key found for %.*s",
2568
 
                                        qKey_len, qKey);
2569
 
                                ret = CHE_FAIL;
2570
 
                                goto next;
2571
 
                        }
2572
 
                } else {
2573
 
                        /* Check for the "*" and use as "/" if found */
2574
 
                        if (bvKey[0]->bv_len == 1 && *bvKey[0]->bv_val == '*')
2575
 
                                *bvKey[0]->bv_val = '/';
2576
 
                        k_val = bvKey[0]->bv_val;
2577
 
                        k_len = bvKey[0]->bv_len;
2578
 
                }
2579
 
 
2580
 
                debug(ap->logopt, MODPREFIX "examining first entry");
2581
 
 
2582
 
                bvValues = ldap_get_values_len(ldap, e, info);
2583
 
                if (!bvValues || !*bvValues) {
2584
 
                        debug(ap->logopt,
2585
 
                              MODPREFIX "no %s defined for %s", info, query);
2586
 
                        goto next;
2587
 
                }
2588
 
 
2589
 
                count = ldap_count_values_len(bvValues);
2590
 
                for (i = 0; i < count; i++) {
2591
 
                        char *v_val = bvValues[i]->bv_val;
2592
 
                        ber_len_t v_len = bvValues[i]->bv_len;
2593
 
 
2594
 
                        if (!mapent) {
2595
 
                                mapent = malloc(v_len + 1);
2596
 
                                if (!mapent) {
2597
 
                                        char *estr;
2598
 
                                        estr = strerror_r(errno, buf, sizeof(buf));
2599
 
                                        logerr(MODPREFIX "malloc: %s", estr);
2600
 
                                        ldap_value_free_len(bvValues);
2601
 
                                        goto next;
2602
 
                                }
2603
 
                                strncpy(mapent, v_val, v_len);
2604
 
                                mapent[v_len] = '\0';
2605
 
                                mapent_len = v_len;
2606
 
                        } else {
2607
 
                                int new_size = mapent_len + v_len + 2;
2608
 
                                char *new_me;
2609
 
                                new_me = realloc(mapent, new_size);
2610
 
                                if (new_me) {
2611
 
                                        mapent = new_me;
2612
 
                                        strcat(mapent, " ");
2613
 
                                        strncat(mapent, v_val, v_len);
2614
 
                                        mapent[new_size] = '\0';
2615
 
                                        mapent_len = new_size;
2616
 
                                } else {
2617
 
                                        char *estr;
2618
 
                                        estr = strerror_r(errno, buf, sizeof(buf));
2619
 
                                        logerr(MODPREFIX "realloc: %s", estr);
2620
 
                                }
2621
 
                        }
2622
 
                }
2623
 
                ldap_value_free_len(bvValues);
2624
 
 
2625
 
                if (*k_val == '/' && k_len == 1) {
2626
 
                        if (ap->type == LKP_DIRECT)
2627
 
                                goto next;
2628
 
                        wild = 1;
2629
 
                        cache_writelock(mc);
2630
 
                        cache_update(mc, source, "*", mapent, age);
2631
 
                        cache_unlock(mc);
2632
 
                        goto next;
2633
 
                }
2634
 
 
2635
 
                if (strcasecmp(class, "nisObject")) {
2636
 
                        s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
2637
 
                        if (!s_key)
2638
 
                                goto next;
2639
 
                } else {
2640
 
                        char *dec_key;
2641
 
                        int dec_len = decode_percent_hack(k_val, &dec_key);
2642
 
 
2643
 
                        if (dec_len < 0) {
2644
 
                                crit(ap->logopt,
2645
 
                                     "could not use percent hack to decode key %s",
2646
 
                                     k_val);
2647
 
                                goto next;
2648
 
                        }
2649
 
 
2650
 
                        if (dec_len == 0)
2651
 
                                s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
2652
 
                        else {
2653
 
                                s_key = sanitize_path(dec_key, dec_len, ap->type, ap->logopt);
2654
 
                                free(dec_key);
2655
 
                        }
2656
 
                        if (!s_key)
2657
 
                                goto next;
2658
 
                }
2659
 
 
2660
 
                cache_writelock(mc);
2661
 
                ret = cache_update(mc, source, s_key, mapent, age);
2662
 
                cache_unlock(mc);
2663
 
 
2664
 
                free(s_key);
2665
 
next:
2666
 
                if (mapent) {
2667
 
                        free(mapent);
2668
 
                        mapent = NULL;
2669
 
                }
2670
 
 
2671
 
                ldap_value_free_len(bvKey);
2672
 
                e = ldap_next_entry(ldap, e);
2673
 
        }
2674
 
 
2675
 
        ldap_msgfree(result);
2676
 
        unbind_ldap_connection(ap->logopt, ldap, ctxt);
2677
 
 
2678
 
        /* Failed to find wild entry, update cache if needed */
2679
 
        pthread_cleanup_push(cache_lock_cleanup, mc);
2680
 
        cache_writelock(mc);
2681
 
        we = cache_lookup_distinct(mc, "*");
2682
 
        if (we) {
2683
 
                /* Wildcard entry existed and is now gone */
2684
 
                if (we->source == source && !wild) {
2685
 
                        cache_delete(mc, "*");
2686
 
                        source->stale = 1;
2687
 
                }
2688
 
        } else {
2689
 
                /* Wildcard not in map but now is */
2690
 
                if (wild)
2691
 
                        source->stale = 1;
2692
 
        }
2693
 
        /* Not found in the map but found in the cache */
2694
 
        if (ret == CHE_MISSING) {
2695
 
                struct mapent *exists = cache_lookup_distinct(mc, qKey);
2696
 
                if (exists && exists->source == source) {
2697
 
                        if (exists->mapent) {
2698
 
                                free(exists->mapent);
2699
 
                                exists->mapent = NULL;
2700
 
                                source->stale = 1;
2701
 
                                exists->status = 0;
2702
 
                        }
2703
 
                }
2704
 
        }
2705
 
        pthread_cleanup_pop(1);
2706
 
        free(query);
2707
 
 
2708
 
        return ret;
2709
 
}
2710
 
 
2711
 
static int check_map_indirect(struct autofs_point *ap,
2712
 
                              char *key, int key_len,
2713
 
                              struct lookup_context *ctxt)
2714
 
{
2715
 
        struct map_source *source;
2716
 
        struct mapent_cache *mc;
2717
 
        struct mapent *me;
2718
 
        time_t now = time(NULL);
2719
 
        time_t t_last_read;
2720
 
        int ret, cur_state;
2721
 
 
2722
 
        source = ap->entry->current;
2723
 
        ap->entry->current = NULL;
2724
 
        master_source_current_signal(ap->entry);
2725
 
 
2726
 
        mc = source->mc;
2727
 
 
2728
 
        master_source_current_wait(ap->entry);
2729
 
        ap->entry->current = source;
2730
 
 
2731
 
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
2732
 
        ret = lookup_one(ap, key, key_len, ctxt);
2733
 
        if (ret == CHE_FAIL) {
2734
 
                pthread_setcancelstate(cur_state, NULL);
2735
 
                return NSS_STATUS_NOTFOUND;
2736
 
        } else if (ret == CHE_UNAVAIL) {
2737
 
                /*
2738
 
                 * If the server is down and the entry exists in the cache
2739
 
                 * and belongs to this map return success and use the entry.
2740
 
                 */
2741
 
                struct mapent *exists = cache_lookup(mc, key);
2742
 
                if (exists && exists->source == source) {
2743
 
                        pthread_setcancelstate(cur_state, NULL);
2744
 
                        return NSS_STATUS_SUCCESS;
2745
 
                }
2746
 
 
2747
 
                warn(ap->logopt,
2748
 
                     MODPREFIX "lookup for %s failed: connection failed", key);
2749
 
 
2750
 
                return NSS_STATUS_UNAVAIL;
2751
 
        }
2752
 
        pthread_setcancelstate(cur_state, NULL);
2753
 
 
2754
 
        /*
2755
 
         * Check for map change and update as needed for
2756
 
         * following cache lookup.
2757
 
         */
2758
 
        cache_readlock(mc);
2759
 
        t_last_read = ap->exp_runfreq + 1;
2760
 
        me = cache_lookup_first(mc);
2761
 
        while (me) {
2762
 
                if (me->source == source) {
2763
 
                        t_last_read = now - me->age;
2764
 
                        break;
2765
 
                }
2766
 
                me = cache_lookup_next(mc, me);
2767
 
        }
2768
 
        cache_unlock(mc);
2769
 
 
2770
 
        if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED)
2771
 
                source->stale = 1;
2772
 
 
2773
 
        cache_readlock(mc);
2774
 
        me = cache_lookup_distinct(mc, "*");
2775
 
        if (ret == CHE_MISSING && (!me || me->source != source)) {
2776
 
                cache_unlock(mc);
2777
 
                return NSS_STATUS_NOTFOUND;
2778
 
        }
2779
 
        cache_unlock(mc);
2780
 
 
2781
 
        return NSS_STATUS_SUCCESS;
2782
 
}
2783
 
 
2784
 
int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
2785
 
{
2786
 
        struct lookup_context *ctxt = (struct lookup_context *) context;
2787
 
        struct map_source *source;
2788
 
        struct mapent_cache *mc;
2789
 
        struct mapent *me;
2790
 
        char key[KEY_MAX_LEN + 1];
2791
 
        int key_len;
2792
 
        char *mapent = NULL;
2793
 
        char mapent_buf[MAPENT_MAX_LEN + 1];
2794
 
        int status = 0;
2795
 
        int ret = 1;
2796
 
 
2797
 
        source = ap->entry->current;
2798
 
        ap->entry->current = NULL;
2799
 
        master_source_current_signal(ap->entry);
2800
 
 
2801
 
        mc = source->mc;
2802
 
 
2803
 
        debug(ap->logopt, MODPREFIX "looking up %s", name);
2804
 
 
2805
 
        key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
2806
 
        if (key_len > KEY_MAX_LEN)
2807
 
                return NSS_STATUS_NOTFOUND;
2808
 
 
2809
 
        /* Check if we recorded a mount fail for this key anywhere */
2810
 
        me = lookup_source_mapent(ap, key, LKP_DISTINCT);
2811
 
        if (me) {
2812
 
                if (me->status >= time(NULL)) {
2813
 
                        cache_unlock(me->mc);
2814
 
                        return NSS_STATUS_NOTFOUND;
2815
 
                }
2816
 
 
2817
 
                /* Negative timeout expired for non-existent entry. */
2818
 
                if (!me->mapent)
2819
 
                        cache_delete(me->mc, key);
2820
 
 
2821
 
                cache_unlock(me->mc);
2822
 
        }
2823
 
 
2824
 
        /*
2825
 
         * We can't check the direct mount map as if it's not in
2826
 
         * the map cache already we never get a mount lookup, so
2827
 
         * we never know about it.
2828
 
         */
2829
 
        if (ap->type == LKP_INDIRECT && *key != '/') {
2830
 
                char *lkp_key;
2831
 
 
2832
 
                cache_readlock(mc);
2833
 
                me = cache_lookup_distinct(mc, key);
2834
 
                if (me && me->multi)
2835
 
                        lkp_key = strdup(me->multi->key);
2836
 
                else
2837
 
                        lkp_key = strdup(key);
2838
 
                cache_unlock(mc);
2839
 
 
2840
 
                if (!lkp_key)
2841
 
                        return NSS_STATUS_UNKNOWN;
2842
 
 
2843
 
                master_source_current_wait(ap->entry);
2844
 
                ap->entry->current = source;
2845
 
 
2846
 
                status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
2847
 
                free(lkp_key);
2848
 
                if (status)
2849
 
                        return status;
2850
 
        }
2851
 
 
2852
 
        cache_readlock(mc);
2853
 
        me = cache_lookup(mc, key);
2854
 
        /* Stale mapent => check for entry in alternate source or wildcard */
2855
 
        if (me && !me->mapent) {
2856
 
                while ((me = cache_lookup_key_next(me)))
2857
 
                        if (me->source == source)
2858
 
                                break;
2859
 
                if (!me)
2860
 
                        me = cache_lookup_distinct(mc, "*");
2861
 
        }
2862
 
        if (me && (me->source == source || *me->key == '/')) {
2863
 
                strcpy(mapent_buf, me->mapent);
2864
 
                mapent = mapent_buf;
2865
 
        }
2866
 
        cache_unlock(mc);
2867
 
 
2868
 
        if (!mapent)
2869
 
                return NSS_STATUS_TRYAGAIN;
2870
 
 
2871
 
        master_source_current_wait(ap->entry);
2872
 
        ap->entry->current = source;
2873
 
 
2874
 
        debug(ap->logopt, MODPREFIX "%s -> %s", key, mapent);
2875
 
        ret = ctxt->parse->parse_mount(ap, key, key_len,
2876
 
                                       mapent, ctxt->parse->context);
2877
 
        if (ret) {
2878
 
                time_t now = time(NULL);
2879
 
                int rv = CHE_OK;
2880
 
 
2881
 
                /* Record the the mount fail in the cache */
2882
 
                cache_writelock(mc);
2883
 
                me = cache_lookup_distinct(mc, key);
2884
 
                if (!me)
2885
 
                        rv = cache_update(mc, source, key, NULL, now);
2886
 
                if (rv != CHE_FAIL) {
2887
 
                        me = cache_lookup_distinct(mc, key);
2888
 
                        me->status = now + ap->negative_timeout;
2889
 
                }
2890
 
                cache_unlock(mc);
2891
 
                return NSS_STATUS_TRYAGAIN;
2892
 
        }
2893
 
 
2894
 
        return NSS_STATUS_SUCCESS;
2895
 
}
2896
 
 
2897
 
/*
2898
 
 * This destroys a context for queries to this module.  It releases the parser
2899
 
 * structure (unloading the module) and frees the memory used by the context.
2900
 
 */
2901
 
int lookup_done(void *context)
2902
 
{
2903
 
        struct lookup_context *ctxt = (struct lookup_context *) context;
2904
 
        int rv = close_parse(ctxt->parse);
2905
 
#ifdef WITH_SASL
2906
 
        autofs_sasl_dispose(ctxt);
2907
 
        autofs_sasl_done();
2908
 
#endif
2909
 
        free_context(ctxt);
2910
 
        return rv;
2911
 
}