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