xref: /titanic_44/usr/src/cmd/sh/service.c (revision b7f45089ccbe01bab3d7c7377b49d80d2ae18a69)
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