-: 0:Source:plugin.c -: 0:Graph:/var/tsitkova/Sources/v10/trunk/src/lib/krb5/krb/plugin.so.gcno -: 0:Data:/var/tsitkova/Sources/v10/trunk/src/lib/krb5/krb/plugin.so.gcda -: 0:Runs:1602 -: 0:Programs:1 -: 1:/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -: 2:/* lib/krb5/krb/plugin.c - Plugin framework functions */ -: 3:/* -: 4: * Copyright (C) 2010 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-int.h" -: 28: -: 29:const char *interface_names[] = { -: 30: "pwqual", -: 31: "kadm5_hook", -: 32: "clpreauth", -: 33: "kdcpreauth", -: 34: "ccselect" -: 35:}; -: 36: -: 37:/* Return the context's interface structure for id, or NULL if invalid. */ -: 38:static inline struct plugin_interface * 5337: 39:get_interface(krb5_context context, int id) -: 40:{ 5337: 41: if (context == NULL || id < 0 || id >= PLUGIN_NUM_INTERFACES) #####: 42: return NULL; 5337: 43: return &context->plugins[id]; -: 44:} -: 45: -: 46:/* Release the memory associated with the linked list entry map. */ -: 47:static void 3645: 48:free_plugin_mapping(struct plugin_mapping *map) -: 49:{ 3645: 50: if (map == NULL) #####: 51: return; 3645: 52: free(map->modname); 3645: 53: if (map->dyn_handle != NULL) 293: 54: krb5int_close_plugin(map->dyn_handle); 3645: 55: free(map); -: 56:} -: 57: -: 58:/* -: 59: * Register a mapping from modname to module. On success, dyn_handle is -: 60: * remembered in the mapping and will be released when the mapping is -: 61: * overwritten or the context is destroyed. -: 62: */ -: 63:static krb5_error_code 3658: 64:register_module(krb5_context context, struct plugin_interface *interface, -: 65: const char *modname, krb5_plugin_initvt_fn module, -: 66: struct plugin_file_handle *dyn_handle) -: 67:{ -: 68: struct plugin_mapping *map, **pmap; -: 69: -: 70: /* If a mapping already exists for modname, remove it. */ 8554: 71: for (pmap = &interface->modules; *pmap != NULL; pmap = &(*pmap)->next) { 4896: 72: map = *pmap; 4896: 73: if (strcmp(map->modname, modname) == 0) { #####: 74: *pmap = map->next; #####: 75: free_plugin_mapping(map); #####: 76: break; -: 77: } -: 78: } -: 79: -: 80: /* Create a new mapping structure. */ 3658: 81: map = malloc(sizeof(*map)); 3658: 82: if (map == NULL) #####: 83: return ENOMEM; 3658: 84: map->modname = strdup(modname); 3658: 85: if (map->modname == NULL) { #####: 86: free(map); #####: 87: return ENOMEM; -: 88: } 3658: 89: map->module = module; 3658: 90: map->dyn_handle = dyn_handle; -: 91: -: 92: /* Chain it into the list. */ 3658: 93: map->next = interface->modules; 3658: 94: interface->modules = map; 3658: 95: return 0; -: 96:} -: 97: -: 98:/* Parse a profile module string of the form "modname:modpath" into its -: 99: * component parts. */ -: 100:static krb5_error_code 3: 101:parse_modstr(krb5_context context, const char *modstr, -: 102: char **modname, char **modpath) -: 103:{ -: 104: const char *sep; 3: 105: char *name = NULL, *path = NULL; -: 106: 3: 107: *modname = NULL; 3: 108: *modpath = NULL; -: 109: 3: 110: sep = strchr(modstr, ':'); 3: 111: if (sep == NULL) { #####: 112: krb5_set_error_message(context, KRB5_PLUGIN_BAD_MODULE_SPEC, #####: 113: _("Invalid module specifier %s"), modstr); #####: 114: return KRB5_PLUGIN_BAD_MODULE_SPEC; -: 115: } -: 116: -: 117: /* Copy the module name. */ 3: 118: name = malloc(sep - modstr + 1); 3: 119: if (name == NULL) #####: 120: return ENOMEM; 3: 121: memcpy(name, modstr, sep - modstr); 3: 122: name[sep - modstr] = '\0'; -: 123: -: 124: /* Copy the module path. */ 3: 125: path = strdup(sep + 1); 3: 126: if (path == NULL) { #####: 127: free(name); #####: 128: return ENOMEM; -: 129: } -: 130: 3: 131: *modname = name; 3: 132: *modpath = path; 3: 133: return 0; -: 134:} -: 135: -: 136:/* Return true if value is found in list. */ -: 137:static krb5_boolean #####: 138:find_in_list(char **list, const char *value) -: 139:{ #####: 140: for (; *list != NULL; list++) { #####: 141: if (strcmp(*list, value) == 0) #####: 142: return TRUE; -: 143: } #####: 144: return FALSE; -: 145:} -: 146: -: 147:/* Return true if module is not filtered out by enable or disable lists. */ -: 148:static krb5_boolean 3658: 149:module_enabled(const char *modname, char **enable, char **disable) -: 150:{ 3658: 151: return ((enable == NULL || find_in_list(enable, modname)) && #####: 152: (disable == NULL || !find_in_list(disable, modname))); -: 153:} -: 154: -: 155:/* Remove any registered modules whose names are filtered out. */ -: 156:static void 1682: 157:filter_builtins(krb5_context context, struct plugin_interface *interface, -: 158: char **enable, char **disable) -: 159:{ -: 160: struct plugin_mapping *map, **pmap; -: 161: 1682: 162: pmap = &interface->modules; 7019: 163: while (*pmap != NULL) { 3655: 164: map = *pmap; 3655: 165: if (!module_enabled(map->modname, enable, disable)) { #####: 166: *pmap = map->next; #####: 167: free_plugin_mapping(map); -: 168: } else 3655: 169: pmap = &map->next; -: 170: } 1682: 171:} -: 172: -: 173:static krb5_error_code 294: 174:register_dyn_module(krb5_context context, struct plugin_interface *interface, -: 175: const char *iname, const char *modname, const char *path) -: 176:{ -: 177: krb5_error_code ret; 294: 178: char *symname = NULL; 294: 179: struct plugin_file_handle *handle = NULL; -: 180: void (*initvt_fn)(); -: 181: -: 182: /* Construct the initvt symbol name for this interface and module. */ 294: 183: if (asprintf(&symname, "%s_%s_initvt", iname, modname) < 0) { #####: 184: symname = NULL; #####: 185: ret = ENOMEM; #####: 186: goto cleanup; -: 187: } -: 188: -: 189: /* Open the plugin and resolve the initvt symbol. */ 294: 190: ret = krb5int_open_plugin(path, &handle, &context->err); 294: 191: if (ret != 0) #####: 192: goto cleanup; 294: 193: ret = krb5int_get_plugin_func(handle, symname, &initvt_fn, &context->err); 294: 194: if (ret != 0) #####: 195: goto cleanup; -: 196: -: 197: /* Create a mapping for the module. */ 294: 198: ret = register_module(context, interface, modname, -: 199: (krb5_plugin_initvt_fn)initvt_fn, handle); 294: 200: if (ret != 0) #####: 201: goto cleanup; 294: 202: handle = NULL; /* Now owned by the module mapping. */ -: 203: -: 204:cleanup: 294: 205: free(symname); 294: 206: if (handle != NULL) #####: 207: krb5int_close_plugin(handle); 294: 208: return ret; -: 209:} -: 210: -: 211:/* Register the plugin module given by the profile string mod, if enabled -: 212: * according to the values of enable and disable. */ -: 213:static krb5_error_code 3: 214:register_dyn_mapping(krb5_context context, struct plugin_interface *interface, -: 215: const char *iname, const char *modstr, char **enable, -: 216: char **disable) -: 217:{ -: 218: krb5_error_code ret; 3: 219: char *modname = NULL, *modpath = NULL, *fullpath = NULL; -: 220: -: 221: /* Parse out the module name and path, and make sure it is enabled. */ 3: 222: ret = parse_modstr(context, modstr, &modname, &modpath); 3: 223: if (ret != 0) #####: 224: goto cleanup; -: 225: /* Treat non-absolute modpaths as relative to the plugin base directory. */ 3: 226: ret = k5_path_join(context->plugin_base_dir, modpath, &fullpath); 3: 227: if (ret != 0) #####: 228: goto cleanup; 3: 229: if (!module_enabled(modname, enable, disable)) #####: 230: goto cleanup; 3: 231: ret = register_dyn_module(context, interface, iname, modname, fullpath); -: 232: -: 233:cleanup: 3: 234: free(modname); 3: 235: free(modpath); 3: 236: free(fullpath); 3: 237: return ret; -: 238:} -: 239: -: 240:/* Ensure that a plugin interface is configured. id is assumed to be valid. */ -: 241:static krb5_error_code 1682: 242:configure_interface(krb5_context context, int id) -: 243:{ -: 244: krb5_error_code ret; 1682: 245: struct plugin_interface *interface = &context->plugins[id]; 1682: 246: const char *iname = interface_names[id]; 1682: 247: char **modules = NULL, **enable = NULL, **disable = NULL, **mod; -: 248: static const char *path[4]; -: 249: 1682: 250: if (interface->configured) #####: 251: return 0; -: 252: -: 253: /* Detect consistency errors when plugin interfaces are added. */ -: 254: assert(sizeof(interface_names) / sizeof(*interface_names) == -: 255: PLUGIN_NUM_INTERFACES); -: 256: -: 257: /* Read the configuration variables for this interface. */ 1682: 258: path[0] = KRB5_CONF_PLUGINS; 1682: 259: path[1] = iname; 1682: 260: path[2] = KRB5_CONF_MODULE; 1682: 261: path[3] = NULL; 1682: 262: ret = profile_get_values(context->profile, path, &modules); 1682: 263: if (ret != 0 && ret != PROF_NO_RELATION) #####: 264: goto cleanup; 1682: 265: path[2] = KRB5_CONF_ENABLE_ONLY; 1682: 266: ret = profile_get_values(context->profile, path, &enable); 1682: 267: if (ret != 0 && ret != PROF_NO_RELATION) #####: 268: goto cleanup; 1682: 269: path[2] = KRB5_CONF_DISABLE; 1682: 270: ret = profile_get_values(context->profile, path, &disable); 1682: 271: if (ret != 0 && ret != PROF_NO_RELATION) #####: 272: goto cleanup; -: 273: -: 274: /* Remove built-in modules which are filtered out by configuration. */ 1682: 275: filter_builtins(context, interface, enable, disable); -: 276: -: 277: /* Create mappings for dynamic modules which aren't filtered out. */ 1685: 278: for (mod = modules; mod && *mod; mod++) { 3: 279: ret = register_dyn_mapping(context, interface, iname, *mod, -: 280: enable, disable); 3: 281: if (ret != 0) #####: 282: return ret; -: 283: } -: 284: 1682: 285: ret = 0; -: 286:cleanup: 1682: 287: profile_free_list(modules); 1682: 288: profile_free_list(enable); 1682: 289: profile_free_list(disable); 1682: 290: return ret; -: 291:} -: 292: -: 293:krb5_error_code #####: 294:k5_plugin_load(krb5_context context, int interface_id, const char *modname, -: 295: krb5_plugin_initvt_fn *module) -: 296:{ -: 297: krb5_error_code ret; #####: 298: struct plugin_interface *interface = get_interface(context, interface_id); -: 299: struct plugin_mapping *map; -: 300: #####: 301: if (interface == NULL) #####: 302: return EINVAL; #####: 303: ret = configure_interface(context, interface_id); #####: 304: if (ret != 0) #####: 305: return ret; #####: 306: for (map = interface->modules; map != NULL; map = map->next) { #####: 307: if (strcmp(map->modname, modname) == 0) { #####: 308: *module = map->module; #####: 309: return 0; -: 310: } -: 311: } #####: 312: krb5_set_error_message(context, KRB5_PLUGIN_NAME_NOTFOUND, #####: 313: _("Could not find %s plugin module named '%s'"), -: 314: interface_names[interface_id], modname); #####: 315: return KRB5_PLUGIN_NAME_NOTFOUND; -: 316:} -: 317: -: 318:krb5_error_code 1682: 319:k5_plugin_load_all(krb5_context context, int interface_id, -: 320: krb5_plugin_initvt_fn **modules) -: 321:{ -: 322: krb5_error_code ret; 1682: 323: struct plugin_interface *interface = get_interface(context, interface_id); -: 324: struct plugin_mapping *map; -: 325: krb5_plugin_initvt_fn *list; -: 326: size_t count; -: 327: 1682: 328: if (interface == NULL) #####: 329: return EINVAL; 1682: 330: ret = configure_interface(context, interface_id); 1682: 331: if (ret != 0) #####: 332: return ret; -: 333: -: 334: /* Count the modules and allocate a list to hold them. */ 1682: 335: count = 0; 5340: 336: for (map = interface->modules; map != NULL; map = map->next) 3658: 337: count++; 1682: 338: list = malloc((count + 1) * sizeof(*list)); 1682: 339: if (list == NULL) #####: 340: return ENOMEM; -: 341: -: 342: /* Place each module's initvt function into list. */ 1682: 343: count = 0; 5340: 344: for (map = interface->modules; map != NULL; map = map->next) 3658: 345: list[count++] = map->module; 1682: 346: list[count] = NULL; -: 347: 1682: 348: *modules = list; 1682: 349: return 0; -: 350:} -: 351: -: 352:void 1682: 353:k5_plugin_free_modules(krb5_context context, krb5_plugin_initvt_fn *modules) -: 354:{ 1682: 355: free(modules); 1682: 356:} -: 357: -: 358:krb5_error_code 3364: 359:k5_plugin_register(krb5_context context, int interface_id, const char *modname, -: 360: krb5_plugin_initvt_fn module) -: 361:{ 3364: 362: struct plugin_interface *interface = get_interface(context, interface_id); -: 363: 3364: 364: if (interface == NULL) #####: 365: return EINVAL; -: 366: -: 367: /* Disallow registering plugins after load. We may need to reconsider -: 368: * this, but it simplifies the design. */ 3364: 369: if (interface->configured) #####: 370: return EINVAL; -: 371: 3364: 372: return register_module(context, interface, modname, module, NULL); -: 373:} -: 374: -: 375:krb5_error_code 291: 376:k5_plugin_register_dyn(krb5_context context, int interface_id, -: 377: const char *modname, const char *modsubdir) -: 378:{ -: 379: krb5_error_code ret; 291: 380: struct plugin_interface *interface = get_interface(context, interface_id); -: 381: char *path; -: 382: -: 383: /* Disallow registering plugins after load. */ 291: 384: if (interface == NULL || interface->configured) #####: 385: return EINVAL; 291: 386: if (asprintf(&path, "%s/%s/%s%s", context->plugin_base_dir, modsubdir, -: 387: modname, PLUGIN_EXT) < 0) #####: 388: return ENOMEM; -: 389: 291: 390: ret = register_dyn_module(context, interface, -: 391: interface_names[interface_id], modname, path); 291: 392: free(path); 291: 393: return ret; -: 394:} -: 395: -: 396:void 8263: 397:k5_plugin_free_context(krb5_context context) -: 398:{ -: 399: int i; -: 400: struct plugin_interface *interface; -: 401: struct plugin_mapping *map, *next; -: 402: 49578: 403: for (i = 0; i < PLUGIN_NUM_INTERFACES; i++) { 41315: 404: interface = &context->plugins[i]; 44960: 405: for (map = interface->modules; map != NULL; map = next) { 3645: 406: next = map->next; 3645: 407: free_plugin_mapping(map); -: 408: } 41315: 409: interface->modules = NULL; 41315: 410: interface->configured = FALSE; -: 411: } 8263: 412:}