Home | History | Annotate | Download | only in common
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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 *
    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