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