Minor tidying and typo correction.
[shells] / chrootsh.c
1 /* -*-c-*-
2 *
3 * $Id: chrootsh.c,v 1.4 1999/04/22 00:30:27 mdw Exp $
4 *
5 * Chroot gaol shell
6 *
7 * (c) 1999 Mark Wooding
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Revision history --------------------------------------------------*
28 *
29 * $Log: chrootsh.c,v $
30 * Revision 1.4 1999/04/22 00:30:27 mdw
31 * Miscellanous tidying and security fixes. Lots of thanks due to Clive
32 * Jones.
33 *
34 * Revision 1.3 1999/04/21 22:52:43 mdw
35 * Added a pile of syslog stuff, so that admins can see what this thing is
36 * doing.
37 *
38 * Revision 1.2 1999/04/21 09:07:55 mdw
39 * Fiddle with copyright messages so that they're correct.
40 *
41 * Revision 1.1.1.1 1999/04/20 00:19:04 mdw
42 * Initial versions.
43 *
44 */
45
46 /*----- Header files ------------------------------------------------------*/
47
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include <sys/types.h>
54 #include <unistd.h>
55 #include <syslog.h>
56 #include <pwd.h>
57
58 extern char **environ;
59
60 /*----- Main code ---------------------------------------------------------*/
61
62 #ifndef CHROOTSH_PATH
63 # define CHROOTSH_PATH "/usr/bin/chrootsh"
64 #endif
65
66 static const char *quis = "chrootsh";
67
68 static void *xmalloc(size_t sz)
69 {
70 void *p = malloc(sz);
71 if (!p) {
72 setuid(getuid());
73 fprintf(stderr, "%s: not enough memory\n", quis);
74 exit(EXIT_FAILURE);
75 }
76 return (p);
77 }
78
79 static char *xstrdup(const char *p)
80 {
81 size_t sz = strlen(p) + 1;
82 char *q = xmalloc(sz);
83 memcpy(q, p, sz);
84 return (q);
85 }
86
87 int main(int argc, char *argv[])
88 {
89 struct passwd *pw;
90 uid_t me = getuid();
91 char *myname;
92 char **env;
93 char **av;
94
95 /* --- Resolve the program name --- */
96
97 {
98 char *p, *q;
99 p = argv[0];
100 for (q = argv[0]; *q; q++) {
101 if (*q == '/')
102 p = q + 1;
103 }
104 if (*p == '-')
105 p++;
106 quis = p;
107 openlog(quis, LOG_PID | LOG_NDELAY, LOG_DAEMON);
108 }
109
110 /* --- Check the user is meant to be chrooted --- */
111
112 {
113 uid_t eff = geteuid();
114
115 setreuid(eff, me);
116 pw = getpwuid(me);
117 if (!pw) {
118 syslog(LOG_ERR, "executed by non-existant user (uid = %i)", (int)me);
119 fprintf(stderr, "%s: you don't exist. Go away.\n", quis);
120 exit(EXIT_FAILURE);
121 }
122 if (strcmp(pw->pw_shell, CHROOTSH_PATH) != 0) {
123 syslog(LOG_ERR, "executed by non-chrooted user `%s'", pw->pw_name);
124 fprintf(stderr, "%s: you aren't a chrooted user\n", quis);
125 exit(EXIT_FAILURE);
126 }
127 endpwent();
128 setreuid(me, eff);
129 }
130
131 /* --- Chroot the user --- */
132
133 {
134 char *p = xstrdup(pw->pw_dir);
135 char *q = strstr(p, "/./");
136 if (q)
137 *q = 0;
138
139 if (chdir(p) || chroot(p)) {
140 int e = errno;
141 syslog(LOG_ERR, "error entering chroot gaol: %m");
142 setuid(me);
143 fprintf(stderr, "%s: couldn't call chroot: %s\n", quis, strerror(e));
144 exit(EXIT_FAILURE);
145 }
146 setuid(me);
147 free(p);
148 }
149
150 /* --- Read the new password block --- */
151
152 myname = xstrdup(pw->pw_name);
153 pw = getpwnam(myname);
154 if (!pw) {
155 syslog(LOG_ERR,
156 "configuration error: user `%s' not defined in gaol", myname);
157 fprintf(stderr, "%s: you don't exist in the gaol\n", quis);
158 exit(EXIT_FAILURE);
159 }
160 endpwent();
161
162 /* --- Now fiddle with environment strings and suchlike --- */
163
164 {
165 size_t n;
166 char **homevar = 0;
167 for (n = 0; environ[n]; n++)
168 ;
169 env = xmalloc((n + 1) * sizeof(char *));
170
171 for (n = 0; environ[n]; n++) {
172 if (strncmp(environ[n], "HOME=", 5) == 0) {
173 char *p = xmalloc(6 + strlen(pw->pw_dir));
174 sprintf(p, "HOME=%s", pw->pw_dir);
175 homevar = &env[n];
176 env[n] = p;
177 } else if (strncmp(environ[n], "SHELL=", 6) == 0) {
178 char *p = xmalloc(7 + strlen(pw->pw_shell));
179 sprintf(p, "SHELL=%s", pw->pw_shell);
180 env[n] = p;
181 } else
182 env[n] = environ[n];
183 }
184 env[n] = 0;
185
186 /* --- Change directory (again) --- */
187
188 if (chdir(pw->pw_dir)) {
189 if (homevar) {
190 free(*homevar);
191 *homevar = "HOME=/";
192 }
193 fprintf(stderr, "No directory, logging in with HOME=/\n");
194 }
195 }
196
197 /* --- Finally, sort the argument list --- */
198
199 {
200 char *p, *q;
201 int i;
202
203 av = xmalloc((argc + 1) * sizeof(char *));
204 p = pw->pw_shell;
205 for (q = p; *q; q++) {
206 if (*q == '/')
207 p = q + 1;
208 }
209 if (argv[0][0] == '-') {
210 q = xmalloc(2 + strlen(p));
211 *q = '-';
212 strcpy(q + 1, p);
213 av[0] = q;
214 } else
215 av[0] = p;
216
217 for (i = 1; i <= argc; i++)
218 av[i] = argv[i];
219 }
220
221 /* --- Run the real shell --- */
222
223 syslog(LOG_INFO, "chroot user `%s' logged in ok", myname);
224 closelog();
225 execve(pw->pw_shell, av, env);
226 fprintf(stderr, "%s: couldn't exec `%s': %s\n",
227 quis, pw->pw_shell, strerror(errno));
228 return (EXIT_FAILURE);
229 }
230
231 /*----- That's all, folks -------------------------------------------------*/