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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.22.5.1 */ 32 33 /* 34 * UNIX shell 35 */ 36 37 #include "defs.h" 38 #include <errno.h> 39 #include <fcntl.h> 40 #include "sh_policy.h" 41 42 #define ARGMK 01 43 44 static unsigned char *execs(); 45 static int gsort(); 46 static int split(); 47 extern const char *sysmsg[]; 48 extern short topfd; 49 50 51 52 /* 53 * service routines for `execute' 54 */ 55 initio(iop, save) 56 struct ionod *iop; 57 int save; 58 { 59 register unsigned char *ion; 60 register int iof, fd; 61 int ioufd; 62 short lastfd; 63 int newmode; 64 65 lastfd = topfd; 66 while (iop) { 67 iof = iop->iofile; 68 ion = mactrim(iop->ioname); 69 ioufd = iof & IOUFD; 70 71 if (*ion && (flags&noexec) == 0) { 72 if (save) { 73 fdmap[topfd].org_fd = ioufd; 74 fdmap[topfd++].dup_fd = savefd(ioufd); 75 } 76 77 if (iof & IODOC) { 78 struct tempblk tb; 79 80 subst(chkopen(ion, 0), (fd = tmpfil(&tb))); 81 82 /* 83 * pushed in tmpfil() -- 84 * bug fix for problem with 85 * in-line scripts 86 */ 87 poptemp(); 88 89 fd = chkopen(tmpout, 0); 90 unlink((const char *)tmpout); 91 } else if (iof & IOMOV) { 92 if (eq(minus, ion)) { 93 fd = -1; 94 close(ioufd); 95 } else if ((fd = stoi(ion)) >= USERIO) { 96 failed(ion, badfile); 97 } 98 else 99 fd = dup(fd); 100 } else if (((iof & IOPUT) == 0) && ((iof & IORDW) == 0)) 101 fd = chkopen(ion, 0); 102 else if (iof & IORDW) /* For <> */ { 103 newmode = O_RDWR|O_CREAT; 104 fd = chkopen(ion, newmode); 105 } else if (flags & rshflg) { 106 failed(ion, restricted); 107 } else if (iof & IOAPP && 108 (fd = open((char *)ion, 1)) >= 0) { 109 lseek(fd, (off_t)0, SEEK_END); 110 } else { 111 fd = create(ion); 112 } 113 if (fd >= 0) 114 renamef(fd, ioufd); 115 } 116 117 iop = iop->ionxt; 118 } 119 return (lastfd); 120 } 121 122 unsigned char * 123 simple(s) 124 unsigned char *s; 125 { 126 unsigned char *sname; 127 128 sname = s; 129 while (1) { 130 if (any('/', sname)) 131 while (*sname++ != '/') 132 ; 133 else 134 return (sname); 135 } 136 } 137 138 unsigned char * 139 getpath(s) 140 unsigned char *s; 141 { 142 register unsigned char *path, *newpath; 143 register int pathlen; 144 145 if (any('/', s)) 146 { 147 if (flags & rshflg) 148 failed(s, restricted); 149 else 150 return ((unsigned char *)nullstr); 151 } else if ((path = pathnod.namval) == 0) 152 return ((unsigned char *)defpath); 153 else { 154 pathlen = length(path)-1; 155 /* Add extra ':' if PATH variable ends in ':' */ 156 if (pathlen > 2 && path[pathlen - 1] == ':' && 157 path[pathlen - 2] != ':') { 158 newpath = locstak(); 159 (void) memcpystak(newpath, path, pathlen); 160 newpath[pathlen] = ':'; 161 endstak(newpath + pathlen + 1); 162 return (newpath); 163 } else 164 return (cpystak(path)); 165 } 166 } 167 168 pathopen(path, name) 169 register unsigned char *path, *name; 170 { 171 register int f; 172 173 do 174 { 175 path = catpath(path, name); 176 } while ((f = open((char *)curstak(), 0)) < 0 && path); 177 return (f); 178 } 179 180 unsigned char * 181 catpath(path, name) 182 register unsigned char *path; 183 unsigned char *name; 184 { 185 /* 186 * leaves result on top of stack 187 */ 188 register unsigned char *scanp = path; 189 register unsigned char *argp = locstak(); 190 191 while (*scanp && *scanp != COLON) 192 { 193 if (argp >= brkend) 194 growstak(argp); 195 *argp++ = *scanp++; 196 } 197 if (scanp != path) 198 { 199 if (argp >= brkend) 200 growstak(argp); 201 *argp++ = '/'; 202 } 203 if (*scanp == COLON) 204 scanp++; 205 path = (*scanp ? scanp : 0); 206 scanp = name; 207 do 208 { 209 if (argp >= brkend) 210 growstak(argp); 211 } 212 while (*argp++ = *scanp++); 213 return (path); 214 } 215 216 unsigned char * 217 nextpath(path) 218 register unsigned char *path; 219 { 220 register unsigned char *scanp = path; 221 222 while (*scanp && *scanp != COLON) 223 scanp++; 224 225 if (*scanp == COLON) 226 scanp++; 227 228 return (*scanp ? scanp : 0); 229 } 230 231 static unsigned char *xecmsg; 232 static unsigned char **xecenv; 233 234 int 235 execa(at, pos) 236 unsigned char *at[]; 237 short pos; 238 { 239 register unsigned char *path; 240 register unsigned char **t = at; 241 int cnt; 242 243 if ((flags & noexec) == 0) 244 { 245 xecmsg = (unsigned char *)notfound; 246 path = getpath(*t); 247 xecenv = local_setenv(); 248 249 if (pos > 0) 250 { 251 cnt = 1; 252 while (cnt != pos) 253 { 254 ++cnt; 255 path = nextpath(path); 256 } 257 execs(path, t); 258 path = getpath(*t); 259 } 260 while (path = execs(path, t)) 261 ; 262 failed(*t, xecmsg); 263 } 264 } 265 266 static unsigned char * 267 execs(ap, t) 268 unsigned char *ap; 269 register unsigned char *t[]; 270 { 271 register int pfstatus = NOATTRS; 272 register unsigned char *p, *prefix; 273 unsigned char *savptr; 274 275 prefix = catpath(ap, t[0]); 276 trim(p = curstak()); 277 sigchk(); 278 279 if (flags & pfshflg) { 280 /* 281 * Need to save the stack information, or the 282 * first memory allocation in secpolicy_profile_lookup() 283 * will clobber it. 284 */ 285 savptr = endstak(p + strlen((const char *)p) + 1); 286 287 pfstatus = secpolicy_pfexec((const char *)p, 288 (char **)t, (const char **)xecenv); 289 290 if (pfstatus != NOATTRS) { 291 errno = pfstatus; 292 } 293 294 tdystak(savptr); 295 } 296 297 if (pfstatus == NOATTRS) { 298 execve((const char *)p, (char *const *)&t[0], 299 (char *const *)xecenv); 300 } 301 302 switch (errno) 303 { 304 case ENOEXEC: /* could be a shell script */ 305 funcnt = 0; 306 flags = 0; 307 *flagadr = 0; 308 comdiv = 0; 309 ioset = 0; 310 clearup(); /* remove open files and for loop junk */ 311 if (input) 312 close(input); 313 input = chkopen(p, 0); 314 315 #ifdef ACCT 316 preacct(p); /* reset accounting */ 317 #endif 318 319 /* 320 * set up new args 321 */ 322 323 setargs(t); 324 longjmp(subshell, 1); 325 326 case ENOMEM: 327 failed(p, toobig); 328 329 case E2BIG: 330 failed(p, arglist); 331 332 case ETXTBSY: 333 failed(p, txtbsy); 334 335 case ELIBACC: 336 failed(p, libacc); 337 338 case ELIBBAD: 339 failed(p, libbad); 340 341 case ELIBSCN: 342 failed(p, libscn); 343 344 case ELIBMAX: 345 failed(p, libmax); 346 347 default: 348 xecmsg = (unsigned char *)badexec; 349 case ENOENT: 350 return (prefix); 351 } 352 } 353 354 BOOL nosubst; 355 356 trim(at) 357 unsigned char *at; 358 { 359 register unsigned char *last; 360 register unsigned char *current; 361 register unsigned char c; 362 int len; 363 wchar_t wc; 364 365 nosubst = 0; 366 if (current = at) 367 { 368 last = at; 369 while (c = *current) { 370 if ((len = mbtowc(&wc, (char *)current, 371 MB_LEN_MAX)) <= 0) { 372 *last++ = c; 373 current++; 374 continue; 375 } 376 377 if (wc != '\\') { 378 memcpy(last, current, len); 379 last += len; 380 current += len; 381 continue; 382 } 383 384 /* remove \ and quoted nulls */ 385 nosubst = 1; 386 current++; 387 if (c = *current) { 388 if ((len = mbtowc(&wc, (char *)current, 389 MB_LEN_MAX)) <= 0) { 390 *last++ = c; 391 current++; 392 continue; 393 } 394 memcpy(last, current, len); 395 last += len; 396 current += len; 397 } else 398 current++; 399 } 400 401 *last = 0; 402 } 403 } 404 405 /* Same as trim, but only removes backlashes before slashes */ 406 trims(at) 407 unsigned char *at; 408 { 409 register unsigned char *last; 410 register unsigned char *current; 411 register unsigned char c; 412 int len; 413 wchar_t wc; 414 415 if (current = at) 416 { 417 last = at; 418 while (c = *current) { 419 if ((len = mbtowc(&wc, (char *)current, 420 MB_LEN_MAX)) <= 0) { 421 *last++ = c; 422 current++; 423 continue; 424 } 425 426 if (wc != '\\') { 427 memcpy(last, current, len); 428 last += len; current += len; 429 continue; 430 } 431 432 /* remove \ and quoted nulls */ 433 current++; 434 if (!(c = *current)) { 435 current++; 436 continue; 437 } 438 439 if (c == '/') { 440 *last++ = c; 441 current++; 442 continue; 443 } 444 445 *last++ = '\\'; 446 if ((len = mbtowc(&wc, (char *)current, 447 MB_LEN_MAX)) <= 0) { 448 *last++ = c; 449 current++; 450 continue; 451 } 452 memcpy(last, current, len); 453 last += len; current += len; 454 } 455 *last = 0; 456 } 457 } 458 459 unsigned char * 460 mactrim(s) 461 unsigned char *s; 462 { 463 register unsigned char *t = macro(s); 464 465 trim(t); 466 return (t); 467 } 468 469 unsigned char ** 470 scan(argn) 471 int argn; 472 { 473 register struct argnod *argp = 474 (struct argnod *)(Rcheat(gchain) & ~ARGMK); 475 register unsigned char **comargn, **comargm; 476 477 comargn = (unsigned char **)getstak(BYTESPERWORD * argn + BYTESPERWORD); 478 comargm = comargn += argn; 479 *comargn = ENDARGS; 480 while (argp) 481 { 482 *--comargn = argp->argval; 483 484 trim(*comargn); 485 argp = argp->argnxt; 486 487 if (argp == 0 || Rcheat(argp) & ARGMK) 488 { 489 gsort(comargn, comargm); 490 comargm = comargn; 491 } 492 argp = (struct argnod *)(Rcheat(argp) & ~ARGMK); 493 } 494 return (comargn); 495 } 496 497 static int 498 gsort(from, to) 499 unsigned char *from[], *to[]; 500 { 501 int k, m, n; 502 register int i, j; 503 504 if ((n = to - from) <= 1) 505 return; 506 for (j = 1; j <= n; j *= 2) 507 ; 508 for (m = 2 * j - 1; m /= 2; ) 509 { 510 k = n - m; 511 for (j = 0; j < k; j++) 512 { 513 for (i = j; i >= 0; i -= m) 514 { 515 register unsigned char **fromi; 516 517 fromi = &from[i]; 518 if (cf(fromi[m], fromi[0]) > 0) 519 { 520 break; 521 } 522 else 523 { 524 unsigned char *s; 525 526 s = fromi[m]; 527 fromi[m] = fromi[0]; 528 fromi[0] = s; 529 } 530 } 531 } 532 } 533 } 534 535 /* 536 * Argument list generation 537 */ 538 getarg(ac) 539 struct comnod *ac; 540 { 541 register struct argnod *argp; 542 register int count = 0; 543 register struct comnod *c; 544 545 if (c = ac) 546 { 547 argp = c->comarg; 548 while (argp) 549 { 550 count += split(macro(argp->argval), 1); 551 argp = argp->argnxt; 552 } 553 } 554 return (count); 555 } 556 557 static int 558 split(s) /* blank interpretation routine */ 559 unsigned char *s; 560 { 561 register unsigned char *argp; 562 register int c; 563 int count = 0; 564 for (;;) 565 { 566 register int length; 567 sigchk(); 568 argp = locstak() + BYTESPERWORD; 569 while (c = *s) { 570 wchar_t wc; 571 if ((length = mbtowc(&wc, (char *)s, 572 MB_LEN_MAX)) <= 0) { 573 wc = (unsigned char)*s; 574 length = 1; 575 } 576 577 if (c == '\\') { /* skip over quoted characters */ 578 if (argp >= brkend) 579 growstak(argp); 580 *argp++ = c; 581 s++; 582 /* get rest of multibyte character */ 583 if ((length = mbtowc(&wc, (char *)s, 584 MB_LEN_MAX)) <= 0) { 585 wc = (unsigned char)*s; 586 length = 1; 587 } 588 if (argp >= brkend) 589 growstak(argp); 590 *argp++ = *s++; 591 while (--length > 0) { 592 if (argp >= brkend) 593 growstak(argp); 594 *argp++ = *s++; 595 } 596 continue; 597 } 598 599 if (anys(s, ifsnod.namval)) { 600 /* skip to next character position */ 601 s += length; 602 break; 603 } 604 605 if (argp >= brkend) 606 growstak(argp); 607 *argp++ = c; 608 s++; 609 while (--length > 0) { 610 if (argp >= brkend) 611 growstak(argp); 612 *argp++ = *s++; 613 } 614 } 615 if (argp == staktop + BYTESPERWORD) 616 { 617 if (c) 618 { 619 continue; 620 } 621 else 622 { 623 return (count); 624 } 625 } 626 /* 627 * file name generation 628 */ 629 630 argp = endstak(argp); 631 trims(((struct argnod *)argp)->argval); 632 if ((flags & nofngflg) == 0 && 633 (c = expand(((struct argnod *)argp)->argval, 0))) 634 count += c; 635 else 636 { 637 makearg(argp); 638 count++; 639 } 640 gchain = (struct argnod *)((int)gchain | ARGMK); 641 } 642 } 643 644 #ifdef ACCT 645 #include <sys/types.h> 646 #include <sys/acct.h> 647 #include <sys/times.h> 648 649 struct acct sabuf; 650 struct tms buffer; 651 static clock_t before; 652 static int shaccton; /* 0 implies do not write record on exit */ 653 /* 1 implies write acct record on exit */ 654 655 656 /* 657 * suspend accounting until turned on by preacct() 658 */ 659 660 suspacct() 661 { 662 shaccton = 0; 663 } 664 665 preacct(cmdadr) 666 unsigned char *cmdadr; 667 { 668 unsigned char *simple(); 669 670 if (acctnod.namval && *acctnod.namval) 671 { 672 sabuf.ac_btime = time((time_t *)0); 673 before = times(&buffer); 674 sabuf.ac_uid = getuid(); 675 sabuf.ac_gid = getgid(); 676 movstrn(simple(cmdadr), sabuf.ac_comm, sizeof (sabuf.ac_comm)); 677 shaccton = 1; 678 } 679 } 680 681 682 doacct() 683 { 684 int fd; 685 clock_t after; 686 687 if (shaccton) { 688 after = times(&buffer); 689 sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); 690 sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); 691 sabuf.ac_etime = compress(after - before); 692 693 if ((fd = open((char *)acctnod.namval, 694 O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) { 695 write(fd, &sabuf, sizeof (sabuf)); 696 close(fd); 697 } 698 } 699 } 700 701 /* 702 * Produce a pseudo-floating point representation 703 * with 3 bits base-8 exponent, 13 bits fraction 704 */ 705 706 compress(t) 707 register clock_t t; 708 { 709 register exp = 0; 710 register rund = 0; 711 712 while (t >= 8192) 713 { 714 exp++; 715 rund = t & 04; 716 t >>= 3; 717 } 718 719 if (rund) 720 { 721 t++; 722 if (t >= 8192) 723 { 724 t >>= 3; 725 exp++; 726 } 727 } 728 return ((exp << 13) + t); 729 } 730 #endif 731