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

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-wildcard-map-entry-match.patch/daemon/lookup.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
 
 *   
3
 
 *  lookup.c - API layer to implement nsswitch semantics for map reading
4
 
 *              and mount lookups.
5
 
 *
6
 
 *   Copyright 2006 Ian Kent <raven@themaw.net>
7
 
 *
8
 
 *   This program is free software; you can redistribute it and/or modify
9
 
 *   it under the terms of the GNU General Public License as published by
10
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
11
 
 *   USA; either version 2 of the License, or (at your option) any later
12
 
 *   version.
13
 
 *   
14
 
 *   This program is distributed in the hope that it will be useful,
15
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
 *   GNU General Public License for more details.
18
 
 *
19
 
 * ----------------------------------------------------------------------- */
20
 
 
21
 
#include <stdlib.h>
22
 
#include <stdio.h>
23
 
#include <string.h>
24
 
#include <sys/stat.h>
25
 
#include "automount.h"
26
 
#include "nsswitch.h"
27
 
 
28
 
static int check_nss_result(struct nss_source *this, enum nsswitch_status result)
29
 
{
30
 
        enum nsswitch_status status;
31
 
        struct nss_action a;
32
 
 
33
 
        /* Check if we have negated actions */
34
 
        for (status = 0; status < NSS_STATUS_MAX; status++) {
35
 
                a = this->action[status];
36
 
                if (a.action == NSS_ACTION_UNKNOWN)
37
 
                        continue;
38
 
 
39
 
                if (a.negated && result != status) {
40
 
                        if (a.action == NSS_ACTION_RETURN) {
41
 
                                if (result == NSS_STATUS_SUCCESS)
42
 
                                        return 1;
43
 
                                else
44
 
                                        return 0;
45
 
                        }
46
 
                }
47
 
        }
48
 
 
49
 
        a = this->action[result];
50
 
 
51
 
        /* Check if we have other actions for this status */
52
 
        switch (result) {
53
 
        case NSS_STATUS_SUCCESS:
54
 
                if (a.action == NSS_ACTION_CONTINUE)
55
 
                        break;
56
 
                return 1;
57
 
 
58
 
        case NSS_STATUS_NOTFOUND:
59
 
        case NSS_STATUS_UNAVAIL:
60
 
        case NSS_STATUS_TRYAGAIN:
61
 
                if (a.action == NSS_ACTION_RETURN) {
62
 
                        return 0;
63
 
                }
64
 
                break;
65
 
 
66
 
        default:
67
 
                break;
68
 
        }
69
 
 
70
 
        return -1;
71
 
}
72
 
 
73
 
static void nsslist_cleanup(void *arg)
74
 
{
75
 
        struct list_head *nsslist = (struct list_head *) arg;
76
 
        if (!list_empty(nsslist))
77
 
                free_sources(nsslist);
78
 
        return;
79
 
}
80
 
 
81
 
static int do_read_master(struct master *master, char *type, time_t age)
82
 
{
83
 
        struct lookup_mod *lookup;
84
 
        const char *argv[2];
85
 
        int argc;
86
 
        int status;
87
 
 
88
 
        argc = 1;
89
 
        argv[0] = master->name;
90
 
        argv[1] = NULL;
91
 
 
92
 
        lookup = open_lookup(type, "", NULL, argc, argv);
93
 
        if (!lookup)
94
 
                return NSS_STATUS_UNAVAIL;
95
 
 
96
 
        status = lookup->lookup_read_master(master, age, lookup->context);
97
 
 
98
 
        close_lookup(lookup);
99
 
 
100
 
        return status;
101
 
}
102
 
 
103
 
static int read_master_map(struct master *master, char *type, time_t age)
104
 
{
105
 
        unsigned int logopt = master->logopt;
106
 
        char *path, *save_name;
107
 
        int result;
108
 
 
109
 
        if (strcasecmp(type, "files")) {
110
 
                return do_read_master(master, type, age);
111
 
        }
112
 
 
113
 
        /* 
114
 
         * This is a special case as we need to append the
115
 
         * normal location to the map name.
116
 
         * note: It's invalid to specify a relative path.
117
 
         */
118
 
 
119
 
        if (strchr(master->name, '/')) {
120
 
                error(logopt, "relative path invalid in files map name");
121
 
                return NSS_STATUS_NOTFOUND;
122
 
        }
123
 
 
124
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(master->name) + 2);
125
 
        if (!path)
126
 
                return NSS_STATUS_UNKNOWN;
127
 
 
128
 
        strcpy(path, AUTOFS_MAP_DIR);
129
 
        strcat(path, "/");
130
 
        strcat(path, master->name);
131
 
 
132
 
        save_name = master->name;
133
 
        master->name = path;
134
 
 
135
 
        result = do_read_master(master, type, age);
136
 
 
137
 
        master->name = save_name;
138
 
        free(path);
139
 
 
140
 
        return result;
141
 
}
142
 
 
143
 
int lookup_nss_read_master(struct master *master, time_t age)
144
 
