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