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 2007 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 /* 206 * If we have no more data to look at, we want to 207 * keep yp_status from previous key/value pair 208 * that we processed. 209 * If this is the 1st time we enter this callback, 210 * yp_status is already set to YPERR_YPERR 211 * (see _exec_nis_lookup() for when this callback 212 * and arguments are set initially). 213 */ 214 if (instatus != YP_NOMORE) { 215 *(eargp->yp_status) = YPERR_YPERR; 216 } 217 return (0); /* yp_all may decide otherwise... */ 218 } 219 220 filter = (_priv_exec->name) ? _priv_exec->name : _priv_exec->id; 221 222 /* 223 * yp_all does not null terminate the entry it retrieves from the 224 * map, unlike yp_match. so we do it explicitly here. 225 */ 226 inval[invallen] = '\0'; 227 228 /* 229 * Optimization: if the entry doesn't contain the filter string then 230 * it can't be the entry we want, so don't bother looking more closely 231 * at it. 232 */ 233 if ((_priv_exec->policy && 234 (strstr(inval, _priv_exec->policy) == NULL)) || 235 (strstr(inval, filter) == NULL)) { 236 *(eargp->yp_status) = YPERR_KEY; 237 return (0); 238 } 239 240 res = _exec_nis_parse(inval, invallen, argp, check_policy); 241 242 switch (res) { 243 case NSS_SUCCESS: 244 *(eargp->yp_status) = 0; 245 stop_cb = (_priv_exec->search_flag == GET_ONE); 246 break; 247 case NSS_UNAVAIL: 248 *(eargp->yp_status) = YPERR_KEY; 249 stop_cb = 1; 250 break; 251 default: 252 *(eargp->yp_status) = YPERR_YPERR; 253 stop_cb = 0; 254 break; 255 } 256 257 return (stop_cb); 258 } 259 260 static nss_status_t 261 _exec_nis_lookup(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) 262 { 263 int ypstatus; 264 nss_status_t res = NSS_SUCCESS; 265 nss_status_t ypres; 266 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 267 268 if (getby_flag == NSS_DBOP_EXECATTR_BYNAMEID) { 269 int check_policy = 0; 270 int vallen; 271 char *val; 272 char key[MAX_INPUT]; 273 274 /* 275 * Try using policy as part of search key. If that fails, 276 * (it will, in case of pre-Solaris9 nis server where policy 277 * was not searchable), try again without using policy. 278 */ 279 if (snprintf(key, MAX_INPUT, "%s%s%s%s%s", _priv_exec->name, 280 KV_TOKEN_DELIMIT, _priv_exec->policy, KV_TOKEN_DELIMIT, 281 _priv_exec->id) >= MAX_INPUT) 282 return (NSS_NOTFOUND); 283 do { 284 ypres = _nss_nis_ypmatch(be->domain, NIS_MAP_EXECATTR, 285 key, &val, &vallen, &ypstatus); 286 if ((check_policy == 0) && (ypstatus == YPERR_KEY)) { 287 (void) snprintf(key, MAX_INPUT, "%s%s%s", 288 _priv_exec->name, KV_TOKEN_DELIMIT, 289 _priv_exec->id); 290 check_policy = 1; 291 continue; 292 } else if (ypres != NSS_SUCCESS) { 293 res = ypres; 294 break; 295 } else { 296 char *val_save = val; 297 298 massage_netdb((const char **)&val, &vallen); 299 res = _exec_nis_parse((const char *)val, 300 vallen, argp, check_policy); 301 free(val_save); 302 break; 303 } 304 } while (res == NSS_SUCCESS); 305 } else { 306 int ypstat = YPERR_YPERR; 307 struct ypall_callback cback; 308 _exec_nis_args eargs; 309 310 eargs.yp_status = &ypstat; 311 eargs.argp = argp; 312 313 cback.foreach = _exec_nis_cb; 314 cback.data = (void *)&eargs; 315 316 /* 317 * Instead of calling yp_all() doing hard lookup, we use 318 * the alternative function, __yp_all_cflookup(), to 319 * perform soft lookup when binding to nis servers with 320 * time-out control. Other than that, these two functions 321 * do exactly the same thing. 322 */ 323 ypstatus = __yp_all_cflookup((char *)(be->domain), 324 (char *)(be->enum_map), &cback, 0); 325 326 /* 327 * For GET_ALL, check if we found anything at all. 328 */ 329 if (_priv_exec->head_exec != NULL) 330 return (NSS_SUCCESS); 331 332 switch (ypstat) { 333 case 0: 334 res = NSS_SUCCESS; 335 break; 336 case YPERR_BUSY: 337 res = NSS_TRYAGAIN; 338 break; 339 case YPERR_KEY: 340 /* 341 * If no such key, return NSS_NOTFOUND 342 * as this looks more relevant; it will 343 * also help libnsl to try with another 344 * policy (see _getexecprof()). 345 */ 346 res = NSS_NOTFOUND; 347 break; 348 default: 349 res = NSS_UNAVAIL; 350 break; 351 } 352 353 } 354 355 return (res); 356 } 357 358 /* 359 * If search for exact match for id failed, get_wild checks if we have 360 * a wild-card entry for that id. 361 */ 362 static nss_status_t 363 get_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) 364 { 365 const char *orig_id; 366 char *old_id = NULL; 367 char *wild_id = NULL; 368 nss_status_t res = NSS_NOTFOUND; 369 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 370 371 orig_id = _priv_exec->id; 372 old_id = strdup(_priv_exec->id); 373 wild_id = old_id; 374 while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) { 375 _priv_exec->id = wild_id; 376 res = _exec_nis_lookup(be, argp, getby_flag); 377 if (res == NSS_SUCCESS) 378 break; 379 } 380 _priv_exec->id = orig_id; 381 if (old_id) 382 free(old_id); 383 384 return (res); 385 } 386 387 388 static nss_status_t 389 getbynam(nis_backend_ptr_t be, void *a) 390 { 391 nss_status_t res; 392 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 393 394 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME); 395 396 _exec_cleanup(res, argp); 397 398 return (res); 399 } 400 401 static nss_status_t 402 getbyid(nis_backend_ptr_t be, void *a) 403 { 404 nss_status_t res; 405 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 406 /*LINTED*/ 407 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 408 409 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID); 410 411 if (res != NSS_SUCCESS) 412 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID); 413 414 _exec_cleanup(res, argp); 415 416 return (res); 417 } 418 419 420 static nss_status_t 421 getbynameid(nis_backend_ptr_t be, void *a) 422 { 423 nss_status_t res; 424 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 425 /*LINTED*/ 426 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 427 428 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); 429 430 if (res != NSS_SUCCESS) 431 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); 432 433 _exec_cleanup(res, argp); 434 435 return (res); 436 } 437 438 439 static nis_backend_op_t execattr_ops[] = { 440 _nss_nis_destr, 441 _nss_nis_endent, 442 _nss_nis_setent, 443 _nss_nis_getent_netdb, 444 getbynam, 445 getbyid, 446 getbynameid 447 }; 448 449 /*ARGSUSED*/ 450 nss_backend_t * 451 _nss_nis_exec_attr_constr(const char *dummy1, 452 const char *dummy2, 453 const char *dummy3, 454 const char *dummy4, 455 const char *dummy5, 456 const char *dummy6, 457 const char *dummy7) 458 { 459 return (_nss_nis_constr(execattr_ops, 460 sizeof (execattr_ops)/sizeof (execattr_ops[0]), 461 NIS_MAP_EXECATTR)); 462 } 463