{
145
 
        unsigned int logopt = master->logopt;
146
 
        struct list_head nsslist;
147
 
        struct list_head *head, *p;
148
 
        int result = NSS_STATUS_UNKNOWN;
149
 
 
150
 
        /* If it starts with a '/' it has to be a file or LDAP map */
151
 
        if (*master->name == '/') {
152
 
                if (*(master->name + 1) == '/') {
153
 
                        debug(logopt, "reading master ldap %s", master->name);
154
 
                        result = do_read_master(master, "ldap", age);
155
 
                } else {
156
 
                        debug(logopt, "reading master file %s", master->name);
157
 
                        result = do_read_master(master, "file", age);
158
 
                }
159
 
 
160
 
                if (result == NSS_STATUS_UNAVAIL)
161
 
                        master->read_fail = 1;
162
 
 
163
 
                return !result;
164
 
        } else {
165
 
                char *name = master->name;
166
 
                char *tmp;
167
 
 
168
 
                /* Old style name specification will remain I think. */
169
 
                tmp = strchr(name, ':');
170
 
                if (tmp) {
171
 
                        char source[10];
172
 
 
173
 
                        memset(source, 0, 10);
174
 
                        if (!strncmp(name, "file:", 5) ||
175
 
                            !strncmp(name, "yp:", 3) ||
176
 
                            !strncmp(name, "nis:", 4) ||
177
 
                            !strncmp(name, "nisplus:", 8) ||
178
 
                            !strncmp(name, "ldap:", 5) ||
179
 
                            !strncmp(name, "ldaps:", 6)) {
180
 
                                strncpy(source, name, tmp - name);
181
 
 
182
 
                                /*
183
 
                                 * If it's an ldap map leave the source in the
184
 
                                 * name so the lookup module can work out if
185
 
                                 * ldaps has been requested.
186
 
                                 */
187
 
                                if (strncmp(name, "ldap", 4)) {
188
 
                                        master->name = tmp + 1;
189
 
                                        debug(logopt, "reading master %s %s",
190
 
                                              source, master->name);
191
 
                                } else {
192
 
                                        master->name = name;
193
 
                                        debug(logopt, "reading master %s %s",
194
 
                                              source, tmp + 1);
195
 
                                }
196
 
 
197
 
                                result = do_read_master(master, source, age);
198
 
                                master->name = name;
199
 
 
200
 
                                if (result == NSS_STATUS_UNAVAIL)
201
 
                                        master->read_fail = 1;
202
 
 
203
 
                                return !result;
204
 
                        }
205
 
                }
206
 
        }
207
 
 
208
 
        INIT_LIST_HEAD(&nsslist);
209
 
 
210
 
        result = nsswitch_parse(&nsslist);
211
 
        if (result) {
212
 
                if (!list_empty(&nsslist))
213
 
                        free_sources(&nsslist);
214
 
                error(logopt, "can't to read name service switch config.");
215
 
                return 0;
216
 
        }
217
 
 
218
 
        /* First one gets it */
219
 
        head = &nsslist;
220
 
        list_for_each(p, head) {
221
 
                struct nss_source *this;
222
 
                int status;
223
 
 
224
 
                this = list_entry(p, struct nss_source, list);
225
 
 
226
 
                debug(logopt,
227
 
                      "reading master %s %s", this->source, master->name);
228
 
 
229
 
                result = read_master_map(master, this->source, age);
230
 
 
231
 
                /*
232
 
                 * If the name of the master map hasn't been explicitly
233
 
                 * configured and we're not reading an included master map
234
 
                 * then we're using auto.master as the default. Many setups
235
 
                 * also use auto_master as the default master map so we
236
 
                 * check for this map when auto.master isn't found.
237
 
                 */
238
 
                if (result != NSS_STATUS_SUCCESS &&
239
 
                    !master->depth && !defaults_master_set()) {
240
 
                        char *tmp = strchr(master->name, '.');
241
 
                        if (tmp) {
242
 
                                debug(logopt,
243
 
                                      "%s not found, replacing '.' with '_'",
244
 
                                       master->name);
245
 
                                *tmp = '_';
246
 
                                result = read_master_map(master, this->source, age);
247
 
                                if (result != NSS_STATUS_SUCCESS)
248
 
                                        *tmp = '.';
249
 
                        }
250
 
                }
251
 
 
252
 
                if (result == NSS_STATUS_UNKNOWN) {
253
 
                        debug(logopt, "no map - continuing to next source");
254
 
                        continue;
255
 
                }
256
 
 
257
 
                if (result == NSS_STATUS_UNAVAIL)
258
 
                        master->read_fail = 1;
259
 
 
260
 
                status = check_nss_result(this, result);
261
 
                if (status >= 0) {
262
 
                        free_sources(&nsslist);
263
 
                        return status;
264
 
                }
265
 
        }
266
 
 
267
 
        if (!list_empty(&nsslist))
268
 
                free_sources(&nsslist);
269
 
 
270
 
        return !result;
271
 
}
272
 
 
273
 
static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t age)
274
 
{
275
 
        struct lookup_mod *lookup;
276
 
        int status;
277
 
 
278
 
        lookup = open_lookup(map->type, "", map->format, map->argc, map->argv);
279
 
        if (!lookup) {
280
 
                debug(ap->logopt, "lookup module %s failed", map->type);
281
 
                return NSS_STATUS_UNAVAIL;
282
 
        }
283
 
 
284
 
        master_source_writelock(ap->entry);
285
 
        if (map->lookup)
286
 
                close_lookup(map->lookup);
287
 
        map->lookup = lookup;
288
 
        master_source_unlock(ap->entry);
289
 
 
290
 
        if (!map->stale)
291
 
                return NSS_STATUS_SUCCESS;
292
 
 
293
 
        master_source_current_wait(ap->entry);
294
 
        ap->entry->current = map;
295
 
 
296
 
        status = lookup->lookup_read_map(ap, age, lookup->context);
297
 
 
298
 
        map->stale = 0;
299
 
 
300
 
        /*
301
 
         * For maps that don't support enumeration return success
302
 
         * and do whatever we must to have autofs function with an
303
 
         * empty map entry cache.
304
 
         *
305
 
         * For indirect maps that use the browse option, when the
306
 
         * server is unavailable continue as best we can with
307
 
         * whatever we have in the cache, if anything.
308
 
         */
309
 
        if (status == NSS_STATUS_UNKNOWN ||
310
 
           (ap->type == LKP_INDIRECT && status == NSS_STATUS_UNAVAIL))
311
 
                return NSS_STATUS_SUCCESS;
312
 
 
313
 
        return status;
314
 
}
315
 
 
316
 
