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