1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/shlib/t_loader.c */
3 /*
4 * Copyright (C) 2005 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-platform.h"
28 #include "krb5.h"
29 #include "gssapi/gssapi.h"
30 #define HAVE_DLOPEN 1
31
32 static int verbose = 1;
33
34 #ifdef HAVE_DLFCN_H
35 # include <dlfcn.h>
36 #endif
37 /* Solaris man page recommends link.h too */
38
39 /* lazy = 1 means resolve symbols later, 0 means now; any
40 other flags we should be testing? On Windows, maybe?
41
42 Return value is the library handle. On error, print a message and
43 exit. */
44 #define do_open(LIB,REV,FLAGS) do_open_1(LIB,REV,FLAGS,__LINE__)
45 static void *do_open_1(const char *libname, const char *rev, int lazy, int line);
46
47 /* Look up a function symbol in the library and return a pointer.
48
49 The return value may need casting to the correct type. On error,
50 print a message and exit. */
51 static void *get_sym_1(void *libhandle, const char *sym, int line);
52 #define get_sym(LIB, NAME) get_sym_1(LIB, NAME, __LINE__)
53 #define GET_FSYM(TYPE, LIB, NAME) ((TYPE) get_sym(LIB, NAME))
54 #define get_gfun(LIB, NAME) ((OM_uint32 KRB5_CALLCONV(*)()) get_sym(LIB, NAME))
55
56 /* Close dynamically-opened library.
57
58 If the OS reports an error in doing so, print a message and
59 exit. */
60 #define do_close(X) do_close_1(X, __LINE__)
61 static void do_close_1(void *libhandle, int line);
62
63 #ifdef HAVE_DLOPEN
64
65 #ifdef _AIX
66 # define SHLIB_SUFFIX ".a"
67 #else
68 # define SHLIB_SUFFIX ".so"
69 #endif
70
71 #define HORIZ 25
72
do_open_1(const char * libname,const char * rev,int lazy,int line)73 static void *do_open_1(const char *libname, const char *rev,
74 int lazy, int line)
75 {
76 void *p;
77 char *namebuf;
78 int r;
79
80 if (verbose)
81 printf("from line %d: do_open(%s)...%*s", line, libname,
82 HORIZ-strlen(libname), "");
83 #ifdef _AIX
84 r = asprintf(&namebuf, "lib%s%s", libname, SHLIB_SUFFIX);
85 #else
86 r = asprintf(&namebuf, "lib%s%s(shr.o.%s)", libname, SHLIB_SUFFIX, rev);
87 #endif
88 if (r < 0) {
89 perror("asprintf");
90 exit(1);
91 }
92
93 #ifndef RTLD_MEMBER
94 #define RTLD_MEMBER 0
95 #endif
96 p = dlopen(namebuf, (lazy ? RTLD_LAZY : RTLD_NOW) | RTLD_MEMBER);
97 if (p == 0) {
98 fprintf(stderr, "dlopen of %s failed: %s\n", namebuf, dlerror());
99 exit(1);
100 }
101 free(namebuf);
102 if (verbose)
103 printf("done: %p\n", p);
104 return p;
105 }
106
107 #define SYM_PREFIX ""
get_sym_1(void * libhandle,const char * symname,int line)108 static void *get_sym_1(void *libhandle, const char *symname, int line)
109 {
110 void *s;
111
112 /* Bah. Fix this later, if we care. */
113 assert(strlen(SYM_PREFIX) == 0);
114
115 if (verbose)
116 printf("from line %d: get_sym(%s)...%*s", line, symname,
117 HORIZ-strlen(symname), "");
118
119 s = dlsym(libhandle, symname);
120 if (s == 0) {
121 fprintf(stderr, "symbol %s not found\n", symname);
122 exit(1);
123 }
124 if (verbose)
125 printf("done: %p\n", s);
126 return s;
127 }
128
do_close_1(void * libhandle,int line)129 static void do_close_1(void *libhandle, int line)
130 {
131 if (verbose) {
132 char pbuf[3*sizeof(libhandle)+4];
133 snprintf(pbuf, sizeof(pbuf), "%p", libhandle);
134 printf("from line %d: do_close(%s)...%*s", line, pbuf,
135 HORIZ-1-strlen(pbuf), "");
136 }
137 if (dlclose(libhandle) != 0) {
138 fprintf(stderr, "dlclose failed: %s\n", dlerror());
139 exit(1);
140 }
141 if (verbose)
142 printf("done\n");
143 }
144
145 #elif defined _WIN32
146
do_open(const char * libname,int lazy)147 static void *do_open(const char *libname, int lazy)
148 {
149 /* To be written? */
150 abort();
151 }
152
get_sym(void * libhandle,const char * symname)153 static void *get_sym(void *libhandle, const char *symname)
154 {
155 abort();
156 }
157
do_close(void * libhandle)158 static void do_close(void *libhandle)
159 {
160 abort();
161 }
162
163 #else
164
do_open(const char * libname,int lazy)165 static void *do_open(const char *libname, int lazy)
166 {
167 printf("don't know how to do dynamic loading here, punting\n");
168 exit(0);
169 }
170
get_sym(void * libhandle,const char * symname)171 static void *get_sym(void *libhandle, const char *symname)
172 {
173 abort();
174 }
175
do_close(void * libhandle)176 static void do_close(void *libhandle)
177 {
178 abort();
179 }
180
181 #endif
182
main()183 int main()
184 {
185 void *celib, *k5lib, *gsslib, *celib2;
186
187 (void) setvbuf(stdout, 0, _IONBF, 0);
188
189 celib = do_open("com_err", "3.0", 0);
190 k5lib = do_open("krb5", "3.2", 0);
191 gsslib = do_open("gssapi_krb5", "2.2", 0);
192 celib2 = do_open("com_err", "3.0", 0);
193 do_close(celib2);
194 {
195 typedef krb5_error_code KRB5_CALLCONV (*ict)(krb5_context *);
196 typedef void KRB5_CALLCONV (*fct)(krb5_context);
197
198 ict init_context = (ict) get_sym(k5lib, "krb5_init_context");
199 fct free_context = (fct) get_sym(k5lib, "krb5_free_context");
200 krb5_context ctx;
201 krb5_error_code err;
202
203 #define CALLING(S) (verbose ? printf("at line %d: calling %s...%*s", __LINE__, #S, (int)(HORIZ+1-strlen(#S)), "") : 0)
204 #define DONE() (verbose ? printf("done\n") : 0)
205
206 CALLING(krb5_init_context);
207 err = init_context(&ctx);
208 DONE();
209 if (err) {
210 fprintf(stderr, "error 0x%lx initializing context\n",
211 (unsigned long) err);
212 exit(1);
213 }
214 CALLING(krb5_free_context);
215 free_context(ctx);
216 DONE();
217 }
218 celib2 = do_open("com_err", "3.0", 0);
219 do_close(celib);
220 do_close(k5lib);
221 do_close(celib2);
222 do_close(gsslib);
223
224 /* Test gssapi_krb5 without having loaded anything else. */
225 gsslib = do_open("gssapi_krb5", "2.2", 1);
226 {
227 OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
228 gss_ctx_id_t *, gss_name_t,
229 gss_OID,
230 OM_uint32, OM_uint32,
231 gss_channel_bindings_t,
232 gss_buffer_t, gss_OID *,
233 gss_buffer_t,
234 OM_uint32 *, OM_uint32 *)
235 = get_gfun(gsslib, "gss_init_sec_context");
236 OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
237 gss_OID, gss_name_t *)
238 = get_gfun(gsslib, "gss_import_name");
239 OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
240 = get_gfun(gsslib, "gss_release_buffer");
241 OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
242 = get_gfun(gsslib, "gss_release_name");
243 OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
244 gss_ctx_id_t *,
245 gss_buffer_t)
246 = get_gfun(gsslib, "gss_delete_sec_context");
247
248 OM_uint32 gmaj, gmin;
249 OM_uint32 retflags;
250 gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
251 gss_buffer_desc token;
252 gss_name_t target;
253 static gss_buffer_desc target_name_buf = {
254 9, "x@mit.edu"
255 };
256 static gss_OID_desc service_name = {
257 10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
258 };
259
260 CALLING(gss_import_name);
261 gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
262 DONE();
263 if (gmaj != GSS_S_COMPLETE) {
264 fprintf(stderr,
265 "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
266 (unsigned long) gmaj, (unsigned long) gmin,
267 (signed long) gmin);
268 exit(1);
269 }
270 /* This will probably get different errors, depending on
271 whether we have tickets at the time. Doesn't matter much,
272 we're ignoring the error and testing whether we're doing
273 cleanup properly. (Though the internal cleanup needed in
274 the two cases might be different.) */
275 CALLING(gss_init_sec_context);
276 gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
277 GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
278 NULL, &token, &retflags, NULL);
279 DONE();
280 /* Ignore success/failure indication. */
281 if (token.length) {
282 CALLING(gss_release_buffer);
283 release_buffer(&gmin, &token);
284 DONE();
285 }
286 CALLING(gss_release_name);
287 release_name(&gmin, &target);
288 DONE();
289 if (gctx != GSS_C_NO_CONTEXT) {
290 CALLING(gss_delete_sec_context);
291 delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
292 DONE();
293 }
294 }
295 do_close(gsslib);
296
297 /* Test gssapi_krb5 with com_err already loaded, then unload
298 com_err first. */
299 celib = do_open("com_err", "3.0", 1);
300 gsslib = do_open("gssapi_krb5", "2.2", 1);
301 {
302 OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
303 gss_ctx_id_t *, gss_name_t,
304 gss_OID,
305 OM_uint32, OM_uint32,
306 gss_channel_bindings_t,
307 gss_buffer_t, gss_OID *,
308 gss_buffer_t,
309 OM_uint32 *, OM_uint32 *)
310 = get_gfun(gsslib, "gss_init_sec_context");
311 OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
312 gss_OID, gss_name_t *)
313 = get_gfun(gsslib, "gss_import_name");
314 OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
315 = get_gfun(gsslib, "gss_release_buffer");
316 OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
317 = get_gfun(gsslib, "gss_release_name");
318 OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
319 gss_ctx_id_t *,
320 gss_buffer_t)
321 = get_gfun(gsslib, "gss_delete_sec_context");
322
323 OM_uint32 gmaj, gmin;
324 OM_uint32 retflags;
325 gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
326 gss_buffer_desc token;
327 gss_name_t target;
328 static gss_buffer_desc target_name_buf = {
329 9, "x@mit.edu"
330 };
331 static gss_OID_desc service_name = {
332 10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
333 };
334
335 CALLING(gss_import_name);
336 gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
337 DONE();
338 if (gmaj != GSS_S_COMPLETE) {
339 fprintf(stderr,
340 "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
341 (unsigned long) gmaj, (unsigned long) gmin,
342 (signed long) gmin);
343 exit(1);
344 }
345 /* This will probably get different errors, depending on
346 whether we have tickets at the time. Doesn't matter much,
347 we're ignoring the error and testing whether we're doing
348 cleanup properly. (Though the internal cleanup needed in
349 the two cases might be different.) */
350 CALLING(gss_init_sec_context);
351 gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
352 GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
353 NULL, &token, &retflags, NULL);
354 DONE();
355 /* Ignore success/failure indication. */
356 if (token.length) {
357 CALLING(gss_release_buffer);
358 release_buffer(&gmin, &token);
359 DONE();
360 }
361 CALLING(gss_release_name);
362 release_name(&gmin, &target);
363 DONE();
364 if (gctx != GSS_C_NO_CONTEXT) {
365 CALLING(gss_delete_sec_context);
366 delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
367 DONE();
368 }
369 }
370 do_close(celib);
371 do_close(gsslib);
372
373 return 0;
374 }
375