static int read_file_source_instance(struct autofs_point *ap, struct map_source *map, time_t age)
317
 
{
318
 
        struct map_source *instance;
319
 
        char src_file[] = "file";
320
 
        char src_prog[] = "program";
321
 
        struct stat st;
322
 
        char *type, *format;
323
 
 
324
 
        if (stat(map->argv[0], &st) == -1) {
325
 
                warn(ap->logopt, "file map %s not found", map->argv[0]);
326
 
                return NSS_STATUS_NOTFOUND;
327
 
        }
328
 
 
329
 
        if (!S_ISREG(st.st_mode))
330
 
                return NSS_STATUS_NOTFOUND;
331
 
 
332
 
        if (st.st_mode & __S_IEXEC)
333
 
                type = src_prog;
334
 
        else
335
 
                type = src_file;
336
 
 
337
 
        format = map->format;
338
 
 
339
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
340
 
        if (!instance) {
341
 
                int argc = map->argc;
342
 
                const char **argv = map->argv;
343
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
344
 
                if (!instance)
345
 
                        return NSS_STATUS_UNAVAIL;
346
 
                instance->recurse = map->recurse;
347
 
                instance->depth = map->depth;
348
 
        }
349
 
        instance->stale = map->stale;
350
 
 
351
 
        return do_read_map(ap, instance, age);
352
 
}
353
 
 
354
 
static int read_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, time_t age)
355
 
{
356
 
        struct map_source *instance;
357
 
        const char *format;
358
 
 
359
 
        format = map->format;
360
 
 
361
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
362
 
        if (!instance) {
363
 
                int argc = map->argc;
364
 
                const char **argv = map->argv;
365
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
366
 
                if (!instance)
367
 
                        return NSS_STATUS_UNAVAIL;
368
 
                instance->recurse = map->recurse;
369
 
                instance->depth = map->depth;
370
 
        }
371
 
        instance->stale = map->stale;
372
 
 
373
 
        return do_read_map(ap, instance, age);
374
 
}
375
 
 
376
 
static void argv_cleanup(void *arg)
377
 
{
378
 
        struct map_source *tmap = (struct map_source *) arg;
379
 
        /* path is freed in free_argv */
380
 
        free_argv(tmap->argc, tmap->argv);
381
 
        return;
382
 
}
383
 
 
384
 
static enum nsswitch_status read_map_source(struct nss_source *this,
385
 
                struct autofs_point *ap, struct map_source *map, time_t age)
386
 
{
387
 
        enum nsswitch_status result;
388
 
        struct map_source tmap;
389
 
        char *path;
390
 
 
391
 
        if (strcasecmp(this->source, "files")) {
392
 
                return read_source_instance(ap, map, this->source, age);
393
 
        }
394
 
 
395
 
        /* 
396
 
         * autofs built-in map for nsswitch "files" is "file".
397
 
         * This is a special case as we need to append the
398
 
         * normal location to the map name.
399
 
         * note: It's invalid to specify a relative path.
400
 
         */
401
 
 
402
 
        if (strchr(map->argv[0], '/')) {
403
 
                error(ap->logopt, "relative path invalid in files map name");
404
 
                return NSS_STATUS_NOTFOUND;
405
 
        }
406
 
 
407
 
        this->source[4] = '\0';
408
 
        tmap.type = this->source;
409
 
        tmap.format = map->format;
410
 
        tmap.lookup = map->lookup;
411
 
        tmap.mc = map->mc;
412
 
        tmap.instance = map->instance;
413
 
        tmap.recurse = map->recurse;
414
 
        tmap.depth = map->depth;
415
 
        tmap.stale = map->stale;
416
 
        tmap.argc = 0;
417
 
        tmap.argv = NULL;
418
 
 
419
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(map->argv[0]) + 2);
420
 
        if (!path)
421
 
                return NSS_STATUS_UNKNOWN;
422
 
 
423
 
        strcpy(path, AUTOFS_MAP_DIR);
424
 
        strcat(path, "/");
425
 
        strcat(path, map->argv[0]);
426
 
 
427
 
        if (map->argc >= 1) {
428
 
                tmap.argc = map->argc;
429
 
                tmap.argv = copy_argv(map->argc, map->argv);
430
 
                if (!tmap.argv) {
431
 
                        error(ap->logopt, "failed to copy args");
432
 
                        free(path);
433
 
                        return NSS_STATUS_UNKNOWN;
434
 
                }
435
 
                if (tmap.argv[0])
436
 
                        free((char *) tmap.argv[0]);
437
 
                tmap.argv[0] = path;
438
 
        } else {
439
 
                error(ap->logopt, "invalid arguments for autofs_point");
440
 
                free(path);
441
 
                return NSS_STATUS_UNKNOWN;
442
 
        }
443
 
 
444
 
        pthread_cleanup_push(argv_cleanup, &tmap);
445
 
        result = read_file_source_instance(ap, &tmap, age);
446
 
        pthread_cleanup_pop(1);
447
 
 
448
 
        map->instance = tmap.instance;
449
 
 
450
 
        return result;
451
 
}
452
 
 
453
 
int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age)
454
 
