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