xref: /illumos-gate/usr/src/cmd/ldap/ns_ldap/mapping.c (revision b446700b)
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 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <ctype.h>
29 #include <libintl.h>
30 #include <strings.h>
31 #include <stdio.h>
32 #include "../../../lib/libsldap/common/ns_sldap.h"
33 
34 
35 #define	SAME	0
36 
37 struct mapping {
38 	char *database;
39 	char *def_type;
40 	char *objectclass;
41 	char *actual_db;
42 };
43 
44 #define	PUBLICKEY	0
45 
46 static struct mapping maplist[] = {
47 	{"publickey", "uidnumber", "niskeyobject", "passwd"},
48 	{"publickey", "cn", "niskeyobject", "host"},
49 	{"bootparams", "cn", "bootableDevice", NULL},
50 	{"ethers", "cn", "ieee802Device", NULL},
51 	{"group", "cn", "posixgroup", NULL},
52 	{"hosts", "cn", "iphost", NULL},
53 	{"ipnodes", "cn", "iphost", NULL},
54 	{"netgroup", "cn", "nisnetgroup", NULL},
55 	{"netmasks", "ipnetworknumber", "ipnetwork", NULL},
56 	{"networks", "ipnetworknumber", "ipnetwork", NULL},
57 	{"passwd", "uid", "posixaccount", NULL},
58 	{"protocols", "cn", "ipprotocol", NULL},
59 	{"rpc", "cn", "oncrpc", NULL},
60 	{"services", "cn", "ipservice", NULL},
61 	{"aliases", "cn", "mailGroup", NULL},
62 	{"project", "SolarisProjectID", "SolarisProject", NULL},
63 	{"printers", "printer-uri", "sunPrinter", NULL},
64 	{"shadow", "uid", "shadowaccount", NULL},
65 	{"auth_attr", "cn", "SolarisAuthAttr", NULL},
66 	{"prof_attr", "cn", "SolarisProfAttr", NULL},
67 	{"exec_attr", "cn", "SolarisExecAttr", NULL},
68 	{"user_attr", "uid", "SolarisUserAttr", NULL},
69 	{"audit_user", "uid", "SolarisAuditUser", NULL},
70 	{NULL, NULL, NULL, NULL}
71 };
72 
73 /* Malloc and print error message in case of failure */
74 #define	MALLOC(ptr, len) \
75 	if ((ptr = (char *)malloc(len)) == NULL) { \
76 		(void) fprintf(stderr, gettext("out of memory\n")); \
77 	}
78 
79 /*
80  * Allocate memory for filter and user data. Set
81  * error to 1 if either of the mallocs fail.
82  * In addition, free the memory allocated for filter,
83  * if memory allocation for user data fails.
84  */
85 #define	MALLOC_FILTER_UDATA(ptr1, len1, ptr2, len2, error) \
86 	error = 0; \
87 	MALLOC(ptr1, len1); \
88 	if (!ptr1) { \
89 		error = 1; \
90 	} \
91 	else { \
92 		MALLOC(ptr2, len2); \
93 		if (!ptr2) { \
94 			error = 1; \
95 			free(ptr1); \
96 		} \
97 	}
98 
99 void
100 printMapping()
101 {
102 	int	i;
103 
104 	(void) fprintf(stdout,
105 		gettext("database       default type        objectclass\n"));
106 	(void) fprintf(stdout,
107 		gettext("=============  =================   =============\n"));
108 	/* first dump auto_* and automount which are not in maplist[] */
109 	(void) fprintf(stdout, "%-15s%-20s%s\n", "auto_*", "automountKey",
110 		"automount");
111 	(void) fprintf(stdout, "%-15s%-20s%s\n", "automount",
112 		"automountMapName",
113 		"automountMap");
114 	for (i = 0; maplist[i].database != NULL; i++) {
115 	/* skip printing shadow */
116 	if (strcasecmp(maplist[i].database, "shadow") != 0)
117 		(void) fprintf(stdout, "%-15s%-20s%s\n", maplist[i].database,
118 			maplist[i].def_type, maplist[i].objectclass);
119 	}
120 }
121 
122 /*
123  * set_key routine to handle user specified keys.
124  * A key can be of the form: attribute=value or value.
125  * A filter is constructed from a set of keys specified in
126  * the form (|(key1)(key2)...(keyn))
127  * It returns: NULL if no keys are defined or
128  *		the keyfilter as constructed above.
129  */
130 
131 char *
132 set_keys(char **key, char *attrtype)
133 {
134 	char	*keyeq = NULL;
135 	char	*keyfilter = NULL;
136 	int	len, totlen = 1; /* Terminating NULL byte */
137 	char	*k, **karray;
138 	char	*tmpptr;
139 
140 	if (!key || !key[0])	/* should never contain NULL string */
141 		return (NULL);
142 
143 	if (key[1]) {
144 		totlen += 3;
145 		/* Allocate memory for '(|)' */
146 		MALLOC(keyfilter, totlen);
147 		if (!keyfilter)
148 			exit(2);
149 		(void) snprintf(keyfilter, totlen, "(|");
150 	}
151 
152 	karray = key;
153 	while ((k = *karray) != 0) {
154 		keyeq = strchr(k, '=');
155 		if (keyeq) {
156 			/* make enough room for (%s) */
157 			totlen += strlen(k) + 2;
158 		} else {
159 			/* make enough room for (%s=%s) */
160 			totlen += strlen(attrtype) + strlen(k) + 3;
161 		}
162 
163 		len = keyfilter ? strlen(keyfilter) : 0;
164 
165 		if (!(tmpptr = (char *)realloc(keyfilter, totlen))) {
166 			if (keyfilter)
167 				free(keyfilter);
168 			(void) fprintf(stderr, gettext("out of memory\n"));
169 			exit(2);
170 		}
171 		keyfilter = tmpptr;
172 
173 		if (keyeq) {
174 			(void) snprintf(keyfilter + len, totlen - len,
175 					"(%s)", k);
176 		} else {
177 			(void) snprintf(keyfilter + len, totlen - len,
178 					"(%s=%s)", attrtype, k);
179 		}
180 		karray++;
181 	}
182 
183 	if (key[1]) {
184 		/* We allocated memory for this earlier */
185 		(void) strlcat(keyfilter, ")", totlen);
186 	}
187 
188 	return (keyfilter);
189 }
190 
191 
192 /*
193  * A special set_key routine for to handle public keys.
194  * If the key starts with a digiti, view it as a user id.
195  * Otherwise, view it as a hostname.
196  * It returns: -1 no keys defined, 0 key defined but none for type
197  *		specified, n>0 number of matches found.
198  */
199 int
200 set_keys_publickey(char **key, char *attrtype, int type, char **ret)
201 {
202 	char	*keyeq = NULL;
203 	char	*keyfilter = NULL;
204 	char	*pre_filter = NULL;
205 	char	*k, **karray;
206 	int	count = 0;
207 	int	len, totlen = 1; /* Terminating NULL byte */
208 	char	*tmpptr;
209 
210 	if (!key || !key[0]) {	/* should never contain NULL string */
211 		*ret = NULL;
212 		return (-1);
213 	}
214 
215 	karray = key;
216 	while ((k = *karray) != 0) {
217 		keyeq = strchr(k, '=');
218 		if (keyeq) {
219 			/* make enough room for (%s) */
220 			totlen += strlen(k) + 2;
221 		} else {
222 			if ((type == 0 && isdigit(*k)) ||
223 				/* user type keys */
224 			    (type == 1 && (!isdigit(*k)))) {
225 				/* hosts type keys */
226 				/* make enough room for (%s=%s) */
227 				totlen += strlen(k) + strlen(attrtype) + 3;
228 			} else {
229 				karray++;
230 				continue;
231 			}
232 		}
233 
234 		len = pre_filter ? strlen(pre_filter) : 0;
235 
236 		if (!(tmpptr = (char *)realloc(pre_filter, totlen))) {
237 			if (pre_filter)
238 				free(pre_filter);
239 			(void) fprintf(stderr, gettext("out of memory\n"));
240 			exit(2);
241 		}
242 		pre_filter = tmpptr;
243 
244 		if (keyeq) {
245 			(void) snprintf(pre_filter + len, totlen - len,
246 					"(%s)", k);
247 		} else {
248 			(void) snprintf(pre_filter + len, totlen - len,
249 					"(%s=%s)", attrtype, k);
250 		}
251 		karray++;
252 		count++;
253 	}
254 	if (count > 1) {
255 		len = strlen(pre_filter) + 4;
256 		if (!(keyfilter = (char *)malloc(len))) {
257 			(void) fprintf(stderr, gettext("out of memory\n"));
258 			free(pre_filter);
259 			exit(2);
260 		}
261 		(void) snprintf(keyfilter, len, "(|%s)", pre_filter);
262 		free(pre_filter);
263 		*ret = keyfilter;
264 	} else
265 		*ret = pre_filter;
266 	return (count);
267 }
268 
269 /*
270  * publickey specific set_filter
271  * type 0 -> check for user publickeys
272  * type 1 -> check for hosts publickeys
273  */
274 char *
275 set_filter_publickey(char **key, char *database, int type, char **udata)
276 {
277 	char 	*filter = NULL;
278 	char 	*userdata;
279 	char	*keyfilter = NULL;
280 	int	rc;
281 	int	filterlen, udatalen;
282 	short	nomem = 0;
283 
284 	if (!database || !udata) {
285 		return (NULL);
286 	}
287 
288 	if (strcasecmp(database, maplist[PUBLICKEY].database) == SAME) {
289 		rc = set_keys_publickey(key,
290 				maplist[PUBLICKEY + type].def_type, type,
291 				&keyfilter);
292 		switch (rc) {
293 		case -1:
294 			filterlen = strlen(maplist[PUBLICKEY].objectclass) + 13;
295 			udatalen = 3;
296 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
297 						udatalen, nomem);
298 			if (!nomem) {
299 				(void) snprintf(filter, filterlen,
300 					"objectclass=%s",
301 					maplist[PUBLICKEY].objectclass);
302 				(void) snprintf(userdata, udatalen, "%%s");
303 			}
304 			break;
305 		case 0:
306 			return (NULL);
307 		default:
308 			filterlen = strlen(maplist[PUBLICKEY].objectclass) +
309 				strlen(keyfilter) + 18;
310 			udatalen = strlen(keyfilter) + 8;
311 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
312 						udatalen, nomem);
313 			if (!nomem) {
314 			    (void) snprintf(filter, filterlen,
315 				"(&(objectclass=%s)%s)",
316 				maplist[PUBLICKEY].objectclass, keyfilter);
317 			    (void) snprintf(userdata, udatalen, "(&(%%s)%s)",
318 					keyfilter);
319 			}
320 		}
321 	} else {
322 		if ((keyfilter = set_keys(key, "cn")) == NULL) {
323 			filterlen = 14;
324 			udatalen = 3;
325 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
326 						udatalen, nomem);
327 			if (!nomem) {
328 				(void) snprintf(filter, filterlen,
329 						"objectclass=*");
330 				(void) snprintf(userdata, udatalen, "%%s");
331 			}
332 		} else {
333 			filterlen = strlen(keyfilter) + 1;
334 			udatalen = strlen(keyfilter) + 8;
335 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
336 						udatalen, nomem);
337 			if (!nomem) {
338 				(void) snprintf(filter, filterlen, "%s",
339 						keyfilter);
340 				(void) snprintf(userdata, udatalen,
341 						"(&(%%s)%s)", keyfilter);
342 			}
343 		}
344 	}
345 #ifdef DEBUG
346 	(void) fprintf(stdout, "set_filter: filter=\"%s\"\n", filter);
347 	(void) fprintf(stdout, "set_filter: userdata=\"%s\"\n", userdata);
348 #endif /* DEBUG */
349 	if (keyfilter)
350 		free(keyfilter);
351 	if (nomem)
352 		exit(2);
353 	*udata = userdata;
354 	return (filter);
355 }
356 
357 
358 /* generic set_filter, this function is not thread safe */
359 char *
360 set_filter(char **key, char *database, char **udata)
361 {
362 	char 		*filter = NULL;
363 	char 		*userdata = NULL;
364 	char		*keyfilter;
365 	int		i, filterlen, udatalen;
366 	int		rc, v2 = 1;
367 	void		**paramVal = NULL;
368 	ns_ldap_error_t	*errorp = NULL;
369 	short		nomem;
370 
371 	if (!database || !udata) {
372 		return (NULL);
373 	}
374 
375 
376 	/*
377 	 * Check for version of the profile the client is using
378 	 *
379 	 * For version 1 profiles we do use nisMap and nisObject schema
380 	 * for backward compatibility with Solaris 8 clients.
381 	 *
382 	 * For version 2 profiles we use automountMap and automount as
383 	 * default attributes (which can then be overridden in libsldap
384 	 * if schema mapping is configured in the profile).
385 	 *
386 	 * If profile version is not available, use version 2 as default.
387 	 */
388 	rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, &errorp);
389 	if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
390 		/* should print a message here: using v2 defaults */
391 		(void) __ns_ldap_freeError(&errorp);
392 	} else {
393 		if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0)
394 			v2 = 0;
395 		(void) __ns_ldap_freeParam(&paramVal);
396 	}
397 
398 	/*
399 	 * starts at 2 to skip over publickey databases.
400 	 * These databases are handled separately.
401 	 */
402 	for (i = 2; maplist[i].database != NULL; i++) {
403 		if (strcasecmp(database, maplist[i].database) == SAME) {
404 			if ((keyfilter = set_keys(key, maplist[i].def_type))
405 							== NULL) {
406 				filterlen = strlen(maplist[i].objectclass) + 13;
407 				udatalen = 3;
408 				MALLOC_FILTER_UDATA(filter, filterlen, userdata,
409 						udatalen, nomem);
410 				if (!nomem) {
411 					(void) snprintf(filter, filterlen,
412 						"objectclass=%s",
413 						maplist[i].objectclass);
414 					(void) snprintf(userdata, udatalen,
415 							"%%s");
416 				}
417 			} else {
418 				filterlen = strlen(maplist[i].objectclass) +
419 					strlen(keyfilter) + 18;
420 				udatalen = strlen(keyfilter) + 8;
421 				MALLOC_FILTER_UDATA(filter, filterlen, userdata,
422 						udatalen, nomem);
423 				if (!nomem) {
424 					(void) snprintf(filter, filterlen,
425 					    "(&(objectclass=%s)%s)",
426 					    maplist[i].objectclass, keyfilter);
427 					(void) snprintf(userdata, udatalen,
428 						"(&(%%s)%s)", keyfilter);
429 				}
430 			}
431 			goto done;
432 		}
433 	}
434 
435 	/* special cases for automounter and other services */
436 
437 	/* auto_* services */
438 	if (strncasecmp(database, "auto_", 5) == SAME) {
439 	    if (v2) {
440 		if ((keyfilter = set_keys(key, "automountKey"))
441 			!= NULL) {
442 			filterlen = strlen(keyfilter) + 27;
443 			udatalen = strlen(keyfilter) + 8;
444 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
445 					udatalen, nomem);
446 			if (!nomem) {
447 				(void) snprintf(filter, filterlen,
448 				    "(&(objectclass=automount)%s)",
449 					keyfilter);
450 				(void) snprintf(userdata, udatalen,
451 					"(&(%%s)%s)", keyfilter);
452 			}
453 		} else {
454 			filterlen = 22;
455 			udatalen = 3;
456 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
457 					udatalen, nomem);
458 			if (!nomem) {
459 				(void) strlcpy(filter, "objectclass=automount",
460 					filterlen);
461 				(void) strlcpy(userdata, "%s", udatalen);
462 			}
463 		}
464 	    } else {
465 		if ((keyfilter = set_keys(key, "cn")) != NULL) {
466 			filterlen = strlen(keyfilter) + 27;
467 			udatalen = strlen(keyfilter) + 8;
468 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
469 					udatalen, nomem);
470 			if (!nomem) {
471 				(void) snprintf(filter, filterlen,
472 				    "(&(objectclass=nisObject)%s)", keyfilter);
473 				(void) snprintf(userdata, udatalen,
474 					"(&(%%s)%s)", keyfilter);
475 			}
476 		} else {
477 			filterlen = 22;
478 			udatalen = 3;
479 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
480 					udatalen, nomem);
481 			if (!nomem) {
482 				(void) strlcpy(filter, "objectclass=nisObject",
483 						filterlen);
484 				(void) strlcpy(userdata, "%s", udatalen);
485 			}
486 		}
487 	    }
488 	    goto done;
489 	}
490 
491 	/* automount service */
492 	if (strcasecmp(database, "automount") == SAME) {
493 	    if (v2) {
494 		if ((keyfilter = set_keys(key, "automountMapName"))
495 			!= NULL) {
496 			filterlen = strlen(keyfilter) + 30;
497 			udatalen = strlen(keyfilter) + 8;
498 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
499 					udatalen, nomem);
500 			if (!nomem) {
501 				(void) snprintf(filter, filterlen,
502 					"(&(objectclass=automountMap)%s)",
503 					keyfilter);
504 				(void) snprintf(userdata, udatalen,
505 					"(&(%%s)%s)", keyfilter);
506 			}
507 		} else {
508 			filterlen = 25;
509 			udatalen = 3;
510 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
511 					udatalen, nomem);
512 			if (!nomem) {
513 				(void) strlcpy(filter,
514 					"objectclass=automountMap",
515 					filterlen);
516 				(void) strlcpy(userdata, "%s", udatalen);
517 			}
518 		}
519 	    } else {
520 		if ((keyfilter = set_keys(key, "nisMapName"))
521 			!= NULL) {
522 			filterlen = strlen(keyfilter) + 24;
523 			udatalen = strlen(keyfilter) + 8;
524 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
525 					udatalen, nomem);
526 			if (!nomem) {
527 				(void) snprintf(filter, filterlen,
528 					"(&(objectclass=nisMap)%s)",
529 					keyfilter);
530 				(void) snprintf(userdata, udatalen,
531 					"(&(%%s)%s)", keyfilter);
532 			}
533 		} else {
534 			filterlen = 19;
535 			udatalen = 3;
536 			MALLOC_FILTER_UDATA(filter, filterlen, userdata,
537 					udatalen, nomem);
538 			if (!nomem) {
539 			    (void) strlcpy(filter, "objectclass=nisMap",
540 					filterlen);
541 			    (void) strlcpy(userdata, "%s", udatalen);
542 			}
543 		}
544 	    }
545 	    goto done;
546 	}
547 
548 	/* other services (catch all) */
549 	if ((keyfilter = set_keys(key, "cn")) == NULL) {
550 		filterlen = 14;
551 		udatalen = 3;
552 		MALLOC_FILTER_UDATA(filter, filterlen, userdata,
553 				udatalen, nomem);
554 		if (!nomem) {
555 			(void) snprintf(filter, filterlen, "objectclass=*");
556 			(void) strlcpy(userdata, "%s", udatalen);
557 		}
558 	} else {
559 		filterlen = strlen(keyfilter) + 1;
560 		udatalen = strlen(keyfilter) + 8;
561 		MALLOC_FILTER_UDATA(filter, filterlen, userdata,
562 				udatalen, nomem);
563 		if (!nomem) {
564 			(void) snprintf(filter, filterlen, "%s", keyfilter);
565 			(void) snprintf(userdata, udatalen, "(&(%%s)%s)",
566 					keyfilter);
567 		}
568 	}
569 
570 done:
571 #ifdef DEBUG
572 	(void) fprintf(stdout, "set_filter: filter=\"%s\"\n", filter);
573 	(void) fprintf(stdout, "set_filter: userdata=\"%s\"\n", userdata);
574 #endif /* DEBUG */
575 	if (keyfilter)
576 		free(keyfilter);
577 	if (nomem)
578 		exit(2);
579 	*udata = userdata;
580 	return (filter);
581 }
582