{
455
 
        struct master_mapent *entry = ap->entry;
456
 
        struct list_head nsslist;
457
 
        struct list_head *head, *p;
458
 
        struct nss_source *this;
459
 
        struct map_source *map;
460
 
        enum nsswitch_status status;
461
 
        unsigned int at_least_one = 0;
462
 
        int result = 0;
463
 
 
464
 
        /*
465
 
         * For each map source (ie. each entry for the mount
466
 
         * point in the master map) do the nss lookup to
467
 
         * locate the map and read it.
468
 
         */
469
 
        if (source)
470
 
                map = source;
471
 
        else
472
 
                map = entry->maps;
473
 
        while (map) {
474
 
                /* Is map source up to date or no longer valid */
475
 
                if (!map->stale || entry->age > map->age) {
476
 
                        map = map->next;
477
 
                        continue;
478
 
                }
479
 
 
480
 
                if (map->type) {
481
 
                        if (!strncmp(map->type, "multi", 5))
482
 
                                debug(ap->logopt, "reading multi map");
483
 
                        else
484
 
                                debug(ap->logopt,
485
 
                                      "reading map %s %s",
486
 
                                       map->type, map->argv[0]);
487
 
                        result = do_read_map(ap, map, age);
488
 
                        map = map->next;
489
 
                        continue;
490
 
                }
491
 
 
492
 
                /* If it starts with a '/' it has to be a file or LDAP map */
493
 
                if (map->argv && *map->argv[0] == '/') {
494
 
                        if (*(map->argv[0] + 1) == '/') {
495
 
                                char *tmp = strdup("ldap");
496
 
                                if (!tmp) {
497
 
                                        map = map->next;
498
 
                                        continue;
499
 
                                }
500
 
                                map->type = tmp;
501
 
                                debug(ap->logopt,
502
 
                                      "reading map %s %s", tmp, map->argv[0]);
503
 
                                result = do_read_map(ap, map, age);
504
 
                        } else {
505
 
                                debug(ap->logopt,
506
 
                                      "reading map file %s", map->argv[0]);
507
 
                                result = read_file_source_instance(ap, map, age);
508
 
                        }
509
 
                        map = map->next;
510
 
                        continue;
511
 
                }
512
 
 
513
 
                INIT_LIST_HEAD(&nsslist);
514
 
 
515
 
                pthread_cleanup_push(nsslist_cleanup, &nsslist);
516
 
                status = nsswitch_parse(&nsslist);
517
 
                pthread_cleanup_pop(0);
518
 
                if (status) {
519
 
                        error(ap->logopt,
520
 
                              "can't to read name service switch config.");
521
 
                        result = 1;
522
 
                        break;
523
 
                }
524
 
 
525
 
                pthread_cleanup_push(nsslist_cleanup, &nsslist);
526
 
                head = &nsslist;
527
 
                list_for_each(p, head) {
528
 
                        this = list_entry(p, struct nss_source, list);
529
 
 
530
 
                        debug(ap->logopt,
531
 
                              "reading map %s %s", this->source, map->argv[0]);
532
 
 
533
 
                        result = read_map_source(this, ap, map, age);
534
 
                        if (result == NSS_STATUS_UNKNOWN)
535
 
                                continue;
536
 
 
537
 
                        /* Don't try to update the map cache if it's unavailable */
538
 
                        if (result == NSS_STATUS_UNAVAIL)
539
 
                                map->stale = 0;
540
 
 
541
 
                        if (result == NSS_STATUS_SUCCESS) {
542
 
                                at_least_one = 1;
543
 
                                result = NSS_STATUS_TRYAGAIN;
544
 
                        }
545
 
 
546
 
                        status = check_nss_result(this, result);
547
 
                        if (status >= 0) {
548
 
                                map = NULL;
549
 
                                break;
550
 
                        }
551
 
 
552
 
                        result = NSS_STATUS_SUCCESS;
553
 
                }
554
 
                pthread_cleanup_pop(1);
555
 
 
556
 
                if (!map)
557
 
                        break;
558
 
 
559
 
                map = map->next;
560
 
        }
561
 
 
562
 
        if (!result || at_least_one)
563
 
                return 1;
564
 
 
565
 
        return 0;
566
 
}
567
 
 
568
 
int lookup_ghost(struct autofs_point *ap, const char *root)
569
 
