mapping.c revision 2830:5228d1267a01
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
39struct mapping {
40	char *database;
41	char *def_type;
42	char *objectclass;
43	char *actual_db;
44};
45
46#define	PUBLICKEY	0
47
48static 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
112void
113printMapping()
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
154char *
155set_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 */
222int
223set_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 */
297char *
298set_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 */
382char *
383set_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
631done:
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