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