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