xref: /freebsd/crypto/krb5/src/tests/shlib/t_loader.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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