xref: /illumos-gate/usr/src/lib/nsswitch/nis/common/getexecattr.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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 */
38 extern void massage_netdb(const char **, int *);
39 /* externs from libnsl */
40 extern int _doexeclist(nss_XbyY_args_t *);
41 extern char *_exec_wild_id(char *, const char *);
42 extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
43 extern char *_strtok_escape(char *, char *, char **);
44 
45 typedef 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  */
57 static int
58 check_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  */
94 static int
95 check_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 
128 static  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*/
188 static 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 
249 static 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 				char *val_save = val;
286 
287 				massage_netdb((const char **)&val, &vallen);
288 				res = _exec_nis_parse((const char *)val,
289 				    vallen, argp, check_policy);
290 				free(val_save);
291 				break;
292 			}
293 		} while (res == NSS_SUCCESS);
294 	} else {
295 		int			ypstat = YPERR_YPERR;
296 		struct ypall_callback	cback;
297 		_exec_nis_args		eargs;
298 
299 		eargs.yp_status = &ypstat;
300 		eargs.argp = argp;
301 
302 		cback.foreach = _exec_nis_cb;
303 		cback.data = (void *)&eargs;
304 
305 		/*
306 		 * Instead of calling yp_all() doing hard lookup, we use
307 		 * the alternative function, __yp_all_cflookup(), to
308 		 * perform soft lookup when binding to nis servers with
309 		 * time-out control. Other than that, these two functions
310 		 * do exactly the same thing.
311 		 */
312 		ypstatus = __yp_all_cflookup((char *)(be->domain),
313 			(char *)(be->enum_map), &cback, 0);
314 
315 		/*
316 		 * For GET_ALL, check if we found anything at all.
317 		 */
318 		if (_priv_exec->head_exec != NULL)
319 			return (NSS_SUCCESS);
320 
321 		switch (ypstat) {
322 		case 0:
323 			res = NSS_SUCCESS;
324 			break;
325 		case YPERR_BUSY:
326 			res = NSS_TRYAGAIN;
327 			break;
328 		default:
329 			res = NSS_UNAVAIL;
330 			break;
331 		}
332 
333 	}
334 
335 	return (res);
336 }
337 
338 /*
339  * If search for exact match for id failed, get_wild checks if we have
340  * a wild-card entry for that id.
341  */
342 static  nss_status_t
343 get_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
344 {
345 	const char	*orig_id;
346 	char		*old_id = NULL;
347 	char		*wild_id = NULL;
348 	nss_status_t	res = NSS_NOTFOUND;
349 	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
350 
351 	orig_id = _priv_exec->id;
352 	old_id = strdup(_priv_exec->id);
353 	wild_id = old_id;
354 	while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) {
355 		_priv_exec->id = wild_id;
356 		res = _exec_nis_lookup(be, argp, getby_flag);
357 		if (res == NSS_SUCCESS)
358 			break;
359 	}
360 	_priv_exec->id = orig_id;
361 	if (old_id)
362 		free(old_id);
363 
364 	return (res);
365 }
366 
367 
368 static  nss_status_t
369 getbynam(nis_backend_ptr_t be, void *a)
370 {
371 	nss_status_t	res;
372 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
373 
374 	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME);
375 
376 	_exec_cleanup(res, argp);
377 
378 	return (res);
379 }
380 
381 static  nss_status_t
382 getbyid(nis_backend_ptr_t be, void *a)
383 {
384 	nss_status_t	res;
385 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
386 	/*LINTED*/
387 	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
388 
389 	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID);
390 
391 	if (res != NSS_SUCCESS)
392 		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
393 
394 	_exec_cleanup(res, argp);
395 
396 	return (res);
397 }
398 
399 
400 static  nss_status_t
401 getbynameid(nis_backend_ptr_t be, void *a)
402 {
403 	nss_status_t	res;
404 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
405 	/*LINTED*/
406 	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);
407 
408 	res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
409 
410 	if (res != NSS_SUCCESS)
411 		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
412 
413 	_exec_cleanup(res, argp);
414 
415 	return (res);
416 }
417 
418 
419 static nis_backend_op_t execattr_ops[] = {
420 	_nss_nis_destr,
421 	_nss_nis_endent,
422 	_nss_nis_setent,
423 	_nss_nis_getent_netdb,
424 	getbynam,
425 	getbyid,
426 	getbynameid
427 };
428 
429 /*ARGSUSED*/
430 nss_backend_t *
431 _nss_nis_exec_attr_constr(const char *dummy1,
432     const char *dummy2,
433     const char *dummy3,
434     const char *dummy4,
435     const char *dummy5,
436     const char *dummy6,
437     const char *dummy7)
438 {
439 	return (_nss_nis_constr(execattr_ops,
440 		sizeof (execattr_ops)/sizeof (execattr_ops[0]),
441 		NIS_MAP_EXECATTR));
442 }
443