{
570
 
        struct master_mapent *entry = ap->entry;
571
 
        struct map_source *map;
572
 
        struct mapent_cache *mc;
573
 
        struct mapent *me;
574
 
        char buf[MAX_ERR_BUF];
575
 
        struct stat st;
576
 
        char *fullpath;
577
 
        int ret;
578
 
 
579
 
        if (!strcmp(ap->path, "/-"))
580
 
                return LKP_FAIL | LKP_DIRECT;
581
 
 
582
 
        if (!(ap->flags & MOUNT_FLAG_GHOST))
583
 
                return LKP_INDIRECT;
584
 
 
585
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
586
 
        master_source_readlock(entry);
587
 
        map = entry->maps;
588
 
        while (map) {
589
 
                /*
590
 
                 * Only consider map sources that have been read since 
591
 
                 * the map entry was last updated.
592
 
                 */
593
 
                if (entry->age > map->age) {
594
 
                        map = map->next;
595
 
                        continue;
596
 
                }
597
 
 
598
 
                mc = map->mc;
599
 
                pthread_cleanup_push(cache_lock_cleanup, mc);
600
 
                cache_readlock(mc);
601
 
                me = cache_enumerate(mc, NULL);
602
 
                while (me) {
603
 
                        if (*me->key == '*')
604
 
                                goto next;
605
 
 
606
 
                        if (*me->key == '/') {
607
 
                                /* It's a busy multi-mount - leave till next time */
608
 
                                if (list_empty(&me->multi_list))
609
 
                                        error(ap->logopt,
610
 
                                              "invalid key %s", me->key);
611
 
                                goto next;
612
 
                        }
613
 
 
614
 
                        fullpath = malloc(strlen(me->key) + strlen(root) + 3);
615
 
                        if (!fullpath) {
616
 
                                warn(ap->logopt, "failed to allocate full path");
617
 
                                goto next;
618
 
                        }
619
 
                        sprintf(fullpath, "%s/%s", root, me->key);
620
 
 
621
 
                        ret = stat(fullpath, &st);
622
 
                        if (ret == -1 && errno != ENOENT) {
623
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
624
 
                                warn(ap->logopt, "stat error %s", estr);
625
 
                                free(fullpath);
626
 
                                goto next;
627
 
                        }
628
 
 
629
 
                        ret = mkdir_path(fullpath, 0555);
630
 
                        if (ret < 0 && errno != EEXIST) {
631
 
                                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
632
 
                                warn(ap->logopt,
633
 
                                     "mkdir_path %s failed: %s", fullpath, estr);
634
 
                                free(fullpath);
635
 
                                goto next;
636
 
                        }
637
 
 
638
 
                        if (stat(fullpath, &st) != -1) {
639
 
                                me->dev = st.st_dev;
640
 
                                me->ino = st.st_ino;
641
 
                        }
642
 
 
643
 
                        free(fullpath);
644
 
next:
645
 
                        me = cache_enumerate(mc, me);
646
 
                }
647
 
                pthread_cleanup_pop(1);
648
 
                map = map->next;
649
 
        }
650
 
        pthread_cleanup_pop(1);
651
 
 
652
 
        return LKP_INDIRECT;
653
 
}
654
 
 
655
 
int do_lookup_mount(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
656
 
{
657
 
        struct lookup_mod *lookup;
658
 
        int status;
659
 
 
660
 
        if (!map->lookup) {
661
 
                lookup = open_lookup(map->type, "",
662
 
                                     map->format, map->argc, map->argv);
663
 
                if (!lookup) {
664
 
                        debug(ap->logopt,
665
 
                              "lookup module %s failed", map->type);
666
 
                        return NSS_STATUS_UNAVAIL;
667
 
                }
668
 
                map->lookup = lookup;
669
 
        }
670
 
 
671
 
        lookup = map->lookup;
672
 
 
673
 
        master_source_current_wait(ap->entry);
674
 
        ap->entry->current = map;
675
 
 
676
 
        status = lookup->lookup_mount(ap, name, name_len, lookup->context);
677
 
 
678
 
        return status;
679
 
}
680
 
 
681
 
static int lookup_name_file_source_instance(struct autofs_point *ap, struct map_source *map, const char *name, int name_len)
682
 
{
683
 
        struct map_source *instance;
684
 
        char src_file[] = "file";
685
 
        char src_prog[] = "program";
686
 
        time_t age = time(NULL);
687
 
        struct stat st;
688
 
        char *type, *format;
689
 
 
690
 
        if (stat(map->argv[0], &st) == -1) {
691
 
                warn(ap->logopt, "file map not found");
692
 
                return NSS_STATUS_NOTFOUND;
693
 
        }
694
 
 
695
 
        if (!S_ISREG(st.st_mode))
696
 
                return NSS_STATUS_NOTFOUND;
697
 
 
698
 
        if (st.st_mode & __S_IEXEC)
699
 
                type = src_prog;
700
 
        else
701
 
                type = src_file;
702
 
 
703
 
        format = map->format;
704
 
 
705
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
706
 
        if (!instance) {
707
 
                int argc = map->argc;
708
 
                const char **argv = map->argv;
709
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
710
 
                if (!instance)
711
 
                        return NSS_STATUS_NOTFOUND;
712
 
                instance->recurse = map->recurse;
713
 
                instance->depth = map->depth;
714
 
        }
715
 
 
716
 
        return do_lookup_mount(ap, instance, name, name_len);
717
 
}
718
 
 
719
 
static int lookup_name_source_instance(struct autofs_point *ap, struct map_source *map, const char *type, const char *name, int name_len)
720
 
{
721
 
        struct map_source *instance;
722
 
        const char *format;
723
 
        time_t age = time(NULL);
724
 
 
725
 
        format = map->format;
726
 
 
727
 
        instance = master_find_source_instance(map, type, format, 0, NULL);
728
 
        if (!instance) {
729
 
                int argc = map->argc;
730
 
                const char **argv = map->argv;
731
 
                instance = master_add_source_instance(map, type, format, age, argc, argv);
732
 
                if (!instance)
733
 
                        return NSS_STATUS_NOTFOUND;
734
 
                instance->recurse = map->recurse;
735
 
                instance->depth = map->depth;
736
 
        }
737
 
 
738
 
        return do_lookup_mount(ap, instance, name, name_len);
739
 
}
740
 
 
741
 
static enum nsswitch_status lookup_map_name(struct nss_source *this,
742
 
                        struct autofs_point *ap, struct map_source *map,
743
 
                        const char *name, int name_len)
744
 
{
745
 
        enum nsswitch_status result;
746
 
        struct map_source tmap;
747
 
        char *path;
748
 
 
749
 
        if (strcasecmp(this->source, "files"))
750
 
                return lookup_name_source_instance(ap, map,
751
 
                                        this->source, name, name_len);
752
 
 
753
 
        /* 
754
 
         * autofs build-in map for nsswitch "files" is "file".
755
 
         * This is a special case as we need to append the
756
 
         * normal location to the map name.
757
 
         * note: we consider it invalid to specify a relative
758
 
         *       path.
759
 
         */
760
 
        if (strchr(map->argv[0], '/')) {
761
 
                error(ap->logopt, "relative path invalid in files map name");
762
 
                return NSS_STATUS_NOTFOUND;
763
 
        }
764
 
 
765
 
        this->source[4] = '\0';
766
 
        tmap.type = this->source;
767
 
        tmap.format = map->format;
768
 
        tmap.mc = map->mc;
769
 
        tmap.instance = map->instance;
770
 
        tmap.recurse = map->recurse;
771
 
        tmap.depth = map->depth;
772
 
        tmap.argc = 0;
773
 
        tmap.argv = NULL;
774
 
 
775
 
        path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(map->argv[0]) + 2);
776
 
        if (!path)
777
 
                return NSS_STATUS_UNKNOWN;
778
 
 
779
 
        strcpy(path, AUTOFS_MAP_DIR);
780
 
        strcat(path, "/");
781
 
        strcat(path, map->argv[0]);
782
 
 
783
 
        if (map->argc >= 1) {
784
 
                tmap.argc = map->argc;
785
 
                tmap.argv = copy_argv(map->argc, map->argv);
786
 
                if (!tmap.argv) {
787
 
                        error(ap->logopt, "failed to copy args");
788
 
                        free(path);
789
 
                        return NSS_STATUS_UNKNOWN;
790
 
                }
791
 
                if (tmap.argv[0])
792
 
                        free((char *) tmap.argv[0]);
793
 
                tmap.argv[0] = path;
794
 
        } else {
795
 
                error(ap->logopt, "invalid arguments for autofs_point");
796
 
                free(path);
797
 
                return NSS_STATUS_UNKNOWN;
798
 
        }
799
 
 
800
 
        result = lookup_name_file_source_instance(ap, &tmap, name, name_len);
801
 
 
802
 
        map->instance = tmap.instance;
803
 
 
804
 
        /* path is freed in free_argv */
805
 
        free_argv(tmap.argc, tmap.argv);
806
 
 
807
 
        return result;
808
 
}
809
 
 
810
 
