~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/plugin.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include "krb5_locl.h"
 
35
RCSID("$Id$");
 
36
#ifdef HAVE_DLFCN_H
 
37
#include <dlfcn.h>
 
38
#endif
 
39
#include <dirent.h>
 
40
 
 
41
struct krb5_plugin {
 
42
    void *symbol;
 
43
    void *dsohandle;
 
44
    struct krb5_plugin *next;
 
45
};
 
46
 
 
47
struct plugin {
 
48
    enum krb5_plugin_type type;
 
49
    void *name;
 
50
    void *symbol;
 
51
    struct plugin *next;
 
52
};
 
53
 
 
54
static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
 
55
static struct plugin *registered = NULL;
 
56
 
 
57
static const char *plugin_dir = LIBDIR "/plugin/krb5";
 
58
 
 
59
/*
 
60
 *
 
61
 */
 
62
 
 
63
void *
 
64
_krb5_plugin_get_symbol(struct krb5_plugin *p)
 
65
{
 
66
    return p->symbol;
 
67
}
 
68
 
 
69
struct krb5_plugin *
 
70
_krb5_plugin_get_next(struct krb5_plugin *p)
 
71
{
 
72
    return p->next;
 
73
}
 
74
 
 
75
/*
 
76
 *
 
77
 */
 
78
 
 
79
#ifdef HAVE_DLOPEN
 
80
 
 
81
static krb5_error_code
 
82
loadlib(krb5_context context,
 
83
        enum krb5_plugin_type type,
 
84
        const char *name,
 
85
        const char *lib,
 
86
        struct krb5_plugin **e)
 
87
{
 
88
    *e = calloc(1, sizeof(**e));
 
89
    if (*e == NULL) {
 
90
        krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
 
91
        return ENOMEM;
 
92
    }
 
93
 
 
94
#ifndef RTLD_LAZY
 
95
#define RTLD_LAZY 0
 
96
#endif
 
97
 
 
98
    (*e)->dsohandle = dlopen(lib, RTLD_LAZY);
 
99
    if ((*e)->dsohandle == NULL) {
 
100
        free(*e);
 
101
        *e = NULL;
 
102
        krb5_set_error_message(context, ENOMEM, "Failed to load %s: %s",
 
103
                               lib, dlerror());
 
104
        return ENOMEM;
 
105
    }
 
106
 
 
107
    /* dlsym doesn't care about the type */
 
108
    (*e)->symbol = dlsym((*e)->dsohandle, name);
 
109
    if ((*e)->symbol == NULL) {
 
110
        dlclose((*e)->dsohandle);
 
111
        free(*e);
 
112
        krb5_clear_error_message(context);
 
113
        return ENOMEM;
 
114
    }
 
115
 
 
116
    return 0;
 
117
}
 
118
#endif /* HAVE_DLOPEN */
 
119
 
 
120
/**
 
121
 * Register a plugin symbol name of specific type.
 
122
 * @param context a Keberos context
 
123
 * @param type type of plugin symbol
 
124
 * @param name name of plugin symbol
 
125
 * @param symbol a pointer to the named symbol
 
126
 * @return In case of error a non zero error com_err error is returned
 
127
 * and the Kerberos error string is set.
 
128
 *
 
129
 * @ingroup krb5_support
 
130
 */
 
131
 
 
132
krb5_error_code
 
133
krb5_plugin_register(krb5_context context,
 
134
                     enum krb5_plugin_type type,
 
135
                     const char *name,
 
136
                     void *symbol)
 
137
{
 
138
    struct plugin *e;
 
139
 
 
140
    /* check for duplicates */
 
141
    for (e = registered; e != NULL; e = e->next)
 
142
        if (e->type == type && strcmp(e->name,name)== 0 && e->symbol == symbol)
 
143
            return 0;
 
144
 
 
145
    e = calloc(1, sizeof(*e));
 
146
    if (e == NULL) {
 
147
        krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
 
148
        return ENOMEM;
 
149
    }
 
150
    e->type = type;
 
151
    e->name = strdup(name);
 
152
    if (e->name == NULL) {
 
153
        free(e);
 
154
        krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
 
155
        return ENOMEM;
 
156
    }
 
157
    e->symbol = symbol;
 
158
 
 
159
    HEIMDAL_MUTEX_lock(&plugin_mutex);
 
160
    e->next = registered;
 
161
    registered = e;
 
162
    HEIMDAL_MUTEX_unlock(&plugin_mutex);
 
163
 
 
164
    return 0;
 
165
}
 
