1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 22 * 23 * This file implements the KMF certificate to name mapping framework. 24 */ 25 #include <stdlib.h> 26 #include <string.h> 27 #include <dlfcn.h> 28 #include <libgen.h> 29 #include <kmftypes.h> 30 #include <kmfapiP.h> 31 32 /* Mappers go in the same dir as plugins. */ 33 #define DEFAULT_MAPPER_DIR KMF_PLUGIN_PATH 34 35 static void 36 cleanup_mapper(KMF_HANDLE_T handle) 37 { 38 KMF_MAPPER_RECORD *mapper = &handle->policy->mapper; 39 void (*finalize)(KMF_HANDLE_T); 40 41 if (mapper->curpathname != NULL) { 42 free(mapper->curpathname); 43 mapper->curpathname = NULL; 44 } 45 if (mapper->curoptions != NULL) { 46 free(mapper->curoptions); 47 mapper->curoptions = NULL; 48 } 49 if (mapper->dldesc != NULL) { 50 finalize = (void(*)())dlsym(mapper->dldesc, 51 MAPPER_FINISH_FUNCTION); 52 /* Optional, not an error if it does not exist. */ 53 if (finalize != NULL) 54 finalize(handle); 55 56 (void) dlclose(mapper->dldesc); 57 mapper->dldesc = NULL; 58 } 59 } 60 61 /* The caller is expected to free the returned string. */ 62 char * 63 get_mapper_pathname(char *name, char *dir) 64 { 65 char *pathname = NULL; 66 int len; 67 68 if (name == NULL) 69 return (NULL); 70 71 if (dir == NULL) 72 dir = DEFAULT_MAPPER_DIR; 73 74 /* 75 * MAPPER_NAME_TEMPLATE has 2 extra characters (%s) which make up for 76 * the "/" and the terminating NULL when computing the total length. 77 */ 78 len = strlen(name) + strlen(MAPPER_NAME_TEMPLATE) + strlen(dir); 79 80 pathname = malloc(len); 81 if (pathname == NULL) 82 return (NULL); 83 (void) memset(pathname, 0, len); 84 /* Avoid double forward slash if the dir's last character is "/". */ 85 (void) snprintf(pathname, len, "%s%s" MAPPER_NAME_TEMPLATE, 86 dir, dir[strlen(dir) - 1] == '/' ? "" : "/", name); 87 88 return (pathname); 89 } 90 91 static KMF_RETURN 92 open_mapper_library(KMF_MAPPER_RECORD *map) 93 { 94 KMF_RETURN ret = KMF_OK; 95 96 map->dldesc = dlopen(map->curpathname, RTLD_LAZY | RTLD_PARENT); 97 if (map->dldesc == NULL) 98 return (KMF_ERR_MAPPER_OPEN); 99 100 return (ret); 101 } 102 103 /* 104 * The mapping framework uses either attributes or the policy file. Those two 105 * sources are never mixed. We always need a mapper name or a mapper pathname 106 * but these two are mutually exclusive. Directory can be set only if name is 107 * set. 108 */ 109 KMF_RETURN 110 kmf_cert_to_name_mapping_initialize(KMF_HANDLE_T handle, int numattr, 111 KMF_ATTRIBUTE *attrlist) 112 { 113 KMF_RETURN ret = KMF_OK; 114 KMF_RETURN (*initialize)(KMF_HANDLE_T, char *); 115 KMF_MAPPER_RECORD *map = NULL; 116 char *dir = NULL; 117 char *name = NULL; 118 char *opts = NULL; 119 char *path = NULL; 120 char *tmppath = NULL; 121 char *old_curpathname = NULL; 122 char *old_curoptions = NULL; 123 124 if (handle == NULL) 125 return (KMF_ERR_BAD_PARAMETER); 126 127 map = &handle->policy->mapper; 128 old_curpathname = map->curpathname; 129 old_curoptions = map->curoptions; 130 131 name = kmf_get_attr_ptr(KMF_MAPPER_NAME_ATTR, attrlist, numattr); 132 dir = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr); 133 path = kmf_get_attr_ptr(KMF_MAPPER_PATH_ATTR, attrlist, numattr); 134 opts = kmf_get_attr_ptr(KMF_MAPPER_OPTIONS_ATTR, attrlist, numattr); 135 136 if (path != NULL) { 137 /* Mutually exclusive. */ 138 if (name != NULL || dir != NULL) 139 return (KMF_ERR_BAD_PARAMETER); 140 tmppath = strdup(path); 141 if (tmppath == NULL) 142 return (KMF_ERR_MEMORY); 143 /* If we only have a name and possibly a dir, we can find the path. */ 144 } else if (name != NULL) { 145 tmppath = get_mapper_pathname(name, dir); 146 /* 147 * If we were given name but the returned path is still NULL, 148 * return an error. 149 */ 150 if (tmppath == NULL) 151 return (KMF_ERR_MEMORY); 152 /* Can not exist standalone. */ 153 } else if (dir != NULL || opts != NULL) { 154 return (KMF_ERR_BAD_PARAMETER); 155 /* No attributes define the mapper so let's use the policy database. */ 156 } else if (map->pathname != NULL) { 157 tmppath = strdup(map->pathname); 158 if (tmppath == NULL) 159 return (KMF_ERR_MEMORY); 160 opts = map->options; 161 } else if (map->mapname != NULL) { 162 tmppath = get_mapper_pathname(map->mapname, map->dir); 163 /* 164 * If we were given name but the returned path is still NULL, 165 * return an error. 166 */ 167 if (tmppath == NULL) 168 return (KMF_ERR_MEMORY); 169 opts = map->options; 170 } else { 171 /* 172 * Either a name or a full pathname must be provided whether 173 * from attributes or the policy database. 174 */ 175 return (KMF_ERR_BAD_PARAMETER); 176 } 177 178 /* 179 * Dlopen the mapper specified by the policy. If anything goes wrong 180 * just return an error. We do not have to worry about resetting 181 * curpathname and curoptions to the previous values since there was no 182 * mapper initialized beforehand. 183 * 184 * No mapper was open so stored curoptions and curpathname are 185 * already NULL and need not to be freed. 186 */ 187 if (map->dldesc == NULL) { 188 map->curpathname = tmppath; 189 if (opts != NULL) { 190 map->curoptions = strdup(opts); 191 if (map->curoptions == NULL) { 192 free(map->curpathname); 193 map->curpathname = NULL; 194 return (KMF_ERR_MEMORY); 195 } 196 } else 197 map->curoptions = NULL; 198 199 if ((ret = open_mapper_library(map)) != KMF_OK) { 200 free(map->curpathname); 201 map->curpathname = NULL; 202 if (map->curoptions != NULL) { 203 free(map->curoptions); 204 map->curoptions = NULL; 205 } 206 return (ret); 207 } 208 209 goto end; 210 } 211 212 /* 213 * We already have an open mapper, let's see if this is a new mapper 214 * library. 215 */ 216 if (map->curpathname != NULL && 217 /* No change in mapper pathname. */ 218 strcmp(map->curpathname, tmppath) == 0) { 219 /* New options are empty while we had some before. */ 220 if (map->curoptions != NULL && opts == NULL) { 221 map->curoptions = NULL; 222 /* We have some options now while we had none before. */ 223 } else if (map->curoptions == NULL && opts != NULL) { 224 if ((map->curoptions = strdup(opts)) == NULL) 225 goto err_mem; 226 /* We got different options. */ 227 } else if (strcmp(map->curoptions, opts) != 0) { 228 if ((map->curoptions = strdup(opts)) == NULL) 229 goto err_mem; 230 } else { 231 /* 232 * Same options, no free() of current options is 233 * required. 234 */ 235 old_curoptions = NULL; 236 } 237 238 /* Free old options if applicable. */ 239 if (old_curoptions != NULL) 240 free(old_curoptions); 241 } else { 242 /* 243 * This is a new mapper path, clean up the old data and open the 244 * new mapper. 245 */ 246 cleanup_mapper(handle); 247 /* These two are no longer valid. */ 248 old_curoptions = NULL; 249 old_curpathname = NULL; 250 map->curpathname = tmppath; 251 if (opts != NULL) { 252 map->curoptions = strdup(opts); 253 if (map->curoptions == NULL) 254 goto err_mem; 255 } 256 if ((ret = open_mapper_library(map)) != KMF_OK) { 257 /* 258 * This will cleanup curoptions and curpathname, and 259 * ignores the dldesc since it is NULL. Do not free 260 * tmppath, it will be freed through map->curpathname. 261 */ 262 cleanup_mapper(handle); 263 return (ret); 264 } 265 } 266 267 end: 268 initialize = (KMF_RETURN(*)())dlsym(map->dldesc, 269 MAPPER_INIT_FUNCTION); 270 /* Optional, not an error if it does not exist. */ 271 ret = KMF_OK; 272 if (initialize != NULL) 273 ret = initialize(handle, map->curoptions); 274 275 if (ret != KMF_OK) 276 cleanup_mapper(handle); 277 278 return (ret); 279 280 err_mem: 281 /* 282 * Try to put the old curpathname and curoptions back there. In theory, 283 * the application might be able to continue to use the old mapping 284 * unless we already called cleanup_mapper(). However, it's neither 285 * recommended nor officially supported. The app should initialize the 286 * old mapping again. 287 */ 288 if (tmppath != NULL) 289 free(tmppath); 290 map->curoptions = old_curoptions; 291 map->curpathname = old_curpathname; 292 return (KMF_ERR_MEMORY); 293 } 294 295 KMF_RETURN 296 kmf_cert_to_name_mapping_finalize(KMF_HANDLE_T handle) 297 { 298 if (handle == NULL) 299 return (KMF_ERR_BAD_PARAMETER); 300 301 cleanup_mapper(handle); 302 303 return (KMF_OK); 304 } 305 306 KMF_RETURN 307 kmf_map_cert_to_name(KMF_HANDLE_T handle, KMF_DATA *cert, KMF_DATA *name) 308 { 309 KMF_MAPPER_RECORD *map = NULL; 310 KMF_RETURN (*cert2name)(KMF_HANDLE *, KMF_DATA *, KMF_DATA *); 311 312 if (handle == NULL) 313 return (KMF_ERR_BAD_PARAMETER); 314 315 map = &handle->policy->mapper; 316 if (map->dldesc == NULL) 317 return (KMF_ERR_MAPPER_NOT_FOUND); 318 319 cert2name = (KMF_RETURN(*)())dlsym(map->dldesc, 320 MAP_CERT_TO_NAME_FUNCTION); 321 if (cert2name == NULL) 322 return (KMF_ERR_FUNCTION_NOT_FOUND); 323 324 return (cert2name(handle, cert, name)); 325 } 326 327 /* 328 * If mapped_name is non-NULL the caller is later expected to free its Data 329 * after use. 330 */ 331 KMF_RETURN 332 kmf_match_cert_to_name(KMF_HANDLE_T handle, KMF_DATA *cert, 333 KMF_DATA *name_to_match, KMF_DATA *mapped_name) 334 { 335 KMF_MAPPER_RECORD *map = NULL; 336 KMF_RETURN (*cert2name)(KMF_HANDLE *, KMF_DATA *, KMF_DATA *, 337 KMF_DATA *); 338 339 if (handle == NULL) 340 return (KMF_ERR_BAD_PARAMETER); 341 342 map = &handle->policy->mapper; 343 344 if (map->curpathname == NULL || map->dldesc == NULL) 345 return (KMF_ERR_MAPPER_NOT_FOUND); 346 347 cert2name = (KMF_RETURN(*)())dlsym(map->dldesc, 348 MATCH_CERT_TO_NAME_FUNCTION); 349 if (cert2name == NULL) 350 return (KMF_ERR_FUNCTION_NOT_FOUND); 351 352 return (cert2name(handle, cert, name_to_match, mapped_name)); 353 } 354 355 /* 356 * The caller is responsible for freeing the error string (ie., *errstr) when 357 * done with it. 358 */ 359 KMF_RETURN 360 kmf_get_mapper_error_str(KMF_HANDLE_T handle, char **errstr) 361 { 362 KMF_HANDLE *h = NULL; 363 KMF_MAPPER_RECORD *map = NULL; 364 KMF_RETURN (*err2string)(KMF_HANDLE *, char **); 365 366 if (handle == NULL || errstr == NULL) 367 return (KMF_ERR_BAD_PARAMETER); 368 369 h = (KMF_HANDLE *)handle; 370 map = &(h->policy->mapper); 371 372 if (map->curpathname == NULL || map->dldesc == NULL) 373 return (KMF_ERR_MAPPER_NOT_FOUND); 374 375 err2string = (KMF_RETURN(*)())dlsym(map->dldesc, 376 MAPPER_ERROR_STRING_FUNCTION); 377 if (err2string == NULL) 378 return (KMF_ERR_FUNCTION_NOT_FOUND); 379 380 return (err2string(h, errstr)); 381 } 382 383 void 384 kmf_set_mapper_lasterror(KMF_HANDLE_T handle, uint32_t err) 385 { 386 handle->mapstate->lastmappererr = err; 387 } 388 389 uint32_t 390 kmf_get_mapper_lasterror(KMF_HANDLE_T handle) 391 { 392 return (handle->mapstate->lastmappererr); 393 } 394 395 void 396 kmf_set_mapper_options(KMF_HANDLE_T handle, void *opts) 397 { 398 handle->mapstate->options = opts; 399 } 400 401 void * 402 kmf_get_mapper_options(KMF_HANDLE_T handle) 403 { 404 return (handle->mapstate->options); 405 } 406