static void update_negative_cache(struct autofs_point *ap, struct map_source *source, const char *name)
811
 
{
812
 
        struct master_mapent *entry = ap->entry;
813
 
        struct map_source *map;
814
 
        struct mapent *me;
815
 
 
816
 
        /* Have we recorded the lookup fail for negative caching? */
817
 
        me = lookup_source_mapent(ap, name, LKP_DISTINCT);
818
 
        if (me)
819
 
                /*
820
 
                 *  Already exists in the cache, the mount fail updates
821
 
                 *  will update negative timeout status.
822
 
                 */
823
 
                cache_unlock(me->mc);
824
 
        else {
825
 
                /* Notify only once after fail */
826
 
                error(ap->logopt, "key \"%s\" not found in map.", name);
827
 
 
828
 
                /* Doesn't exist in any source, just add it somewhere */
829
 
                if (source)
830
 
                        map = source;
831
 
                else
832
 
                        map = entry->maps;
833
 
                if (map) {
834
 
                        time_t now = time(NULL);
835
 
                        int rv = CHE_FAIL;
836
 
 
837
 
                        cache_writelock(map->mc);
838
 
                        rv = cache_update(map->mc, map, name, NULL, now);
839
 
                        if (rv != CHE_FAIL) {
840
 
                                me = cache_lookup_distinct(map->mc, name);
841
 
                                me->status = now + ap->negative_timeout;
842
 
                        }
843
 
                        cache_unlock(map->mc);
844
 
                }
845
 
        }
846
 
        return;
847
 
}
848
 
 
849
 
int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len)
850
 
{
851
 
        struct master_mapent *entry = ap->entry;
852
 
        struct list_head nsslist;
853
 
        struct list_head *head, *p;
854
 
        struct nss_source *this;
855
 
        struct map_source *map;
856
 
        enum nsswitch_status status;
857
 
        int result = 0;
858
 
 
859
 
        /*
860
 
         * For each map source (ie. each entry for the mount
861
 
         * point in the master map) do the nss lookup to
862
 
         * locate the map and lookup the name.
863
 
         */
864
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
865
 
        master_source_readlock(entry);
866
 
        if (source)
867
 
                map = source;
868
 
        else
869
 
                map = entry->maps;
870
 
        while (map) {
871
 
                /*
872
 
                 * Only consider map sources that have been read since 
873
 
                 * the map entry was last updated.
874
 
                 */
875
 
                if (entry->age > map->age) {
876
 
                        map = map->next;
877
 
                        continue;
878
 
                }
879
 
 
880
 
                sched_yield();
881
 
 
882
 
                if (map->type) {
883
 
                        result = do_lookup_mount(ap, map, name, name_len);
884
 
 
885
 
                        if (result == NSS_STATUS_SUCCESS)
886
 
                                break;
887
 
 
888
 
                        map = map->next;
889
 
                        continue;
890
 
                }
891
 
 
892
 
                /* If it starts with a '/' it has to be a file or LDAP map */
893
 
                if (*map->argv[0] == '/') {
894
 
                        if (*(map->argv[0] + 1) == '/') {
895
 
                                char *tmp = strdup("ldap");
896
 
                                if (!tmp) {
897
 
                                        map = map->next;
898
 
                                        continue;
899
 
                                }
900
 
                                map->type = tmp;
901
 
                                result = do_lookup_mount(ap, map, name, name_len);
902
 
                        } else
903
 
                                result = lookup_name_file_source_instance(ap, map, name, name_len);
904
 
 
905
 
                        if (result == NSS_STATUS_SUCCESS)
906
 
                                break;
907
 
 
908
 
                        map = map->next;
909
 
                        continue;
910
 
                }
911
 
 
912
 
                INIT_LIST_HEAD(&nsslist);
913
 
 
914
 
                status = nsswitch_parse(&nsslist);
915
 
                if (status) {
916
 
                        error(ap->logopt,
917
 
                              "can't to read name service switch config.");
918
 
                        result = 1;
919
 
                        break;
920
 
                }
921
 
 
922
 
                head = &nsslist;
923
 
                list_for_each(p, head) {
924
 
                        this = list_entry(p, struct nss_source, list);
925
 
 
926
 
                        result = lookup_map_name(this, ap, map, name, name_len);
927
 
 
928
 
                        if (result == NSS_STATUS_UNKNOWN) {
929
 
                                map = map->next;
930
 
                                continue;
931
 
                        }
932
 
 
933
 
                        status = check_nss_result(this, result);
934
 
                        if (status >= 0) {
935
 
                                map = NULL;
936
 
                                break;
937
 
                        }
938
 
                }
939
 
 
940
 
                if (!list_empty(&nsslist))
941
 
                        free_sources(&nsslist);
942
 
 
943
 
                if (!map)
944
 
                        break;
945
 
 
946
 
                map = map->next;
947
 
        }
948
 
        if (ap->state != ST_INIT)
949
 
                send_map_update_request(ap);
950
 
        pthread_cleanup_pop(1);
951
 
 
952
 
        /*
953
 
         * The last source lookup will return NSS_STATUS_NOTFOUND if the
954
 
         * map exits and the key has not been found but the map may also
955
 
         * not exist in which case the key is also not found.
956
 
         */
957
 
        if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL)