166
 
 
167
krb5_error_code
 
168
_krb5_plugin_find(krb5_context context,
 
169
                  enum krb5_plugin_type type,
 
170
                  const char *name,
 
171
                  struct krb5_plugin **list)
 
172
{
 
173
    struct krb5_plugin *e;
 
174
    struct plugin *p;
 
175
    krb5_error_code ret;
 
176
    char *sysdirs[2] = { NULL, NULL };
 
177
    char **dirs = NULL, **di;
 
178
    struct dirent *entry;
 
179
    char *path;
 
180
    DIR *d = NULL;
 
181
 
 
182
    *list = NULL;
 
183
 
 
184
    HEIMDAL_MUTEX_lock(&plugin_mutex);
 
185
 
 
186
    for (p = registered; p != NULL; p = p->next) {
 
187
        if (p->type != type || strcmp(p->name, name) != 0)
 
188
            continue;
 
189
 
 
190
        e = calloc(1, sizeof(*e));
 
191
        if (e == NULL) {
 
192
            HEIMDAL_MUTEX_unlock(&plugin_mutex);
 
193
            ret = ENOMEM;
 
194
            krb5_set_error_message(context, ret, "malloc: out of memory");
 
195
            goto out;
 
196
        }
 
197
        e->symbol = p->symbol;
 
198
        e->dsohandle = NULL;
 
199
        e->next = *list;
 
200
        *list = e;
 
201
    }
 
202
    HEIMDAL_MUTEX_unlock(&plugin_mutex);
 
203
 
 
204
#ifdef HAVE_DLOPEN
 
205
 
 
206
    dirs = krb5_config_get_strings(context, NULL, "libdefaults",
 
207
                                   "plugin_dir", NULL);
 
208
    if (dirs == NULL) {
 
209
        sysdirs[0] = rk_UNCONST(plugin_dir);
 
210
        dirs = sysdirs;
 
211
    }
 
212
 
 
213
    for (di = dirs; *di != NULL; di++) {
 
214
 
 
215
        d = opendir(*di);
 
216
        if (d == NULL)
 
217
            continue;
 
218
        rk_cloexec(dirfd(d));
 
219
 
 
220
        while ((entry = readdir(d)) != NULL) {
 
221
            asprintf(&path, "%s/%s", *di, entry->d_name);
 
222
            if (path == NULL) {
 
223
                ret = ENOMEM;
 
224
                krb5_set_error_message(context, ret, "malloc: out of memory");
 
225
                goto out;
 
226
            }
 
227
            ret = loadlib(context, type, name, path, &e);
 
228
            free(path);
 
229
            if (ret)
 
230
                continue;
 
231
        
 
232
            e->next = *list;
 
233
            *list = e;
 
234
        }
 
235
        closedir(d);
 
236
    }
 
237
    if (dirs != sysdirs)
 
238
        krb5_config_free_strings(dirs);
 
239
#endif /* HAVE_DLOPEN */
 
240
 
 
241
    if (*list == NULL) {
 
242
        krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
 
243
        return ENOENT;
 
244
    }
 
245
 
 
246
    return 0;
 
247
 
 
248
out:
 
249
    if (dirs && dirs != sysdirs)
 
250
        krb5_config_free_strings(dirs);
 
251
    if (d)
 
252
        closedir(d);
 
253
    _krb5_plugin_free(*list);
 
254
    *list = NULL;
 
255
 
 
256
    return ret;
 
257
}
 
258
 
 
259
void
 
260
_krb5_plugin_free(struct krb5_plugin *list)
 
261
{
 
262
    struct krb5_plugin *next;
 
263
    while (list) {
 
264
        next = list->next;
 
265
        if (list->dsohandle)
 
266
            dlclose(list->dsohandle);
 
267
        free(list);
 
268
        list = next;
 
269
    }
 
270
}