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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <secdb.h>
27#include <exec_attr.h>
28#include "ldap_common.h"
29
30
31/* exec_attr attributes filters */
32#define	ISWILD(x)		(x == NULL) ? "*" : x
33#define	_EXEC_NAME		"cn"
34#define	_EXEC_POLICY		"SolarisKernelSecurityPolicy"
35#define	_EXEC_TYPE		"SolarisProfileType"
36#define	_EXEC_RES1		"SolarisAttrRes1"
37#define	_EXEC_RES2		"SolarisAttrRes2"
38#define	_EXEC_ID		"SolarisProfileId"
39#define	_EXEC_ATTRS		"SolarisAttrKeyValue"
40#define	_EXEC_GETEXECNAME	"(&(objectClass=SolarisExecAttr)(cn=%s)"\
41				"(SolarisKernelSecurityPolicy=%s)"\
42				"(SolarisProfileType=%s))"
43#define	_EXEC_GETEXECNAME_SSD	"(&(%%s)(cn=%s)"\
44				"(SolarisKernelSecurityPolicy=%s)"\
45				"(SolarisProfileType=%s))"
46#define	_EXEC_GETEXECID		"(&(objectClass=SolarisExecAttr)"\
47				"(SolarisProfileId=%s)"\
48				"(SolarisKernelSecurityPolicy=%s)"\
49				"(SolarisProfileType=%s))"
50#define	_EXEC_GETEXECID_SSD	"(&(%%s)"\
51				"(SolarisProfileId=%s)"\
52				"(SolarisKernelSecurityPolicy=%s)"\
53				"(SolarisProfileType=%s))"
54#define	_EXEC_GETEXECNAMEID	"(&(objectClass=SolarisExecAttr)(cn=%s)"\
55				"(SolarisProfileId=%s)"\
56				"(SolarisKernelSecurityPolicy=%s)"\
57				"(SolarisProfileType=%s))"
58#define	_EXEC_GETEXECNAMEID_SSD	"(&(%%s)(cn=%s)"\
59				"(SolarisProfileId=%s)"\
60				"(SolarisKernelSecurityPolicy=%s)"\
61				"(SolarisProfileType=%s))"
62
63
64/* from libnsl */
65extern int _doexeclist(nss_XbyY_args_t *);
66extern char *_exec_wild_id(char *, const char *);
67extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
68
69
70static const char *exec_attrs[] = {
71	_EXEC_NAME,
72	_EXEC_POLICY,
73	_EXEC_TYPE,
74	_EXEC_RES1,
75	_EXEC_RES2,
76	_EXEC_ID,
77	_EXEC_ATTRS,
78	(char *)NULL
79};
80
81
82#ifdef	DEBUG
83static void
84_print_execstr(execstr_t *exec)
85{
86
87	(void) fprintf(stdout, "      exec-name: [%s]\n", exec->name);
88	if (exec->policy != (char *)NULL) {
89		(void) fprintf(stdout, "      policy: [%s]\n", exec->policy);
90	}
91	if (exec->type != (char *)NULL) {
92		(void) fprintf(stdout, "      type: [%s]\n", exec->type);
93	}
94	if (exec->res1 != (char *)NULL) {
95		(void) fprintf(stdout, "      res1: [%s]\n", exec->res1);
96	}
97	if (exec->res2 != (char *)NULL) {
98		(void) fprintf(stdout, "      res2: [%s]\n", exec->res2);
99	}
100	if (exec->id != (char *)NULL) {
101		(void) fprintf(stdout, "      id: [%s]\n", exec->id);
102	}
103	if (exec->attr != (char *)NULL) {
104		(void) fprintf(stdout, "      attr: [%s]\n", exec->attr);
105	}
106	if (exec->next != (execstr_t *)NULL) {
107		(void) fprintf(stdout, "      next: [%s]\n", exec->next->name);
108		(void) fprintf(stdout, "\n");
109		_print_execstr(exec->next);
110	}
111}
112#endif	/* DEBUG */
113
114
115static int
116_exec_ldap_exec2ent(ns_ldap_entry_t *entry, nss_XbyY_args_t *argp)
117{
118
119	int			i;
120	unsigned long		len = 0L;
121	int			buflen = (int)0;
122	char			*nullstring = (char *)NULL;
123	char			*buffer = (char *)NULL;
124	char			*ceiling = (char *)NULL;
125	execstr_t		*exec = (execstr_t *)NULL;
126	ns_ldap_attr_t		*attrptr;
127
128	buffer = argp->buf.buffer;
129	buflen = (size_t)argp->buf.buflen;
130	(void) memset(argp->buf.buffer, 0, buflen);
131	exec = (execstr_t *)(argp->buf.result);
132	ceiling = buffer + buflen;
133	exec->name = (char *)NULL;
134	exec->policy = (char *)NULL;
135	exec->type = (char *)NULL;
136	exec->res1 = (char *)NULL;
137	exec->res2 = (char *)NULL;
138	exec->id = (char *)NULL;
139	exec->attr = (char *)NULL;
140
141	for (i = 0; i < entry->attr_count; i++) {
142		attrptr = entry->attr_pair[i];
143		if (attrptr == NULL) {
144			return ((int)NSS_STR_PARSE_PARSE);
145		}
146		if (strcasecmp(attrptr->attrname, _EXEC_NAME) == 0) {
147			if ((attrptr->attrvalue[0] == NULL) ||
148			    (len = strlen(attrptr->attrvalue[0])) < 1) {
149				return ((int)NSS_STR_PARSE_PARSE);
150			}
151			exec->name = buffer;
152			buffer += len + 1;
153			if (buffer >= ceiling) {
154				return ((int)NSS_STR_PARSE_ERANGE);
155			}
156			(void) strcpy(exec->name, attrptr->attrvalue[0]);
157			continue;
158		}
159		if (strcasecmp(attrptr->attrname, _EXEC_POLICY) == 0) {
160			if ((attrptr->attrvalue[0] == NULL) ||
161			    (len = strlen(attrptr->attrvalue[0])) < 1) {
162				exec->policy = nullstring;
163			} else {
164				exec->policy = buffer;
165				buffer += len + 1;
166				if (buffer >= ceiling) {
167					return ((int)NSS_STR_PARSE_ERANGE);
168				}
169				(void) strcpy(exec->policy,
170				    attrptr->attrvalue[0]);
171			}
172			continue;
173		}
174		if (strcasecmp(attrptr->attrname, _EXEC_TYPE) == 0) {
175			if ((attrptr->attrvalue[0] == NULL) ||
176			    (len = strlen(attrptr->attrvalue[0])) < 1) {
177				exec->type = nullstring;
178			} else {
179				exec->type = buffer;
180				buffer += len + 1;
181				if (buffer >= ceiling) {
182					return ((int)NSS_STR_PARSE_ERANGE);
183				}
184				(void) strcpy(exec->type,
185				    attrptr->attrvalue[0]);
186			}
187			continue;
188		}
189		if (strcasecmp(attrptr->attrname, _EXEC_RES1) == 0) {
190			if ((attrptr->attrvalue[0] == NULL) ||
191			    (len = strlen(attrptr->attrvalue[0])) < 1) {
192				exec->res1 = nullstring;
193			} else {
194				exec->res1 = buffer;
195				buffer += len + 1;
196				if (buffer >= ceiling) {
197					return ((int)NSS_STR_PARSE_ERANGE);
198				}
199				(void) strcpy(exec->res1,
200				    attrptr->attrvalue[0]);
201			}
202			continue;
203		}
204		if (strcasecmp(attrptr->attrname, _EXEC_RES2) == 0) {
205			if ((attrptr->attrvalue[0] == NULL) ||
206			    (len = strlen(attrptr->attrvalue[0])) < 1) {
207				exec->res2 = nullstring;
208			} else {
209				exec->res2 = buffer;
210				buffer += len + 1;
211				if (buffer >= ceiling) {
212					return ((int)NSS_STR_PARSE_ERANGE);
213				}
214				(void) strcpy(exec->res2,
215				    attrptr->attrvalue[0]);
216			}
217			continue;
218		}
219		if (strcasecmp(attrptr->attrname, _EXEC_ID) == 0) {
220			if ((attrptr->attrvalue[0] == NULL) ||
221			    (len = strlen(attrptr->attrvalue[0])) < 1) {
222				exec->id = nullstring;
223			} else {
224				exec->id = buffer;
225				buffer += len + 1;
226				if (buffer >= ceiling) {
227					return ((int)NSS_STR_PARSE_ERANGE);
228				}
229				(void) strcpy(exec->id, attrptr->attrvalue[0]);
230			}
231			continue;
232		}
233		if (strcasecmp(attrptr->attrname, _EXEC_ATTRS) == 0) {
234			if ((attrptr->attrvalue[0] == NULL) ||
235			    (len = strlen(attrptr->attrvalue[0])) < 1) {
236				exec->attr = nullstring;
237			} else {
238				exec->attr = buffer;
239				buffer += len + 1;
240				if (buffer >= ceiling) {
241					return ((int)NSS_STR_PARSE_ERANGE);
242				}
243				(void) strcpy(exec->attr,
244				    attrptr->attrvalue[0]);
245			}
246			continue;
247		}
248	}
249
250	exec->next = (execstr_t *)NULL;
251
252#ifdef	DEBUG
253	(void) fprintf(stdout, "\n[getexecattr.c: _exec_ldap_exec2ent]\n");
254	_print_execstr(exec);
255#endif	/* DEBUG */
256
257	return ((int)NSS_STR_PARSE_SUCCESS);
258}
259
260
261/*
262 * place the results from ldap object structure into the file format
263 * returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE}
264 */
265static int
266_nss_ldap_exec2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
267{
268	int			status = NSS_STR_PARSE_SUCCESS;
269	ns_ldap_result_t	*result = be->result;
270	int			len;
271	char			*buffer, **name, **policy, **type;
272	char			**res1, **res2, **id, **attr;
273	char			*policy_str, *type_str, *res1_str, *res2_str;
274	char			*id_str, *attr_str;
275
276	if (result == NULL)
277		return (NSS_STR_PARSE_PARSE);
278
279	(void) memset(argp->buf.buffer, 0, argp->buf.buflen);
280
281	name = __ns_ldap_getAttr(result->entry, _EXEC_NAME);
282	if (name == NULL || name[0] == NULL ||
283	    (strlen(name[0]) < 1)) {
284		status = NSS_STR_PARSE_PARSE;
285		goto result_exec2str;
286	}
287
288	policy = __ns_ldap_getAttr(result->entry, _EXEC_POLICY);
289
290	if (policy == NULL || policy[0] == NULL)
291		policy_str = _NO_VALUE;
292	else
293		policy_str = policy[0];
294
295	type = __ns_ldap_getAttr(result->entry, _EXEC_TYPE);
296	if (type == NULL || type[0] == NULL)
297		type_str = _NO_VALUE;
298	else
299		type_str = type[0];
300
301	res1 = __ns_ldap_getAttr(result->entry, _EXEC_RES1);
302	if (res1 == NULL || res1[0] == NULL)
303		res1_str = _NO_VALUE;
304	else
305		res1_str = res1[0];
306
307	res2 = __ns_ldap_getAttr(result->entry, _EXEC_RES2);
308	if (res2 == NULL || res2[0] == NULL)
309		res2_str = _NO_VALUE;
310	else
311		res2_str = res2[0];
312
313	id = __ns_ldap_getAttr(result->entry, _EXEC_ID);
314	if (id == NULL || id[0] == NULL)
315		id_str = _NO_VALUE;
316	else
317		id_str = id[0];
318
319	attr = __ns_ldap_getAttr(result->entry, _EXEC_ATTRS);
320	if (attr == NULL || attr[0] == NULL)
321		attr_str = _NO_VALUE;
322	else
323		attr_str = attr[0];
324
325	/* 7 = 6 ':' + 1 '\0' */
326	len = strlen(name[0]) + strlen(policy_str) + strlen(type_str) +
327	    strlen(res1_str) + strlen(res2_str) + strlen(id_str) +
328	    strlen(attr_str) + 7;
329
330	if (len > argp->buf.buflen) {
331		status = NSS_STR_PARSE_ERANGE;
332		goto  result_exec2str;
333	}
334	if (argp->buf.result != NULL) {
335		if ((be->buffer = calloc(1, len)) == NULL) {
336			status = NSS_STR_PARSE_PARSE;
337			goto result_exec2str;
338		}
339		buffer = be->buffer;
340	} else
341		buffer = argp->buf.buffer;
342
343	(void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s",
344	    name[0], policy_str, type_str, res1_str,
345	    res2_str, id_str, attr_str);
346	/* The front end marshaller does not need the trailing null */
347	if (argp->buf.result != NULL)
348		be->buflen = strlen(buffer);
349result_exec2str:
350	(void) __ns_ldap_freeResult(&be->result);
351	return (status);
352}
353
354
355static nss_status_t
356_exec_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp)
357{
358	int 			status;
359	nss_status_t		nss_stat = NSS_UNAVAIL;
360	ns_ldap_attr_t		*attrptr;
361	ns_ldap_entry_t		*entry;
362	ns_ldap_result_t	*result = be->result;
363	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
364
365	argp->returnval = NULL;
366	attrptr = getattr(result, 0);
367	if (attrptr == NULL) {
368		(void) __ns_ldap_freeResult(&be->result);
369		return (nss_stat);
370	}
371	for (entry = result->entry; entry != NULL; entry = entry->next) {
372		status = _exec_ldap_exec2ent(entry, argp);
373		switch (status) {
374		case NSS_STR_PARSE_SUCCESS:
375			argp->returnval = argp->buf.result;
376			nss_stat = NSS_SUCCESS;
377			if (IS_GET_ALL(_priv_exec->search_flag)) {
378				if (_doexeclist(argp) == 0) {
379					nss_stat = NSS_UNAVAIL;
380				}
381			}
382			break;
383		case NSS_STR_PARSE_ERANGE:
384			argp->erange = 1;
385			nss_stat = NSS_NOTFOUND;
386			break;
387		case NSS_STR_PARSE_PARSE:
388			nss_stat = NSS_NOTFOUND;
389			break;
390		default:
391			nss_stat = NSS_UNAVAIL;
392			break;
393		}
394
395		if (IS_GET_ONE(_priv_exec->search_flag) ||
396		    (nss_stat != NSS_SUCCESS)) {
397			break;
398		}
399	}
400
401	return (nss_stat);
402}
403
404
405/*
406 * Check if we have either an exact match or a wild-card entry for that id.
407 */
408static nss_status_t
409get_wild(ldap_backend_ptr be, nss_XbyY_args_t *argp, int getby_flag)
410{
411	char		*dup_id = NULL;
412	char		*wild_id;
413	char		searchfilter[SEARCHFILTERLEN];
414	char		userdata[SEARCHFILTERLEN];
415	char		name[SEARCHFILTERLEN];
416	char		id[SEARCHFILTERLEN];
417	int		ret;
418	nss_status_t	nss_stat = NSS_NOTFOUND;
419	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
420	const char	*policy = _priv_exec->policy;
421	const char	*type = _priv_exec->type;
422
423	if (strpbrk(policy, "*()\\") != NULL ||
424	    type != NULL && strpbrk(type, "*()\\") != NULL)
425		return ((nss_status_t)NSS_NOTFOUND);
426
427	if (_priv_exec->id != NULL)
428		dup_id = strdup(_priv_exec->id);
429
430	switch (getby_flag) {
431	case NSS_DBOP_EXECATTR_BYNAMEID:
432		if (_ldap_filter_name(name, _priv_exec->name,
433		    sizeof (name)) != 0)
434			goto go_out;
435		break;
436	}
437
438	wild_id = dup_id;
439	do {
440		if (wild_id != NULL) {
441			if (_ldap_filter_name(id, wild_id, sizeof (id)) != 0)
442				goto go_out;
443		} else
444			(void) strlcpy(id, "*", sizeof (id));
445
446		switch (getby_flag) {
447		case NSS_DBOP_EXECATTR_BYID:
448			ret = snprintf(searchfilter, sizeof (searchfilter),
449			    _EXEC_GETEXECID, id, policy, ISWILD(type));
450			if (ret >= sizeof (searchfilter) || ret < 0)
451				goto go_out;
452			ret = snprintf(userdata, sizeof (userdata),
453			    _EXEC_GETEXECID_SSD, id, policy, ISWILD(type));
454			if (ret >= sizeof (userdata) || ret < 0)
455				goto go_out;
456			break;
457
458		case NSS_DBOP_EXECATTR_BYNAMEID:
459			ret = snprintf(searchfilter, sizeof (searchfilter),
460			    _EXEC_GETEXECNAMEID, name, id,
461			    policy, ISWILD(type));
462			if (ret >= sizeof (searchfilter) || ret < 0)
463				goto go_out;
464			ret = snprintf(userdata, sizeof (userdata),
465			    _EXEC_GETEXECNAMEID_SSD, name, id,
466			    policy, ISWILD(type));
467			if (ret >= sizeof (userdata) || ret < 0)
468				goto go_out;
469			break;
470
471		default:
472			goto go_out;
473		}
474		nss_stat = _nss_ldap_nocb_lookup(be, argp, _EXECATTR,
475		    searchfilter, NULL, _merge_SSD_filter, userdata);
476		if (nss_stat == NSS_SUCCESS)
477			break;
478	} while ((wild_id = _exec_wild_id(wild_id, type)) != NULL);
479
480go_out:
481	free(dup_id);
482
483	return (nss_stat);
484}
485
486static nss_status_t
487exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) {
488
489	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
490	int		stat, nss_stat = NSS_SUCCESS;
491
492	if (IS_GET_ONE(_priv_exec->search_flag)) {
493		/* ns_ldap_entry_t -> file format */
494		stat = (*be->ldapobj2str)(be, argp);
495
496		if (stat == NSS_STR_PARSE_SUCCESS) {
497			if (argp->buf.result != NULL) {
498				/* file format -> execstr_t */
499				stat = (*argp->str2ent)(be->buffer,
500					be->buflen,
501					argp->buf.result,
502					argp->buf.buffer,
503					argp->buf.buflen);
504				if (stat == NSS_STR_PARSE_SUCCESS) {
505					argp->returnval = argp->buf.result;
506					argp->returnlen = 1; /* irrelevant */
507					nss_stat = NSS_SUCCESS;
508				} else {
509					argp->returnval = NULL;
510					argp->returnlen = 0;
511					nss_stat = NSS_NOTFOUND;
512				}
513			} else {
514				/* return file format in argp->buf.buffer */
515				argp->returnval = argp->buf.buffer;
516				argp->returnlen = strlen(argp->buf.buffer);
517				nss_stat = NSS_SUCCESS;
518			}
519		} else {
520			argp->returnval = NULL;
521			argp->returnlen = 0;
522			nss_stat = NSS_NOTFOUND;
523		}
524	} else {
525		/* GET_ALL */
526		nss_stat = _exec_process_val(be, argp);
527		_exec_cleanup(nss_stat, argp);
528	}
529
530	return (nss_stat);
531
532}
533
534static nss_status_t
535getbynam(ldap_backend_ptr be, void *a)
536{
537	char		searchfilter[SEARCHFILTERLEN];
538	char		userdata[SEARCHFILTERLEN];
539	char		name[SEARCHFILTERLEN];
540	int		ret;
541	nss_status_t	nss_stat;
542	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
543	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
544	const char	*policy = _priv_exec->policy;
545	const char	*type = _priv_exec->type;
546
547	if (strpbrk(policy, "*()\\") != NULL ||
548	    type != NULL && strpbrk(type, "*()\\") != NULL ||
549	    _ldap_filter_name(name, _priv_exec->name, sizeof (name)) != 0)
550		return ((nss_status_t)NSS_NOTFOUND);
551	ret = snprintf(searchfilter, sizeof (searchfilter),
552	    _EXEC_GETEXECNAME, name, policy, ISWILD(type));
553	if (ret >= sizeof (searchfilter) || ret < 0)
554		return ((nss_status_t)NSS_NOTFOUND);
555	ret = snprintf(userdata, sizeof (userdata),
556	    _EXEC_GETEXECNAME_SSD, name, policy, ISWILD(type));
557	if (ret >= sizeof (userdata) || ret < 0)
558		return ((nss_status_t)NSS_NOTFOUND);
559
560	nss_stat = _nss_ldap_nocb_lookup(be, argp, _EXECATTR,
561	    searchfilter, NULL, _merge_SSD_filter, userdata);
562
563	if (nss_stat ==  NSS_SUCCESS)
564		nss_stat = exec_attr_process_val(be, argp);
565
566	return (nss_stat);
567}
568
569static nss_status_t
570getbyid(ldap_backend_ptr be, void *a)
571{
572	nss_status_t	nss_stat = NSS_SUCCESS;
573	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
574
575	nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
576
577	if (nss_stat ==  NSS_SUCCESS)
578		nss_stat = exec_attr_process_val(be, argp);
579
580	return (nss_stat);
581}
582
583
584static nss_status_t
585getbynameid(ldap_backend_ptr be, void *a)
586{
587	nss_status_t	nss_stat;
588	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
589
590	nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
591
592	if (nss_stat ==  NSS_SUCCESS)
593		nss_stat = exec_attr_process_val(be, argp);
594
595	return (nss_stat);
596}
597
598
599static ldap_backend_op_t execattr_ops[] = {
600	_nss_ldap_destr,
601	_nss_ldap_endent,
602	_nss_ldap_setent,
603	_nss_ldap_getent,
604	getbynam,
605	getbyid,
606	getbynameid
607};
608
609
610/*ARGSUSED0*/
611nss_backend_t *
612_nss_ldap_exec_attr_constr(const char *dummy1,
613    const char *dummy2,
614    const char *dummy3,
615    const char *dummy4,
616    const char *dummy5,
617    const char *dummy6,
618    const char *dummy7)
619{
620#ifdef	DEBUG
621	(void) fprintf(stdout,
622	    "\n[getexecattr.c: _nss_ldap_exec_attr_constr]\n");
623#endif
624	return ((nss_backend_t *)_nss_ldap_constr(execattr_ops,
625	    sizeof (execattr_ops)/sizeof (execattr_ops[0]), _EXECATTR,
626	    exec_attrs, _nss_ldap_exec2str));
627}
628