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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1999-2003 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 "mt.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <nss_dbdefs.h>
34 #include <rpc/trace.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <sys/systeminfo.h>
38 #include <thread.h>
39 #include <synch.h>
40 #include <nsswitch.h>
41 #include <prof_attr.h>
42 #include <exec_attr.h>
43 
44 /* externs from libc */
45 extern void _nss_db_state_destr(struct nss_db_state *);
46 
47 /* externs from parse.c */
48 extern char *_strtok_escape(char *, char *, char **);
49 extern char *_strdup_null(char *);
50 /* extern from getprofattr.c */
51 extern int str2profattr(const char *, int, void *, char *, int);
52 
53 char *_exec_wild_id(char *, const char *);
54 execstr_t *_dup_execstr(execstr_t *);
55 void _free_execstr(execstr_t *);
56 
57 static char *_nsw_search_path = NULL;
58 
59 /*
60  * Unsynchronized, but it affects only efficiency, not correctness
61  */
62 
63 static DEFINE_NSS_DB_ROOT(exec_root);
64 static DEFINE_NSS_GETENT(context);
65 
66 void
67 _nss_initf_execattr(nss_db_params_t *p)
68 {
69 	trace1(TR__nss_initf_execattr, 0);
70 	p->name = NSS_DBNAM_EXECATTR;
71 	p->config_name    = NSS_DBNAM_PROFATTR; /* use config for "prof_attr" */
72 	trace1(TR__nss_initf_execattr, 1);
73 }
74 
75 void
76 _nsw_initf_execattr(nss_db_params_t *p)
77 {
78 	trace1(TR__nss_initf_execattr, 0);
79 	p->name = NSS_DBNAM_EXECATTR;
80 	p->flags |= NSS_USE_DEFAULT_CONFIG;
81 	p->default_config = _nsw_search_path;
82 	trace1(TR__nss_initf_execattr, 1);
83 }
84 
85 void
86 _nsw_initf_profattr(nss_db_params_t *p)
87 {
88 	trace1(TR__nss_initf_execattr, 0);
89 	p->name = NSS_DBNAM_PROFATTR;
90 	p->flags |= NSS_USE_DEFAULT_CONFIG;
91 	p->default_config = _nsw_search_path;
92 	trace1(TR__nss_initf_execattr, 1);
93 }
94 
95 /*
96  * Return values: 0 = success, 1 = parse error, 2 = erange ... The structure
97  * pointer passed in is a structure in the caller's space wherein the field
98  * pointers would be set to areas in the buffer if need be. instring and buffer
99  * should be separate areas.
100  */
101 int
102 str2execattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
103 {
104 	char		*last = (char *)NULL;
105 	char		*sep = KV_TOKEN_DELIMIT;
106 	char		*empty = KV_EMPTY;
107 	execstr_t	*exec = (execstr_t *)ent;
108 
109 	if (exec == NULL) {
110 		return (NSS_STR_PARSE_PARSE);
111 	}
112 
113 	trace3(TR_str2execattr, 0, lenstr, buflen);
114 	if ((instr >= buffer && (buffer + buflen) > instr) ||
115 	    (buffer >= instr && (instr + lenstr) > buffer)) {
116 		trace3(TR_str2execattr, 1, lenstr, buflen);
117 		return (NSS_STR_PARSE_PARSE);
118 	}
119 	if (lenstr >= buflen) {
120 		trace3(TR_str2execattr, 1, lenstr, buflen);
121 		return (NSS_STR_PARSE_ERANGE);
122 	}
123 	strncpy(buffer, instr, buflen);
124 	/*
125 	 * Remove newline that nis (yp_match) puts at the
126 	 * end of the entry it retrieves from the map.
127 	 */
128 	if (buffer[lenstr] == '\n') {
129 		buffer[lenstr] = '\0';
130 	}
131 
132 	exec->name = _strtok_escape(buffer, sep, &last);
133 	exec->policy = _strtok_escape(NULL, sep, &last);
134 	exec->type = _strtok_escape(NULL, sep, &last);
135 	exec->res1 = _strtok_escape(NULL, sep, &last);
136 	exec->res2 = _strtok_escape(NULL, sep, &last);
137 	exec->id = _strtok_escape(NULL, sep, &last);
138 	exec->attr = _strtok_escape(NULL, sep, &last);
139 	exec->next = (execstr_t *)NULL;
140 
141 	return (NSS_STR_PARSE_SUCCESS);
142 }
143 
144 
145 void
146 _setexecattr(void)
147 {
148 	trace1(TR_setexecattr, 0);
149 	nss_setent(&exec_root, _nss_initf_execattr, &context);
150 	trace1(TR_setexecattr, 0);
151 }
152 
153 
154 void
155 _endexecattr(void)
156 {
157 	trace1(TR_endexecattr, 0);
158 	nss_endent(&exec_root, _nss_initf_execattr, &context);
159 	nss_delete(&exec_root);
160 	trace1(TR_endexecattr, 0);
161 }
162 
163 
164 execstr_t *
165 _getexecattr(execstr_t *result, char *buffer, int buflen, int *errnop)
166 {
167 	nss_status_t    res;
168 	nss_XbyY_args_t arg;
169 
170 	trace2(TR_getexecattr, 0, buflen);
171 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2execattr);
172 	res = nss_getent(&exec_root, _nss_initf_execattr, &context, &arg);
173 	arg.status = res;
174 	*errnop = arg.h_errno;
175 	trace2(TR_getexecattr, 1, buflen);
176 
177 	return ((execstr_t *)NSS_XbyY_FINI(&arg));
178 }
179 
180 execstr_t *
181 _getexecprof(char *name,
182     char *type,
183     char *id,
184     int search_flag,
185     execstr_t *result,
186     char *buffer,
187     int buflen,
188     int *errnop)
189 {
190 	int		getby_flag;
191 	char		policy_buf[BUFSIZ];
192 	const char	*empty = (const char *)NULL;
193 	nss_status_t	res = NSS_NOTFOUND;
194 	nss_XbyY_args_t	arg;
195 	_priv_execattr	_priv_exec;
196 	static mutex_t	_nsw_exec_lock = DEFAULTMUTEX;
197 
198 	trace2(TR_getexecprof, 0, _buflen);
199 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2execattr);
200 
201 	_priv_exec.name = (name == NULL) ? empty : (const char *)name;
202 	_priv_exec.type = (type == NULL) ? empty : (const char *)type;
203 	_priv_exec.id = (id == NULL) ? empty : (const char *)id;
204 #ifdef SI_SECPOLICY
205 	if (sysinfo(SI_SECPOLICY, policy_buf, BUFSIZ) == -1)
206 #endif	/* SI_SECPOLICY */
207 	strncpy(policy_buf, DEFAULT_POLICY, BUFSIZ);
208 
209 retry_policy:
210 	_priv_exec.policy = policy_buf;
211 	_priv_exec.search_flag = search_flag;
212 	_priv_exec.head_exec = (execstr_t *)NULL;
213 	_priv_exec.prev_exec = (execstr_t *)NULL;
214 
215 	if ((name != NULL) && (id != NULL)) {
216 		getby_flag = NSS_DBOP_EXECATTR_BYNAMEID;
217 	} else if (name != NULL) {
218 		getby_flag = NSS_DBOP_EXECATTR_BYNAME;
219 	} else if (id != NULL) {
220 		getby_flag = NSS_DBOP_EXECATTR_BYID;
221 	}
222 
223 	arg.key.attrp = &(_priv_exec);
224 
225 	switch (getby_flag) {
226 	case NSS_DBOP_EXECATTR_BYID:
227 		res = nss_search(&exec_root, _nss_initf_execattr, getby_flag,
228 		    &arg);
229 		break;
230 	case NSS_DBOP_EXECATTR_BYNAMEID:
231 	case NSS_DBOP_EXECATTR_BYNAME:
232 		{
233 			char			pbuf[NSS_BUFLEN_PROFATTR];
234 			profstr_t		prof;
235 			nss_status_t		pres;
236 			nss_XbyY_args_t		parg;
237 			enum __nsw_parse_err	pserr;
238 			struct __nsw_lookup	*lookups = NULL;
239 			struct __nsw_switchconfig *conf = NULL;
240 
241 			if (conf = __nsw_getconfig(NSS_DBNAM_PROFATTR, &pserr))
242 				if ((lookups = conf->lookups) == NULL)
243 					goto out;
244 			NSS_XbyY_INIT(&parg, &prof, pbuf, NSS_BUFLEN_PROFATTR,
245 			    str2profattr);
246 			parg.key.name = name;
247 			do {
248 				/*
249 				 * search the exec_attr entry only in the scope
250 				 * that we find the profile in.
251 				 * if conf = NULL, search in local files only,
252 				 * as we were not able to read nsswitch.conf.
253 				 */
254 				DEFINE_NSS_DB_ROOT(prof_root);
255 				if (mutex_lock(&_nsw_exec_lock) != 0)
256 					goto out;
257 				_nsw_search_path = (conf == NULL)
258 				    ? NSS_FILES_ONLY
259 				    : lookups->service_name;
260 				pres = nss_search(&prof_root,
261 				    _nsw_initf_profattr,
262 				    NSS_DBOP_PROFATTR_BYNAME, &parg);
263 				if (pres == NSS_SUCCESS) {
264 					DEFINE_NSS_DB_ROOT(pexec_root);
265 					res = nss_search(&pexec_root,
266 					    _nsw_initf_execattr, getby_flag,
267 					    &arg);
268 					_nss_db_state_destr(pexec_root.s);
269 				}
270 				_nss_db_state_destr(prof_root.s);
271 				(void) mutex_unlock(&_nsw_exec_lock);
272 				if ((pres == NSS_SUCCESS) || (conf == NULL))
273 					break;
274 			} while (lookups && (lookups = lookups->next));
275 		}
276 		break;
277 	default:
278 		break;
279 	}
280 
281 out:
282 	/*
283 	 * If we can't find an entry for the current default policy
284 	 * fall back to the old "suser" policy.  The nameservice is
285 	 * shared between different OS releases.
286 	 */
287 	if (res == NSS_NOTFOUND && strcmp(policy_buf, DEFAULT_POLICY) == 0) {
288 		(void) strlcpy(policy_buf, SUSER_POLICY, BUFSIZ);
289 		goto retry_policy;
290 	}
291 
292 	arg.status = res;
293 	*errnop = res;
294 	trace2(TR_getexecprof, 1, buflen);
295 	return ((execstr_t *)NSS_XbyY_FINI(&arg));
296 }
297 
298 
299 int
300 _doexeclist(nss_XbyY_args_t *argp)
301 {
302 	int		status = 1;
303 	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
304 	execstr_t	*exec = (execstr_t *)((argp->buf.result));
305 
306 	if (_priv_exec->head_exec == NULL) {
307 		if (_priv_exec->head_exec = _dup_execstr(exec))
308 			_priv_exec->prev_exec = _priv_exec->head_exec;
309 		else
310 			status = 0;
311 	} else {
312 		if (_priv_exec->prev_exec->next = _dup_execstr(exec))
313 			_priv_exec->prev_exec = _priv_exec->prev_exec->next;
314 		else
315 			status = 0;
316 	}
317 	memset(argp->buf.buffer, NULL, argp->buf.buflen);
318 
319 	return (status);
320 
321 }
322 
323 
324 /*
325  * Converts id to a wildcard string. e.g.:
326  *   For type = KV_COMMAND: /usr/ccs/bin/what ---> /usr/ccs/bin/\* ---> \*
327  *   For type = KV_ACTION: Dtfile;*;*;*;0 ---> *;*;*;*;*
328  *
329  * Returns NULL if id is already a wild-card.
330  */
331 char *
332 _exec_wild_id(char *id, const char *type)
333 {
334 	char	c_id = '/';
335 	char	*pchar = NULL;
336 
337 	if ((id == NULL) || (type == NULL))
338 		return (NULL);
339 
340 	if (strcmp(type, KV_ACTION) == 0) {
341 		return ((strcmp(id, KV_ACTION_WILDCARD) == 0) ? NULL :
342 		    KV_ACTION_WILDCARD);
343 	} else if (strcmp(type, KV_COMMAND) == 0) {
344 		if ((pchar = rindex(id, c_id)) == NULL)
345 			/*
346 			 * id = \*
347 			 */
348 			return (NULL);
349 		else if (*(++pchar) == KV_WILDCHAR)
350 			/*
351 			 * id = /usr/ccs/bin/\*
352 			 */
353 			return (pchar);
354 		/*
355 		 * id = /usr/ccs/bin/what
356 		 */
357 		strcpy(pchar, KV_WILDCARD);
358 		return (id);
359 	}
360 
361 	return (NULL);
362 
363 }
364 
365 
366 execstr_t *
367 _dup_execstr(execstr_t *old_exec)
368 {
369 	execstr_t *new_exec = (execstr_t *)NULL;
370 
371 	if (old_exec == NULL) {
372 		return ((execstr_t *)NULL);
373 	}
374 	if ((new_exec = (execstr_t *)malloc(sizeof (execstr_t))) != NULL) {
375 		new_exec->name = _strdup_null(old_exec->name);
376 		new_exec->type = _strdup_null(old_exec->type);
377 		new_exec->policy = _strdup_null(old_exec->policy);
378 		new_exec->res1 = _strdup_null(old_exec->res1);
379 		new_exec->res2 = _strdup_null(old_exec->res2);
380 		new_exec->id = _strdup_null(old_exec->id);
381 		new_exec->attr = _strdup_null(old_exec->attr);
382 		new_exec->next = old_exec->next;
383 	}
384 	return (new_exec);
385 }
386 
387 void
388 _free_execstr(execstr_t *exec)
389 {
390 	if (exec != NULL) {
391 		free(exec->name);
392 		free(exec->type);
393 		free(exec->policy);
394 		free(exec->res1);
395 		free(exec->res2);
396 		free(exec->id);
397 		free(exec->attr);
398 		_free_execstr(exec->next);
399 		free(exec);
400 	}
401 }
402 
403 void
404 _exec_cleanup(nss_status_t res, nss_XbyY_args_t *argp)
405 {
406 	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
407 
408 	if (res == NSS_SUCCESS) {
409 		if (_priv_exec->head_exec != NULL) {
410 			argp->buf.result = _priv_exec->head_exec;
411 			argp->returnval = argp->buf.result;
412 		}
413 	} else {
414 		if (_priv_exec->head_exec != NULL)
415 			_free_execstr(_priv_exec->head_exec);
416 		argp->returnval = NULL;
417 	}
418 }
419