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 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