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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 /* 32 * UNIX shell 33 */ 34 35 #include "hash.h" 36 #include "defs.h" 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <errno.h> 40 41 #define EXECUTE 01 42 43 static unsigned char cost; 44 static int dotpath; 45 static int multrel; 46 static struct entry relcmd; 47 48 static int argpath(); 49 static void pr_path(unsigned char *, int); 50 51 short 52 pathlook(com, flg, arg) 53 unsigned char *com; 54 int flg; 55 struct argnod *arg; 56 { 57 unsigned char *name = com; 58 ENTRY *h; 59 60 ENTRY hentry; 61 int count = 0; 62 int i; 63 int pathset = 0; 64 int oldpath = 0; 65 struct namnod *n; 66 67 68 69 hentry.data = 0; 70 71 if (any('/', name)) 72 return(COMMAND); 73 74 h = hfind(name); 75 76 77 if (h) 78 { 79 if (h->data & (BUILTIN | FUNCTION)) 80 { 81 if (flg) 82 h->hits++; 83 return(h->data); 84 } 85 86 if (arg && (pathset = argpath(arg))) 87 return(PATH_COMMAND); 88 89 if ((h->data & DOT_COMMAND) == DOT_COMMAND) 90 { 91 if (multrel == 0 && hashdata(h->data) > dotpath) 92 oldpath = hashdata(h->data); 93 else 94 oldpath = dotpath; 95 96 h->data = 0; 97 goto pathsrch; 98 } 99 100 if (h->data & (COMMAND | REL_COMMAND)) 101 { 102 if (flg) 103 h->hits++; 104 return(h->data); 105 } 106 107 h->data = 0; 108 h->cost = 0; 109 } 110 111 if (i = syslook(name, commands, no_commands)) 112 { 113 hentry.data = (BUILTIN | i); 114 count = 1; 115 } 116 else 117 { 118 if (arg && (pathset = argpath(arg))) 119 return(PATH_COMMAND); 120 pathsrch: 121 count = findpath(name, oldpath); 122 } 123 124 if (count > 0) 125 { 126 if (h == 0) 127 { 128 hentry.cost = 0; 129 hentry.key = make(name); 130 h = henter(hentry); 131 } 132 133 if (h->data == 0) 134 { 135 if (count < dotpath) 136 h->data = COMMAND | count; 137 else 138 { 139 h->data = REL_COMMAND | count; 140 h->next = relcmd.next; 141 relcmd.next = h; 142 } 143 } 144 145 146 h->hits = flg; 147 h->cost += cost; 148 return(h->data); 149 } 150 else 151 { 152 return(-count); 153 } 154 } 155 156 157 static void 158 zapentry(h) 159 ENTRY *h; 160 { 161 h->data &= HASHZAP; 162 } 163 164 void 165 zaphash() 166 { 167 hscan(zapentry); 168 relcmd.next = 0; 169 } 170 171 void 172 zapcd() 173 { 174 ENTRY *ptr = relcmd.next; 175 176 while (ptr) 177 { 178 ptr->data |= CDMARK; 179 ptr = ptr->next; 180 } 181 relcmd.next = 0; 182 } 183 184 185 static void 186 hashout(h) 187 ENTRY *h; 188 { 189 sigchk(); 190 191 if (hashtype(h->data) == NOTFOUND) 192 return; 193 194 if (h->data & (BUILTIN | FUNCTION)) 195 return; 196 197 prn_buff(h->hits); 198 199 if (h->data & REL_COMMAND) 200 prc_buff('*'); 201 202 203 prc_buff(TAB); 204 prn_buff(h->cost); 205 prc_buff(TAB); 206 207 pr_path(h->key, hashdata(h->data)); 208 prc_buff(NL); 209 } 210 211 void 212 hashpr() 213 { 214 prs_buff(_gettext("hits cost command\n")); 215 hscan(hashout); 216 } 217 218 void 219 set_dotpath(void) 220 { 221 unsigned char *path; 222 int cnt = 1; 223 224 dotpath = 10000; 225 path = getpath(""); 226 227 while (path && *path) 228 { 229 if (*path == '/') 230 cnt++; 231 else 232 { 233 if (dotpath == 10000) 234 dotpath = cnt; 235 else 236 { 237 multrel = 1; 238 return; 239 } 240 } 241 242 path = nextpath(path); 243 } 244 245 multrel = 0; 246 } 247 248 void 249 hash_func(unsigned char *name) 250 { 251 ENTRY *h; 252 ENTRY hentry; 253 254 h = hfind(name); 255 256 if (h) 257 h->data = FUNCTION; 258 else 259 { 260 hentry.data = FUNCTION; 261 hentry.key = make(name); 262 hentry.cost = 0; 263 hentry.hits = 0; 264 henter(hentry); 265 } 266 } 267 268 void 269 func_unhash(unsigned char *name) 270 { 271 ENTRY *h; 272 int i; 273 274 h = hfind(name); 275 276 if (h && (h->data & FUNCTION)) { 277 if(i = syslook(name, commands, no_commands)) 278 h->data = (BUILTIN|i); 279 else 280 h->data = NOTFOUND; 281 } 282 } 283 284 285 short 286 hash_cmd(name) 287 unsigned char *name; 288 { 289 ENTRY *h; 290 291 if (any('/', name)) 292 return(COMMAND); 293 294 h = hfind(name); 295 296 if (h) 297 { 298 if (h->data & (BUILTIN | FUNCTION)) 299 return(h->data); 300 else if ((h->data & REL_COMMAND) == REL_COMMAND) 301 { /* unlink h from relative command list */ 302 ENTRY *ptr = &relcmd; 303 while(ptr-> next != h) 304 ptr = ptr->next; 305 ptr->next = h->next; 306 } 307 zapentry(h); 308 } 309 310 return(pathlook(name, 0, 0)); 311 } 312 313 314 /* 315 * Return 0 if found, 1 if not. 316 */ 317 int 318 what_is_path(unsigned char *name) 319 { 320 ENTRY *h; 321 int cnt; 322 short hashval; 323 324 h = hfind(name); 325 326 prs_buff(name); 327 if (h) 328 { 329 hashval = hashdata(h->data); 330 331 switch (hashtype(h->data)) 332 { 333 case BUILTIN: 334 prs_buff(_gettext(" is a shell builtin\n")); 335 return (0); 336 337 case FUNCTION: 338 { 339 struct namnod *n = lookup(name); 340 341 prs_buff(_gettext(" is a function\n")); 342 prs_buff(name); 343 prs_buff("(){\n"); 344 prf(n->namenv); 345 prs_buff("\n}\n"); 346 return (0); 347 } 348 349 case REL_COMMAND: 350 { 351 short hash; 352 353 if ((h->data & DOT_COMMAND) == DOT_COMMAND) 354 { 355 hash = pathlook(name, 0, 0); 356 if (hashtype(hash) == NOTFOUND) 357 { 358 prs_buff(_gettext(" not" 359 " found\n")); 360 return (1); 361 } 362 else 363 hashval = hashdata(hash); 364 } 365 } 366 367 case COMMAND: 368 prs_buff(_gettext(" is hashed (")); 369 pr_path(name, hashval); 370 prs_buff(")\n"); 371 return (0); 372 } 373 } 374 375 if (syslook(name, commands, no_commands)) 376 { 377 prs_buff(_gettext(" is a shell builtin\n")); 378 return (0); 379 } 380 381 if ((cnt = findpath(name, 0)) > 0) 382 { 383 prs_buff(_gettext(" is ")); 384 pr_path(name, cnt); 385 prc_buff(NL); 386 return (0); 387 } 388 else 389 { 390 prs_buff(_gettext(" not found\n")); 391 return (1); 392 } 393 } 394 395 int 396 findpath(unsigned char *name, int oldpath) 397 { 398 unsigned char *path; 399 int count = 1; 400 401 unsigned char *p; 402 int ok = 1; 403 int e_code = 1; 404 405 cost = 0; 406 path = getpath(name); 407 408 if (oldpath) 409 { 410 count = dotpath; 411 while (--count) 412 path = nextpath(path); 413 414 if (oldpath > dotpath) 415 { 416 catpath(path, name); 417 p = curstak(); 418 cost = 1; 419 420 if ((ok = chk_access(p, S_IEXEC, 1)) == 0) 421 return(dotpath); 422 else 423 return(oldpath); 424 } 425 else 426 count = dotpath; 427 } 428 429 while (path) 430 { 431 path = catpath(path, name); 432 cost++; 433 p = curstak(); 434 435 if ((ok = chk_access(p, S_IEXEC, 1)) == 0) 436 break; 437 else 438 e_code = max(e_code, ok); 439 440 count++; 441 } 442 443 return(ok ? -e_code : count); 444 } 445 446 /* 447 * Determine if file given by name is accessible with permissions 448 * given by mode. 449 * Regflag argument non-zero means not to consider 450 * a non-regular file as executable. 451 */ 452 453 int 454 chk_access(unsigned char *name, mode_t mode, int regflag) 455 { 456 static int flag; 457 static uid_t euid; 458 struct stat statb; 459 mode_t ftype; 460 461 if(flag == 0) { 462 euid = geteuid(); 463 flag = 1; 464 } 465 ftype = statb.st_mode & S_IFMT; 466 if (stat((char *)name, &statb) == 0) { 467 ftype = statb.st_mode & S_IFMT; 468 if(mode == S_IEXEC && regflag && ftype != S_IFREG) 469 return(2); 470 if(access((char *)name, 010|(mode>>6)) == 0) { 471 if(euid == 0) { 472 if (ftype != S_IFREG || mode != S_IEXEC) 473 return(0); 474 /* root can execute file as long as it has execute 475 permission for someone */ 476 if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))) 477 return(0); 478 return(3); 479 } 480 return(0); 481 } 482 } 483 return(errno == EACCES ? 3 : 1); 484 } 485 486 static void 487 pr_path(unsigned char *name, int count) 488 { 489 unsigned char *path; 490 491 path = getpath(name); 492 493 while (--count && path) 494 path = nextpath(path, name); 495 496 catpath(path, name); 497 prs_buff(curstak()); 498 } 499 500 501 static int 502 argpath(struct argnod *arg) 503 { 504 unsigned char *s; 505 unsigned char *start; 506 507 while (arg) 508 { 509 s = arg->argval; 510 start = s; 511 512 if (letter(*s)) 513 { 514 while (alphanum(*s)) 515 s++; 516 517 if (*s == '=') 518 { 519 *s = 0; 520 521 if (eq(start, pathname)) 522 { 523 *s = '='; 524 return(1); 525 } 526 else 527 *s = '='; 528 } 529 } 530 arg = arg->argnxt; 531 } 532 533 return(0); 534 } 535