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 				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  */
339 static  nss_status_t
340 get_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 
365 static  nss_status_t
366 getbynam(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 
378 static  nss_status_t
379 getbyid(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 
397 static  nss_status_t
398 getbynameid(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 
416 static 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*/
427 nss_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