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