Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / tests / shlib / t_loader.c
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
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 ""
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
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
147 static void *do_open(const char *libname, int lazy)
148 {
149     /* To be written?  */
150     abort();
151 }
152
153 static void *get_sym(void *libhandle, const char *symname)
154 {
155     abort();
156 }
157
158 static void do_close(void *libhandle)
159 {
160     abort();
161 }
162
163 #else
164
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
171 static void *get_sym(void *libhandle, const char *symname)
172 {
173     abort();
174 }
175
176 static void do_close(void *libhandle)
177 {
178     abort();
179 }
180
181 #endif
182
183 int main()
184 {
185     void *celib, *k5lib, *gsslib, *celib2;
186
187     (void) setvbuf(stdout, 0, _IONBF, 0);
188
189 #if 0
190     /* Simplest test: Load, then unload out of order.  */
191     celib = do_open("com_err", "3.0", 0);
192     k5lib = do_open("krb5", "3.2", 0);
193     gsslib = do_open("gssapi_krb5", "2.2", 0);
194     celib2 = do_open("com_err", "3.0", 0);
195     do_close(celib);
196     do_close(k5lib);
197     do_close(celib2);
198     do_close(gsslib);
199 #endif
200
201     celib = do_open("com_err", "3.0", 0);
202     k5lib = do_open("krb5", "3.2", 0);
203     gsslib = do_open("gssapi_krb5", "2.2", 0);
204     celib2 = do_open("com_err", "3.0", 0);
205     do_close(celib2);
206     {
207         typedef krb5_error_code KRB5_CALLCONV (*ict)(krb5_context *);
208         typedef void KRB5_CALLCONV (*fct)(krb5_context);
209
210         ict init_context = (ict) get_sym(k5lib, "krb5_init_context");
211         fct free_context = (fct) get_sym(k5lib, "krb5_free_context");
212         krb5_context ctx;
213         krb5_error_code err;
214
215 #define CALLING(S) (verbose ? printf("at   line %d: calling %s...%*s", __LINE__, #S, (int)(HORIZ+1-strlen(#S)), "") : 0)
216 #define DONE() (verbose ? printf("done\n") : 0)
217
218         CALLING(krb5_init_context);
219         err = init_context(&ctx);
220         DONE();
221         if (err) {
222             fprintf(stderr, "error 0x%lx initializing context\n",
223                     (unsigned long) err);
224             exit(1);
225         }
226         CALLING(krb5_free_context);
227         free_context(ctx);
228         DONE();
229     }
230     celib2 = do_open("com_err", "3.0", 0);
231     do_close(celib);
232     do_close(k5lib);
233     do_close(celib2);
234     do_close(gsslib);
235
236     /* Test gssapi_krb5 without having loaded anything else.  */
237     gsslib = do_open("gssapi_krb5", "2.2", 1);
238     {
239         OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
240                                                     gss_ctx_id_t *, gss_name_t,
241                                                     gss_OID,
242                                                     OM_uint32, OM_uint32,
243                                                     gss_channel_bindings_t,
244                                                     gss_buffer_t, gss_OID *,
245                                                     gss_buffer_t,
246                                                     OM_uint32 *, OM_uint32 *)
247             = get_gfun(gsslib, "gss_init_sec_context");
248         OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
249                                                gss_OID, gss_name_t *)
250             = get_gfun(gsslib, "gss_import_name");
251         OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
252             = get_gfun(gsslib, "gss_release_buffer");
253         OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
254             = get_gfun(gsslib, "gss_release_name");
255         OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
256                                                       gss_ctx_id_t *,
257                                                       gss_buffer_t)
258             = get_gfun(gsslib, "gss_delete_sec_context");
259
260         OM_uint32 gmaj, gmin;
261         OM_uint32 retflags;
262         gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
263         gss_buffer_desc token;
264         gss_name_t target;
265         static gss_buffer_desc target_name_buf = {
266             9, "x@mit.edu"
267         };
268         static gss_OID_desc service_name = {
269             10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
270         };
271
272         CALLING(gss_import_name);
273         gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
274         DONE();
275         if (gmaj != GSS_S_COMPLETE) {
276             fprintf(stderr,
277                     "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
278                     (unsigned long) gmaj, (unsigned long) gmin,
279                     (signed long) gmin);
280             exit(1);
281         }
282         /* This will probably get different errors, depending on
283            whether we have tickets at the time.  Doesn't matter much,
284            we're ignoring the error and testing whether we're doing
285            cleanup properly.  (Though the internal cleanup needed in
286            the two cases might be different.)  */
287         CALLING(gss_init_sec_context);
288         gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
289                                 GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
290                                 NULL, &token, &retflags, NULL);
291         DONE();
292         /* Ignore success/failure indication.  */
293         if (token.length) {
294             CALLING(gss_release_buffer);
295             release_buffer(&gmin, &token);
296             DONE();
297         }
298         CALLING(gss_release_name);
299         release_name(&gmin, &target);
300         DONE();
301         if (gctx != GSS_C_NO_CONTEXT) {
302             CALLING(gss_delete_sec_context);
303             delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
304             DONE();
305         }
306     }
307     do_close(gsslib);
308
309     /* Test gssapi_krb5 with com_err already loaded, then unload
310        com_err first.  */
311     celib = do_open("com_err", "3.0", 1);
312     gsslib = do_open("gssapi_krb5", "2.2", 1);
313     {
314         OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
315                                                     gss_ctx_id_t *, gss_name_t,
316                                                     gss_OID,
317                                                     OM_uint32, OM_uint32,
318                                                     gss_channel_bindings_t,
319                                                     gss_buffer_t, gss_OID *,
320                                                     gss_buffer_t,
321                                                     OM_uint32 *, OM_uint32 *)
322             = get_gfun(gsslib, "gss_init_sec_context");
323         OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
324                                                gss_OID, gss_name_t *)
325             = get_gfun(gsslib, "gss_import_name");
326         OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
327             = get_gfun(gsslib, "gss_release_buffer");
328         OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
329             = get_gfun(gsslib, "gss_release_name");
330         OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
331                                                       gss_ctx_id_t *,
332                                                       gss_buffer_t)
333             = get_gfun(gsslib, "gss_delete_sec_context");
334
335         OM_uint32 gmaj, gmin;
336         OM_uint32 retflags;
337         gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
338         gss_buffer_desc token;
339         gss_name_t target;
340         static gss_buffer_desc target_name_buf = {
341             9, "x@mit.edu"
342         };
343         static gss_OID_desc service_name = {
344             10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
345         };
346
347         CALLING(gss_import_name);
348         gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
349         DONE();
350         if (gmaj != GSS_S_COMPLETE) {
351             fprintf(stderr,
352                     "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
353                     (unsigned long) gmaj, (unsigned long) gmin,
354                     (signed long) gmin);
355             exit(1);
356         }
357         /* This will probably get different errors, depending on
358            whether we have tickets at the time.  Doesn't matter much,
359            we're ignoring the error and testing whether we're doing
360            cleanup properly.  (Though the internal cleanup needed in
361            the two cases might be different.)  */
362         CALLING(gss_init_sec_context);
363         gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
364                                 GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
365                                 NULL, &token, &retflags, NULL);
366         DONE();
367         /* Ignore success/failure indication.  */
368         if (token.length) {
369             CALLING(gss_release_buffer);
370             release_buffer(&gmin, &token);
371             DONE();
372         }
373         CALLING(gss_release_name);
374         release_name(&gmin, &target);
375         DONE();
376         if (gctx != GSS_C_NO_CONTEXT) {
377             CALLING(gss_delete_sec_context);
378             delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
379             DONE();
380         }
381     }
382     do_close(celib);
383     do_close(gsslib);
384
385     return 0;
386 }