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