getexecattr.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 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
31#include <exec_attr.h>
32#include <rpcsvc/ypclnt.h>
33#include <rpcsvc/yp_prot.h>
34#include "nis_common.h"
35
36
37/* extern from nis_common.c */
38extern void massage_netdb(const char **, int *);
39/* externs from libnsl */
40extern int _doexeclist(nss_XbyY_args_t *);
41extern char *_exec_wild_id(char *, const char *);
42extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
43extern char *_strtok_escape(char *, char *, char **);
44
45typedef struct __exec_nis_args {
46	int		*yp_status;
47	nss_XbyY_args_t	*argp;
48} _exec_nis_args;
49
50
51/*
52 * check_match: returns 1 if -  matching entry found and no more entries needed,
53 *				or, entry cannot be found because of error;
54 *		returns 0 if -  no matching entry found, or,
55 *				matching entry found and next match needed.
56 */
57static int
58check_match(nss_XbyY_args_t *argp, int check_policy)
59{
60	execstr_t	*exec = (execstr_t *)(argp->returnval);
61	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
62	const char	*name = _priv_exec->name;
63	const char	*type = _priv_exec->type;
64	const char	*id = _priv_exec->id;
65	const char	*policy = _priv_exec->policy;
66
67	if (name && id) {
68		/*
69		 * NSS_DBOP_EXECATTR_BYNAMEID searched for name and id in
70		 * _exec_nis_lookup already.
71		 * If we're talking to pre-Solaris9 nis servers, check policy,
72		 * as policy was not a searchable column then.
73		 */
74		if ((check_policy && policy &&
75		    (strcmp(policy, exec->policy) != 0)) ||
76		    (type && (strcmp(type, exec->type) != 0))) {
77			return (0);
78		}
79	} else if ((policy && exec->policy &&
80	    (strcmp(policy, exec->policy) != 0)) ||
81	    (name && exec->name && (strcmp(name, exec->name) != 0)) ||
82	    (type && exec->type && (strcmp(type, exec->type) != 0)) ||
83	    (id && exec->id && (strcmp(id, exec->id) != 0))) {
84		return (0);
85	}
86
87	return (1);
88}
89
90/*
91 * check_match_strbuf: set up the data needed by check_match()
92 * and call it to match exec_attr data in strbuf and argp->key.attrp
93 */
94static int
95check_match_strbuf(nss_XbyY_args_t *argp, char *strbuf, int check_policy)
96{
97	char		*last = NULL;
98	char		*sep = KV_TOKEN_DELIMIT;
99	execstr_t	exec;
100	execstr_t	*execp = &exec;
101	void		*sp;
102	int		rc;
103
104	/*
105	 * Remove newline that yp_match puts at the
106	 * end of the entry it retrieves from the map.
107	 */
108	if (strbuf[argp->returnlen] == '\n') {
109		strbuf[argp->returnlen] = '\0';
110	}
111
112	execp->name = _strtok_escape(strbuf, sep, &last);
113	execp->policy = _strtok_escape(NULL, sep, &last);
114	execp->type = _strtok_escape(NULL, sep, &last);
115	execp->res1 = _strtok_escape(NULL, sep, &last);
116	execp->res2 = _strtok_escape(NULL, sep, &last);
117	execp->id = _strtok_escape(NULL, sep, &last);
118
119	sp = argp->returnval;
120	argp->returnval = execp;
121	rc = check_match(argp, check_policy);
122	argp->returnval = sp;
123	free(strbuf);
124
125	return (rc);
126}
127
128static  nss_status_t
129_exec_nis_parse(const char *instr,
130    int instr_len,
131    nss_XbyY_args_t *argp,
132    int check_policy)
133{
134	int		parse_stat;
135	nss_status_t	res;
136	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
137	char		*strbuf;
138	int		check_matched;
139
140	argp->returnval = NULL;
141	argp->returnlen = 0;
142	parse_stat = (*argp->str2ent)(instr, instr_len, argp->buf.result,
143	    argp->buf.buffer, argp->buf.buflen);
144	switch (parse_stat) {
145	case NSS_STR_PARSE_SUCCESS:
146		argp->returnlen = instr_len;
147		/* if exec_attr file format requested */
148		if (argp->buf.result == NULL) {
149			argp->returnval = argp->buf.buffer;
150			if ((strbuf = strdup(instr)) == NULL)
151				res = NSS_UNAVAIL;
152			check_matched = check_match_strbuf(argp,
153				strbuf, check_policy);
154		} else {
155			argp->returnval = argp->buf.result;
156			check_matched = check_match(argp, check_policy);
157		}
158		if (check_matched) {
159			res = NSS_SUCCESS;
160			if (_priv_exec->search_flag == GET_ALL) {
161				if (_doexeclist(argp) == 0) {
162					res = NSS_UNAVAIL;
163				}
164			}
165		} else {
166			res = NSS_NOTFOUND;
167		}
168		break;
169	case NSS_STR_PARSE_ERANGE:
170		argp->erange = 1;
171		res = NSS_NOTFOUND;
172		break;
173	default:
174		res = NSS_UNAVAIL;
175		break;
176	}
177
178	return (res);
179}
180
181/*
182 * This is the callback for yp_all. It returns 0 to indicate that it wants to
183 * be called again for further key-value pairs, or returns non-zero to stop the
184 * flow of key-value pairs. If it returns a non-zero value, it is not called
185 * again. The functional value of yp_all is then 0.
186 */
187/*ARGSUSED*/
188static int
189_exec_nis_cb(int instatus,
190    char *inkey,
191    int inkeylen,
192    char *inval,
193    int invallen,
194    void *indata)
195{
196	int		check_policy = 1; /* always check policy for yp_all */
197	int		stop_cb;
198	const char	*filter;
199	nss_status_t	res;
200	_exec_nis_args	*eargp = (_exec_nis_args *)indata;
201	nss_XbyY_args_t	*argp = eargp->argp;
202	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
203
204	if (instatus != YP_TRUE) {
205		*(eargp->yp_status) = YPERR_YPERR;
206		return (0);	/* yp_all may decide otherwise... */
207	}
208
209	filter = (_priv_exec->name) ? _priv_exec->name : _priv_exec->id;
210
211	/*
212	 * yp_all does not null terminate the entry it retrieves from the
213	 * map, unlike yp_match. so we do it explicitly here.
214	 */
215	inval[invallen] = '\0';
216
217	/*
218	 * Optimization:  if the entry doesn't contain the filter string then
219	 * it can't be the entry we want, so don't bother looking more closely
220	 * at it.
221	 */
222	if ((_priv_exec->policy &&
223	    (strstr(inval, _priv_exec->policy) == NULL)) ||
224	    (strstr(inval, filter) == NULL)) {
225		*(eargp->yp_status) = YPERR_KEY;
226		return (0);
227	}
228
229	res = _exec_nis_parse(inval, invallen, argp, check_policy);
230
231	switch (res) {
232	case NSS_SUCCESS:
233		*(eargp->yp_status) = 0;
234		stop_cb = (_priv_exec->search_flag == GET_ONE);
235		break;
236	case NSS_UNAVAIL:
237		*(eargp->yp_status) = YPERR_KEY;
238		stop_cb = 1;
239		break;
240	default:
241		*(eargp->yp_status) = YPERR_YPERR;
242		stop_cb = 0;
243		break;
244	}
245
246	return (stop_cb);
247}
248
249static nss_status_t
250_exec_nis_lookup(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
251{
252	int		ypstatus;
253	nss_status_t	res = NSS_SUCCESS;
254	nss_status_t	ypres;
255	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
256
257	if (getby_flag == NSS_DBOP_EXECATTR_BYNAMEID) {
258		int		check_policy = 0;
259		int		vallen;
260		char		*val;
261		char		key[MAX_INPUT];
262
263		/*
264		 * Try using policy as part of search key. If that fails,
265		 * (it will, in case of pre-Solaris9 nis server where policy
266		 * was not searchable), try again without using policy.
267		 */
268		if (snprintf(key, MAX_INPUT, "%s%s%s%s%s", _priv_exec->name,
269		    KV_TOKEN_DELIMIT, _priv_exec->policy, KV_TOKEN_DELIMIT,
270		    _priv_exec->id) >= MAX_INPUT)
271			return (NSS_NOTFOUND);
272		do {
273			ypres = _nss_nis_ypmatch(be->domain, NIS_MAP_EXECATTR,
274			    key, &val, &vallen, &ypstatus);
275			if ((check_policy == 0) && (ypstatus == YPERR_KEY)) {
276				(void) snprintf(key, MAX_INPUT, "%s%s%s",
277				    _priv_exec->name, KV_TOKEN_DELIMIT,
278				    _priv_exec->id);
279				check_policy = 1;
280				continue;
281			} else if (ypres != NSS_SUCCESS) {
282				res = ypres;
283				break;
284			} else {
285				massage_netdb((const char **)&val, &vallen);
286				res = _exec_nis_parse((const char *)val,
287				    vallen, argp, check_policy);
288				break;
289			}
290		} while (res == NSS_SUCCESS);
291	} else {
292		int			ypstat = YPERR_YPERR;
293		struct ypall_callback	cback;
294		_exec_nis_args		eargs;
295
296		eargs.yp_status = &ypstat;
297		eargs.argp = argp;
298
299		cback.foreach = _exec_nis_cb;
300		cback.data = (void *)&eargs;
301
302		/*
303		 * Instead of calling yp_all() doing hard lookup, we use
304		 * the alternative function, __yp_all_cflookup(), to
305		 * perform soft lookup when binding to nis servers with
306		 * time-out control. Other than that, these two functions
307		 * do exactly the same thing.
308		 */
309		ypstatus = __yp_all_cflookup((char *)(be->domain),
310			(char *)(be->enum_map), &cback, 0);
311
312		/*
313		 * For GET_ALL, check if we found anything at all.
314		 */
315		if (_priv_exec->head_exec != NULL)
316			return (NSS_SUCCESS);
317
318		switch (ypstat) {
319		case 0:
320			res = NSS_SUCCESS;
321			break;
322		case YPERR_BUSY:
323			res = NSS_TRYAGAIN;
324			break;
325		default:
326			res = NSS_UNAVAIL;
327			break;
328		}
329
330	}
331
332	return (res);
333}
334
335/*
336 * If search for exact match for id failed, get_wild checks if we have
337 * a wild-card entry for that id.
338 */
339static  nss_status_t
340get_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
341{
342	char		*orig_id = NULL;
343	char		*old_id = NULL;
344	char		*wild_id = NULL;
345	nss_status_t	res = NSS_NOTFOUND;
346	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
347
348	orig_id = strdup(_priv_exec->id);
349	old_id = strdup(_priv_exec->id);
350	wild_id = old_id;
351	while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) {
352		_priv_exec->id = wild_id;
353		res = _exec_nis_lookup(be, argp, getby_flag);
354		if (res == NSS_SUCCESS)
355			break;
356	}
357	_priv_exec->id = orig_id;
358	if (old_id)
359		free(old_id);
360
361	return (res);
362}
363
364
365static  nss_status_t
366getbynam(nis_backend_ptr_t be, void *a)
367{
368	nss_status_t	res;
369	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
370
371	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME);
372
373	_exec_cleanup(res, argp);
374
375	return (res);
376}
377
378static  nss_status_t
379getbyid(nis_backend_ptr_t be, void *a)
380{
381	nss_status_t	res;
382	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
383	/*LINTED*/
384	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
385
386	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID);
387
388	if (res != NSS_SUCCESS)
389		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
390
391	_exec_cleanup(res, argp);
392
393	return (res);
394}
395
396
397static  nss_status_t
398getbynameid(nis_backend_ptr_t be, void *a)
399{
400	nss_status_t	res;
401	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
402	/*LINTED*/
403	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
404
405	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
406
407	if (res != NSS_SUCCESS)
408		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
409
410	_exec_cleanup(res, argp);
411
412	return (res);
413}
414
415
416static nis_backend_op_t execattr_ops[] = {
417	_nss_nis_destr,
418	_nss_nis_endent,
419	_nss_nis_setent,
420	_nss_nis_getent_netdb,
421	getbynam,
422	getbyid,
423	getbynameid
424};
425
426/*ARGSUSED*/
427nss_backend_t *
428_nss_nis_exec_attr_constr(const char *dummy1,
429    const char *dummy2,
430    const char *dummy3,
431    const char *dummy4,
432    const char *dummy5,
433    const char *dummy6,
434    const char *dummy7)
435{
436	return (_nss_nis_constr(execattr_ops,
437		sizeof (execattr_ops)/sizeof (execattr_ops[0]),
438		NIS_MAP_EXECATTR));
439}
440