Home | History | Annotate | Download | only in sh
      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 2008 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_SUBST) {
     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