xref: /illumos-gate/usr/src/lib/libkmf/libkmf/common/mapping.c (revision 269e59f9a28bf47e0f463e64fc5af4a408b73b21)
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
cleanup_mapper(KMF_HANDLE_T handle)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 *
get_mapper_pathname(char * name,char * dir)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
open_mapper_library(KMF_MAPPER_RECORD * map)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
kmf_cert_to_name_mapping_initialize(KMF_HANDLE_T handle,int numattr,KMF_ATTRIBUTE * attrlist)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
kmf_cert_to_name_mapping_finalize(KMF_HANDLE_T handle)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
kmf_map_cert_to_name(KMF_HANDLE_T handle,KMF_DATA * cert,KMF_DATA * name)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
kmf_match_cert_to_name(KMF_HANDLE_T handle,KMF_DATA * cert,KMF_DATA * name_to_match,KMF_DATA * mapped_name)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
kmf_get_mapper_error_str(KMF_HANDLE_T handle,char ** errstr)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
kmf_set_mapper_lasterror(KMF_HANDLE_T handle,uint32_t err)384 kmf_set_mapper_lasterror(KMF_HANDLE_T handle, uint32_t err)
385 {
386 	handle->mapstate->lastmappererr = err;
387 }
388 
389 uint32_t
kmf_get_mapper_lasterror(KMF_HANDLE_T handle)390 kmf_get_mapper_lasterror(KMF_HANDLE_T handle)
391 {
392 	return (handle->mapstate->lastmappererr);
393 }
394 
395 void
kmf_set_mapper_options(KMF_HANDLE_T handle,void * opts)396 kmf_set_mapper_options(KMF_HANDLE_T handle, void *opts)
397 {
398 	handle->mapstate->options = opts;
399 }
400 
401 void *
kmf_get_mapper_options(KMF_HANDLE_T handle)402 kmf_get_mapper_options(KMF_HANDLE_T handle)
403 {
404 	return (handle->mapstate->options);
405 }
406