958
 
                update_negative_cache(ap, source, name);
959
 
 
960
 
        return !result;
961
 
}
962
 
 
963
 
static void lookup_close_lookup_instances(struct map_source *map)
964
 
{
965
 
        struct map_source *instance;
966
 
 
967
 
        instance = map->instance;
968
 
        while (instance) {
969
 
                lookup_close_lookup_instances(instance);
970
 
                instance = instance->next;
971
 
        }
972
 
 
973
 
        if (map->lookup) {
974
 
                close_lookup(map->lookup);
975
 
                map->lookup = NULL;
976
 
        }
977
 
}
978
 
 
979
 
void lookup_close_lookup(struct autofs_point *ap)
980
 
{
981
 
        struct map_source *map;
982
 
 
983
 
        map = ap->entry->maps;
984
 
        if (!map)
985
 
                return;
986
 
 
987
 
        while (map) {
988
 
                lookup_close_lookup_instances(map);
989
 
                map = map->next;
990
 
        }
991
 
 
992
 
        return;
993
 
}
994
 
 
995
 
static char *make_fullpath(const char *root, const char *key)
996
 
{
997
 
        int l;
998
 
        char *path;
999
 
 
1000
 
        if (*key == '/') {
1001
 
                l = strlen(key) + 1;
1002
 
                if (l > KEY_MAX_LEN)
1003
 
                        return NULL;
1004
 
                path = malloc(l);
1005
 
                if (!path)
1006
 
                        return NULL;
1007
 
                strcpy(path, key);
1008
 
        } else {
1009
 
                l = strlen(key) + 1 + strlen(root) + 1;
1010
 
                if (l > KEY_MAX_LEN)
1011
 
                        return NULL;
1012
 
                path = malloc(l);
1013
 
                if (!path)
1014
 
                        return NULL;
1015
 
                sprintf(path, "%s/%s", root, key);
1016
 
        }
1017
 
        return path;
1018
 
}
1019
 
 
1020
 
void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age)
1021
 
{
1022
 
        struct mapent *me, *this;
1023
 
        char *path;
1024
 
        int status = CHE_FAIL;
1025
 
 
1026
 
        me = cache_enumerate(mc, NULL);
1027
 
        while (me) {
1028
 
                struct mapent *valid;
1029
 
                char *key = NULL, *next_key = NULL;
1030
 
 
1031
 
                if (me->age >= age) {
1032
 
                        me = cache_enumerate(mc, me);
1033
 
                        continue;
1034
 
                }
1035
 
 
1036
 
                key = strdup(me->key);
1037
 
                me = cache_enumerate(mc, me);
1038
 
                if (!key || *key == '*') {
1039
 
                        if (key)
1040
 
                                free(key);
1041
 
                        continue;
1042
 
                }
1043
 
 
1044
 
                path = make_fullpath(ap->path, key);
1045
 
                if (!path) {
1046
 
                        warn(ap->logopt, "can't malloc storage for path");
1047
 
                        free(key);
1048
 
                        continue;
1049
 
                }
1050
 
 
1051
 
                /*
1052
 
                 * If this key has another valid entry we want to prune it,
1053
 
                 * even if it's a mount, as the valid entry will take the
1054
 
                 * mount if it is a direct mount or it's just a stale indirect
1055
 
                 * cache entry.
1056
 
                 */
1057
 
                valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
1058
 
                if (!valid &&
1059
 
                    is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
1060
 
                        debug(ap->logopt,
1061
 
                              "prune check posponed, %s mounted", path);
1062
 
                        free(key);
1063
 
                        free(path);
1064
 
                        continue;
1065
 
                }
1066
 
                if (valid)
1067
 
                        cache_unlock(valid->mc);
1068
 
 
1069
 
                if (me)
1070
 
                        next_key = strdup(me->key);
1071
 
 
1072
 
                cache_unlock(mc);
1073
 
 
1074
 
                cache_writelock(mc);
1075
 
                this = cache_lookup_distinct(mc, key);
1076
 
                if (!this) {
1077
 
                        cache_unlock(mc);
1078
 
                        goto next;
1079
 
                }
1080
 
 
1081
 
                if (valid)
1082
 
                        cache_delete(mc, key);
1083
 
                else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
1084
 
                        status = CHE_FAIL;
1085
 
                        if (this->ioctlfd == -1)
1086
 
                                status = cache_delete(mc, key);
1087
 
                        if (status != CHE_FAIL) {
1088
 
                                if (ap->type == LKP_INDIRECT) {
1089
 
                                        if (ap->flags & MOUNT_FLAG_GHOST)
1090
 
                                                rmdir_path(ap, path, ap->dev);
1091
 
                                } else
1092
 
                                        rmdir_path(ap, path, this->dev);
1093
 
                        }
1094
 
                }
1095
 
                cache_unlock(mc);
1096
 
 
1097
 
next:
1098
 
                cache_readlock(mc);
1099
 
                if (next_key) {
1100
 
                        me = cache_lookup_distinct(mc, next_key);
1101
 
                        free(next_key);
1102
 
                }
1103
 
                free(key);
1104
 
                free(path);
1105
 
        }
