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