xref: /freebsd/sys/kern/imgact_shell.c (revision 610ecfe035fa08e39d4f6f6a247a16b7e60188e7)
19454b2d8SWarner Losh /*-
2cfefd687SGarrett Wollman  * Copyright (c) 1993, David Greenman
3cfefd687SGarrett Wollman  * All rights reserved.
4cfefd687SGarrett Wollman  *
5cfefd687SGarrett Wollman  * Redistribution and use in source and binary forms, with or without
6cfefd687SGarrett Wollman  * modification, are permitted provided that the following conditions
7cfefd687SGarrett Wollman  * are met:
8cfefd687SGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
9cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
10cfefd687SGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
11cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
12cfefd687SGarrett Wollman  *    documentation and/or other materials provided with the distribution.
13cfefd687SGarrett Wollman  *
14cfefd687SGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cfefd687SGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cfefd687SGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171984b014SDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cfefd687SGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cfefd687SGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cfefd687SGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cfefd687SGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cfefd687SGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cfefd687SGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cfefd687SGarrett Wollman  * SUCH DAMAGE.
25cfefd687SGarrett Wollman  */
26cfefd687SGarrett Wollman 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
30f540b106SGarrett Wollman #include <sys/param.h>
31aa855a59SPeter Wemm #include <sys/systm.h>
32ad7507e2SSteven Wallace #include <sys/sysproto.h>
3326f9a767SRodney W. Grimes #include <sys/exec.h>
34f540b106SGarrett Wollman #include <sys/imgact.h>
35f540b106SGarrett Wollman #include <sys/kernel.h>
36cfefd687SGarrett Wollman 
3792d91f76SGarrett Wollman #if BYTE_ORDER == LITTLE_ENDIAN
38cfefd687SGarrett Wollman #define SHELLMAGIC	0x2123 /* #! */
3992d91f76SGarrett Wollman #else
4092d91f76SGarrett Wollman #define SHELLMAGIC	0x2321
4192d91f76SGarrett Wollman #endif
4292d91f76SGarrett Wollman 
43cfefd687SGarrett Wollman /*
449d5abbddSJens Schweikhardt  * Shell interpreter image activator. An interpreter name beginning
45610ecfe0SMaxim Sobolev  *	at imgp->args->begin_argv is the minimal successful exit requirement.
46cfefd687SGarrett Wollman  */
47d323ddf3SMatthew Dillon int
48c52007c2SDavid Greenman exec_shell_imgact(imgp)
49c52007c2SDavid Greenman 	struct image_params *imgp;
50cfefd687SGarrett Wollman {
51c52007c2SDavid Greenman 	const char *image_header = imgp->image_header;
52610ecfe0SMaxim Sobolev 	const char *ihp;
53610ecfe0SMaxim Sobolev 	int error, length, offset;
54cfefd687SGarrett Wollman 
55cfefd687SGarrett Wollman 	/* a shell script? */
56e0c95ed9SBruce Evans 	if (((const short *) image_header)[0] != SHELLMAGIC)
57cfefd687SGarrett Wollman 		return(-1);
58cfefd687SGarrett Wollman 
59cfefd687SGarrett Wollman 	/*
60cfefd687SGarrett Wollman 	 * Don't allow a shell script to be the shell for a shell
61cfefd687SGarrett Wollman 	 *	script. :-)
62cfefd687SGarrett Wollman 	 */
63c52007c2SDavid Greenman 	if (imgp->interpreted)
64cfefd687SGarrett Wollman 		return(ENOEXEC);
65cfefd687SGarrett Wollman 
66c52007c2SDavid Greenman 	imgp->interpreted = 1;
67cfefd687SGarrett Wollman 
68cfefd687SGarrett Wollman 	/*
69610ecfe0SMaxim Sobolev 	 * Figure out the number of bytes that need to be reserved in the
70610ecfe0SMaxim Sobolev 	 * argument string to copy the contents of the interpreter's command
71610ecfe0SMaxim Sobolev 	 * line into the argument string.
72cfefd687SGarrett Wollman 	 */
73cfefd687SGarrett Wollman 	ihp = &image_header[2];
74610ecfe0SMaxim Sobolev 	offset = 0;
75610ecfe0SMaxim Sobolev 	while (ihp < &image_header[MAXSHELLCMDLEN]) {
76610ecfe0SMaxim Sobolev 		/* Skip any whitespace */
77610ecfe0SMaxim Sobolev 		while ((*ihp == ' ') || (*ihp == '\t')) {
78610ecfe0SMaxim Sobolev 			ihp++;
79610ecfe0SMaxim Sobolev 			continue;
80610ecfe0SMaxim Sobolev 		}
81cfefd687SGarrett Wollman 
82610ecfe0SMaxim Sobolev 		/* End of line? */
83610ecfe0SMaxim Sobolev 		if ((*ihp == '\n') || (*ihp == '#'))
84610ecfe0SMaxim Sobolev 			break;
85cfefd687SGarrett Wollman 
86610ecfe0SMaxim Sobolev 		/* Found a token */
87610ecfe0SMaxim Sobolev 		while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') &&
88610ecfe0SMaxim Sobolev 		    (*ihp != '#')) {
89610ecfe0SMaxim Sobolev 			offset++;
90610ecfe0SMaxim Sobolev 			ihp++;
91610ecfe0SMaxim Sobolev 		}
92610ecfe0SMaxim Sobolev 		/* Include terminating nulls in the offset */
93610ecfe0SMaxim Sobolev 		offset++;
94610ecfe0SMaxim Sobolev 	}
95cfefd687SGarrett Wollman 
96610ecfe0SMaxim Sobolev 	/* If the script gives a null line as the interpreter, we bail */
97610ecfe0SMaxim Sobolev 	if (offset == 0)
98cfefd687SGarrett Wollman 		return (ENOEXEC);
99cfefd687SGarrett Wollman 
100610ecfe0SMaxim Sobolev 	/* Check that we aren't too big */
101610ecfe0SMaxim Sobolev 	if (offset > MAXSHELLCMDLEN)
102610ecfe0SMaxim Sobolev 		return (ENAMETOOLONG);
103cfefd687SGarrett Wollman 
104cfefd687SGarrett Wollman 	/*
105610ecfe0SMaxim Sobolev 	 * The full path name of the original script file must be tagged
106610ecfe0SMaxim Sobolev 	 * onto the end, adjust the offset to deal with it.
107610ecfe0SMaxim Sobolev 	 *
108610ecfe0SMaxim Sobolev 	 * The original argv[0] is being replaced, set 'length' to the number
109610ecfe0SMaxim Sobolev 	 * of bytes being removed.  So 'offset' is the number of bytes being
110610ecfe0SMaxim Sobolev 	 * added and 'length' is the number of bytes being removed.
111cfefd687SGarrett Wollman 	 */
112610ecfe0SMaxim Sobolev 	offset += strlen(imgp->args->fname) + 1;	/* add fname */
113610ecfe0SMaxim Sobolev 	length = (imgp->args->argc == 0) ? 0 :
114610ecfe0SMaxim Sobolev 	    strlen(imgp->args->begin_argv) + 1;		/* bytes to delete */
115610ecfe0SMaxim Sobolev 
116610ecfe0SMaxim Sobolev 	if (offset - length > imgp->args->stringspace)
117610ecfe0SMaxim Sobolev 		return (E2BIG);
118610ecfe0SMaxim Sobolev 
119610ecfe0SMaxim Sobolev 	bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset,
120610ecfe0SMaxim Sobolev 	    imgp->args->endp - (imgp->args->begin_argv + length));
121610ecfe0SMaxim Sobolev 
122610ecfe0SMaxim Sobolev 	offset -= length;		/* calculate actual adjustment */
123610ecfe0SMaxim Sobolev 	imgp->args->begin_envv += offset;
124610ecfe0SMaxim Sobolev 	imgp->args->endp += offset;
125610ecfe0SMaxim Sobolev 	imgp->args->stringspace -= offset;
126610ecfe0SMaxim Sobolev 
127610ecfe0SMaxim Sobolev 	/*
128610ecfe0SMaxim Sobolev 	 * If there were no arguments then we've added one, otherwise
129610ecfe0SMaxim Sobolev 	 * decr argc remove old argv[0], incr argc for fname add, net 0
130610ecfe0SMaxim Sobolev 	 */
131610ecfe0SMaxim Sobolev 	if (imgp->args->argc == 0)
132610ecfe0SMaxim Sobolev 		imgp->args->argc = 1;
133610ecfe0SMaxim Sobolev 
134610ecfe0SMaxim Sobolev 	/*
135610ecfe0SMaxim Sobolev 	 * Loop through the interpreter name yet again, copying as
136610ecfe0SMaxim Sobolev 	 * we go.
137610ecfe0SMaxim Sobolev 	 */
138610ecfe0SMaxim Sobolev 	ihp = &image_header[2];
139610ecfe0SMaxim Sobolev 	offset = 0;
140610ecfe0SMaxim Sobolev 	while (ihp < &image_header[MAXSHELLCMDLEN]) {
141610ecfe0SMaxim Sobolev 		/* Skip whitespace */
142610ecfe0SMaxim Sobolev 		while ((*ihp == ' ' || *ihp == '\t')) {
143610ecfe0SMaxim Sobolev 			ihp++;
144610ecfe0SMaxim Sobolev 			continue;
145cfefd687SGarrett Wollman 		}
146cfefd687SGarrett Wollman 
147610ecfe0SMaxim Sobolev 		/* End of line? */
148610ecfe0SMaxim Sobolev 		if ((*ihp == '\n') || (*ihp == '#'))
149610ecfe0SMaxim Sobolev 			break;
150cfefd687SGarrett Wollman 
151610ecfe0SMaxim Sobolev 		/* Found a token, copy it */
152610ecfe0SMaxim Sobolev 		while ((*ihp != ' ') && (*ihp != '\t') &&
153610ecfe0SMaxim Sobolev 		    (*ihp != '\n') && (*ihp != '#')) {
154610ecfe0SMaxim Sobolev 			imgp->args->begin_argv[offset++] = *ihp++;
155cfefd687SGarrett Wollman 		}
156610ecfe0SMaxim Sobolev 		imgp->args->begin_argv[offset++] = '\0';
157610ecfe0SMaxim Sobolev 		imgp->args->argc++;
158cfefd687SGarrett Wollman 	}
159cfefd687SGarrett Wollman 
160610ecfe0SMaxim Sobolev 	/*
161610ecfe0SMaxim Sobolev 	 * Finally, add the filename onto the end for the interpreter to
162610ecfe0SMaxim Sobolev 	 * use and copy the interpreter's name to imgp->interpreter_name
163610ecfe0SMaxim Sobolev 	 * for exec to use.
164610ecfe0SMaxim Sobolev 	 */
165610ecfe0SMaxim Sobolev 	error = copystr(imgp->args->fname, imgp->args->buf + offset,
166610ecfe0SMaxim Sobolev 	    imgp->args->stringspace, &length);
167cfefd687SGarrett Wollman 
168610ecfe0SMaxim Sobolev 	if (error == 0)
169610ecfe0SMaxim Sobolev 		error = copystr(imgp->args->begin_argv, imgp->interpreter_name,
170610ecfe0SMaxim Sobolev 		    MAXSHELLCMDLEN, &length);
171610ecfe0SMaxim Sobolev 
172610ecfe0SMaxim Sobolev 	return (error);
173cfefd687SGarrett Wollman }
17492d91f76SGarrett Wollman 
17592d91f76SGarrett Wollman /*
17692d91f76SGarrett Wollman  * Tell kern_execve.c about it, with a little help from the linker.
17792d91f76SGarrett Wollman  */
178820ca326SMatthew Dillon static struct execsw shell_execsw = { exec_shell_imgact, "#!" };
179aa855a59SPeter Wemm EXEC_SET(shell, shell_execsw);
180