1106
 
 
1107
 
        return;
1108
 
}
1109
 
 
1110
 
int lookup_prune_cache(struct autofs_point *ap, time_t age)
1111
 
{
1112
 
        struct master_mapent *entry = ap->entry;
1113
 
        struct map_source *map;
1114
 
 
1115
 
        pthread_cleanup_push(master_source_lock_cleanup, entry);
1116
 
        master_source_readlock(entry);
1117
 
 
1118
 
        map = entry->maps;
1119
 
        while (map) {
1120
 
                /* Is the map stale */
1121
 
                if (!map->stale) {
1122
 
                        map = map->next;
1123
 
                        continue;
1124
 
                }
1125
 
                pthread_cleanup_push(cache_lock_cleanup, map->mc);
1126
 
                cache_readlock(map->mc);
1127
 
                lookup_prune_one_cache(ap, map->mc, age);
1128
 
                pthread_cleanup_pop(1);
1129
 
                map->stale = 0;
1130
 
                map = map->next;
1131
 
        }
1132
 
 
1133
 
        pthread_cleanup_pop(1);
1134
 
 
1135
 
        return 1;
1136
 
}
1137
 
 
1138
 
/* Return with cache readlock held */
1139
 
struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type)
1140
 
{
1141
 
        struct master_mapent *entry = ap->entry;
1142
 
        struct map_source *map;
1143
 
        struct mapent_cache *mc;
1144
 
        struct mapent *me = NULL;
1145
 
 
1146
 
        map = entry->maps;
1147
 
        while (map) {
1148
 
                /*
1149
 
                 * Only consider map sources that have been read since
1150
 
                 * the map entry was last updated.
1151
 
                 */
1152
 
                if (ap->entry->age > map->age) {
1153
 
                        map = map->next;
1154
 
                        continue;
1155
 
                }
1156
 
 
1157
 
                mc = map->mc;
1158
 
                cache_readlock(mc);
1159
 
                if (type == LKP_DISTINCT)
1160
 
                        me = cache_lookup_distinct(mc, key);
1161
 
                else
1162
 
                        me = cache_lookup(mc, key);
1163
 
                if (me)
1164
 
                        break;
1165
 
                cache_unlock(mc);
1166
 
                map = map->next;
1167
 
        }
1168
 
 
1169
 
        return me;
1170
 
}
1171
 
 
1172
 
/* Return with cache readlock held */
1173
 
struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type)
1174
 
{
1175
 
        struct master_mapent *entry = ap->entry;
1176
 
        struct map_source *map;
1177
 
        struct mapent_cache *mc;
1178
 
        struct mapent *me = NULL;
1179
 
 
1180
 
        map = entry->maps;
1181
 
        while (map) {
1182
 
                mc = map->mc;
1183
 
                cache_readlock(mc);
1184
 
                if (type == LKP_DISTINCT)
1185
 
                        me = cache_lookup_distinct(mc, key);
1186
 
                else
1187
 
                        me = cache_lookup(mc, key);
1188
 
                if (me)
1189
 
                        break;
1190
 
                cache_unlock(mc);
1191
 
                map = map->next;
1192
 
        }
1193
 
 
1194
 
        if (me && me->mc != mc)
1195
 
                error(LOGOPT_ANY, "mismatching mc in cache", me->key);
1196
 
 
1197
 
        return me;
1198
 
}
1199
 
 
1200
 
int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key)
1201
 
{
1202
 
        struct master_mapent *entry = ap->entry;
1203
 
        struct map_source *map;
1204
 
        struct mapent_cache *mc;
1205
 
        struct mapent *me;
1206
 
        int ret = 0;
1207
 
 
1208
 
        map = entry->maps;
1209
 
        while (map) {
1210
 
                mc = map->mc;
1211
 
                cache_readlock(mc);
1212
 
                me = cache_lookup_distinct(mc, key);
1213
 
                if (me) {
1214
 
                        if (me->ioctlfd != -1) {
1215
 
                                struct ioctl_ops *ops = get_ioctl_ops();
1216
 
                                ops->close(ap->logopt, me->ioctlfd);
1217
 
                                me->ioctlfd = -1;
1218
 
                        }
1219
 
                        cache_unlock(mc);
1220
 
                        ret = 1;
1221
 
                        break;
1222
 
                }
1223
 
                cache_unlock(mc);
1224
 
                map = map->next;
1225
 
        }
1226
 
 
1227
 
        return ret;
1228
 
}
1229