1
#ident "$Id: lookup_nssldap.c,v 1.3 2005/08/08 23:28:37 lukeh Exp $"
2
/* ----------------------------------------------------------------------- *
4
* lookup_nss.c - module for Linux automountd to access a NSS
7
* Copyright 1997 Transmeta Corporation - All Rights Reserved
8
* Copyright 2001-2003 Ian Kent <raven@themaw.net>
9
* Copyright 2005 PADL Software Pty Ltd - All Rights Reserved
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
14
* USA; either version 2 of the License, or (at your option) any later
15
* version; incorporated herein by reference.
17
* ----------------------------------------------------------------------- */
21
#include <sys/types.h>
28
#include <netinet/in.h>
29
#include <arpa/nameser.h>
35
#include "automount.h"
37
#define MAPFMT_DEFAULT "sun"
39
#define NAMESERVICE "ldap"
41
#define MODPREFIX "lookup(nss" NAMESERVICE "): "
43
struct lookup_context {
46
struct parse_mod *parse;
48
enum nss_status (*setautomntent)(const char *, void **);
49
enum nss_status (*getautomntent_r)(void *, const char **, const char **,
50
char *, size_t, int *);
51
enum nss_status (*endautomntent)(void **);
52
enum nss_status (*getautomntbyname_r)(void *, const char *,
53
const char **, const char **,
54
char *, size_t, int *);
57
int lookup_version = AUTOFS_LOOKUP_VERSION;
59
int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **context_p)
61
struct lookup_context *context;
64
context = (struct lookup_context *)malloc(sizeof(*context));
65
if (context == NULL) {
66
crit(MODPREFIX "malloc: %m");
69
memset(context, 0, sizeof(*context));
71
context->nsname = NULL;
72
context->parse = NULL;
73
context->dlhandle = NULL;
74
context->setautomntent = NULL;
75
context->getautomntent_r = NULL;
76
context->endautomntent = NULL;
79
mapfmt = MAPFMT_DEFAULT;
83
crit(MODPREFIX "invalid number of arguments");
87
asprintf(&context->nsname, "nss%s", NAMESERVICE);
88
if (context->nsname == NULL) {
89
crit(MODPREFIX "strdup: %m");
93
snprintf(buf, sizeof(buf), "libnss_%s.so.2", NAMESERVICE);
95
context->dlhandle = dlopen(buf, RTLD_NOW | RTLD_LOCAL);
96
if (context->dlhandle == NULL) {
97
crit(MODPREFIX "failed to load %s nameservice provider: %s", NAMESERVICE, dlerror());
101
snprintf(buf, sizeof(buf), "_nss_%s_setautomntent", NAMESERVICE);
102
context->setautomntent = dlsym(context->dlhandle, buf);
103
if (context->setautomntent == NULL) {
104
crit(MODPREFIX "failed to load %s nameservice provider: %s", NAMESERVICE, dlerror());
108
snprintf(buf, sizeof(buf), "_nss_%s_getautomntent_r", NAMESERVICE);
109
context->getautomntent_r = dlsym(context->dlhandle, buf);
110
if (context->getautomntent_r == NULL) {
111
crit(MODPREFIX "failed to load %s nameservice provider: %s", NAMESERVICE, dlerror());
115
snprintf(buf, sizeof(buf), "_nss_%s_endautomntent", NAMESERVICE);
116
context->endautomntent = dlsym(context->dlhandle, buf);
117
if (context->endautomntent == NULL) {
118
crit(MODPREFIX "failed to load %s nameservice provider: %s", NAMESERVICE, dlerror());
122
snprintf(buf, sizeof(buf), "_nss_%s_getautomntbyname_r", NAMESERVICE);
123
context->getautomntbyname_r = dlsym(context->dlhandle, buf);
124
if (context->getautomntbyname_r == NULL) {
125
crit(MODPREFIX "failed to load %s nameservice provider: %s", NAMESERVICE, dlerror());
129
context->mapname = strdup(argv[0]);
130
if (context->mapname == NULL) {
131
crit(MODPREFIX "strdup: %m");
135
context->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
136
if (context->parse == NULL) {
141
*context_p = context;
145
static const char *nsserr_string(enum nss_status status)
148
case NSS_STATUS_TRYAGAIN:
149
return "Insufficient buffer space";
151
case NSS_STATUS_UNAVAIL:
152
return "Name service unavailable";
154
case NSS_STATUS_NOTFOUND:
157
case NSS_STATUS_SUCCESS:
164
return "Unknown error";
167
static int read_map(const char *root, struct lookup_context *context)
169
enum nss_status status;
170
void *private = NULL;
171
time_t age = time(NULL);
172
const char *key, *mapent;
174
char buffer[KEY_MAX_LEN + 1 + MAPENT_MAX_LEN + 1];
176
status = (*context->setautomntent)(context->mapname, &private);
177
if (status != NSS_STATUS_SUCCESS) {
178
warn(MODPREFIX "failed to read map %s: %s",
179
context->mapname, nsserr_string(status));
184
status = (*context->getautomntent_r)(private, &key, &mapent,
185
buffer, sizeof(buffer),
187
if (status != NSS_STATUS_SUCCESS)
190
cache_update(root, key, mapent, age);
192
cache_update(key, mapent, age);
196
(*context->endautomntent)(&private);
198
cache_clean(root, age);
202
int lookup_ghost(const char *root, int ghost, time_t now, void *context)
204
struct lookup_context *ctxt = (struct lookup_context *)context;
205
struct mapent_cache *me;
208
if (!read_map(root, ctxt))
211
status = cache_ghost(root, ghost, ctxt->mapname, ctxt->nsname, ctxt->parse);
213
me = cache_lookup_first();
217
if (*me->key == '/' && *(root + 1) != '-') {
218
me = cache_partial_match(root);
219
/* me NULL => no entries for this direct mount root or indirect map */
221
return LKP_FAIL | LKP_INDIRECT;
227
int lookup_mount(const char *root, const char *name, int name_len, void *context)
229
struct lookup_context *ctxt = (struct lookup_context *)context;
230
char key[KEY_MAX_LEN + 1];
231
char buffer[KEY_MAX_LEN + 1 + MAPENT_MAX_LEN + 1];
232
const char *canon_key, *mapent;
233
struct mapent_cache *me = NULL;
234
time_t age = time(NULL);
235
enum nss_status status;
237
debug(MODPREFIX "looking up %s", name);
239
snprintf(key, sizeof(key), "%s/%s", root, name);
241
me = cache_lookup(name);
243
me = cache_lookup(key);
247
/* path component, do submount */
248
me = cache_partial_match(key);
251
snprintf(buffer, sizeof(buffer), "-fstype=autofs %s:%s",
252
ctxt->nsname, ctxt->mapname);
256
snprintf(buffer, sizeof(buffer), "%s", me->mapent);
264
void *private = NULL;
266
status = (*ctxt->setautomntent)(ctxt->mapname, &private);
267
if (status != NSS_STATUS_SUCCESS) {
268
warn(MODPREFIX "failed to read map %s: %s", ctxt->mapname, nsserr_string(status));
276
for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
277
status = (*ctxt->getautomntbyname_r)(private, name,
279
buffer, sizeof(buffer),
281
if (status != NSS_STATUS_NOTFOUND)
285
(*ctxt->endautomntent)(&private);
287
if (status != NSS_STATUS_SUCCESS) {
288
warn(MODPREFIX "failed to read map %s: %s", ctxt->mapname, nsserr_string(status));
293
cache_update(root, keys[i], mapent, age);
295
cache_update(keys[i], mapent, age);
299
debug(MODPREFIX "%s -> %s", name, mapent);
301
return ctxt->parse->parse_mount(root, name, name_len, mapent, ctxt->parse->context);
304
warn(MODPREFIX "lookup for %s failed: %d", name, status);
308
int lookup_done(void *context)
310
struct lookup_context *ctxt = (struct lookup_context *)context;
313
if (ctxt->nsname != NULL) {
318
if (ctxt->mapname != NULL) {
320
ctxt->mapname = NULL;
323
ret = close_parse(ctxt->parse);
325
if (ctxt->dlhandle != NULL) {
326
dlclose(ctxt->dlhandle);
327
ctxt->dlhandle = NULL;
330
memset(ctxt, 0, sizeof(*ctxt));