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