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 char *val_save = val; 286 287 massage_netdb((const char **)&val, &vallen); 288 res = _exec_nis_parse((const char *)val, 289 vallen, argp, check_policy); 290 free(val_save); 291 break; 292 } 293 } while (res == NSS_SUCCESS); 294 } else { 295 int ypstat = YPERR_YPERR; 296 struct ypall_callback cback; 297 _exec_nis_args eargs; 298 299 eargs.yp_status = &ypstat; 300 eargs.argp = argp; 301 302 cback.foreach = _exec_nis_cb; 303 cback.data = (void *)&eargs; 304 305 /* 306 * Instead of calling yp_all() doing hard lookup, we use 307 * the alternative function, __yp_all_cflookup(), to 308 * perform soft lookup when binding to nis servers with 309 * time-out control. Other than that, these two functions 310 * do exactly the same thing. 311 */ 312 ypstatus = __yp_all_cflookup((char *)(be->domain), 313 (char *)(be->enum_map), &cback, 0); 314 315 /* 316 * For GET_ALL, check if we found anything at all. 317 */ 318 if (_priv_exec->head_exec != NULL) 319 return (NSS_SUCCESS); 320 321 switch (ypstat) { 322 case 0: 323 res = NSS_SUCCESS; 324 break; 325 case YPERR_BUSY: 326 res = NSS_TRYAGAIN; 327 break; 328 default: 329 res = NSS_UNAVAIL; 330 break; 331 } 332 333 } 334 335 return (res); 336 } 337 338 /* 339 * If search for exact match for id failed, get_wild checks if we have 340 * a wild-card entry for that id. 341 */ 342 static nss_status_t 343 get_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) 344 { 345 const char *orig_id; 346 char *old_id = NULL; 347 char *wild_id = NULL; 348 nss_status_t res = NSS_NOTFOUND; 349 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 350 351 orig_id = _priv_exec->id; 352 old_id = strdup(_priv_exec->id); 353 wild_id = old_id; 354 while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) { 355 _priv_exec->id = wild_id; 356 res = _exec_nis_lookup(be, argp, getby_flag); 357 if (res == NSS_SUCCESS) 358 break; 359 } 360 _priv_exec->id = orig_id; 361 if (old_id) 362 free(old_id); 363 364 return (res); 365 } 366 367 368 static nss_status_t 369 getbynam(nis_backend_ptr_t be, void *a) 370 { 371 nss_status_t res; 372 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 373 374 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME); 375 376 _exec_cleanup(res, argp); 377 378 return (res); 379 } 380 381 static nss_status_t 382 getbyid(nis_backend_ptr_t be, void *a) 383 { 384 nss_status_t res; 385 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 386 /*LINTED*/ 387 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 388 389 res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID); 390 391 if (res != NSS_SUCCESS) 392 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID); 393 394 _exec_cleanup(res, argp); 395 396 return (res); 397 } 398 399 400 static nss_status_t 401 getbynameid(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_BYNAMEID); 409 410 if (res != NSS_SUCCESS) 411 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); 412 413 _exec_cleanup(res, argp); 414 415 return (res); 416 } 417 418 419 static nis_backend_op_t execattr_ops[] = { 420 _nss_nis_destr, 421 _nss_nis_endent, 422 _nss_nis_setent, 423 _nss_nis_getent_netdb, 424 getbynam, 425 getbyid, 426 getbynameid 427 }; 428 429 /*ARGSUSED*/ 430 nss_backend_t * 431 _nss_nis_exec_attr_constr(const char *dummy1, 432 const char *dummy2, 433 const char *dummy3, 434 const char *dummy4, 435 const char *dummy5, 436 const char *dummy6, 437 const char *dummy7) 438 { 439 return (_nss_nis_constr(execattr_ops, 440 sizeof (execattr_ops)/sizeof (execattr_ops[0]), 441 NIS_MAP_EXECATTR)); 442 } 443