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