Expunge revision histories.
[shells] / chrootsh.c
1 /* -*-c-*-
2 *
3 * $Id$
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 /*----- Header files ------------------------------------------------------*/
28
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <syslog.h>
37 #include <pwd.h>
38
39 extern char **environ;
40
41 /*----- Main code ---------------------------------------------------------*/
42
43 #ifndef CHROOTSH_PATH
44 # define CHROOTSH_PATH "/usr/bin/chrootsh"
45 #endif
46
47 static const char *quis = "chrootsh";
48
49 static void *xmalloc(size_t sz)
50 {
51 void *p = malloc(sz);
52 if (!p) {
53 setuid(getuid());
54 fprintf(stderr, "%s: not enough memory\n", quis);
55 exit(EXIT_FAILURE);
56 }
57 return (p);
58 }
59
60 static char *xstrdup(const char *p)
61 {
62 size_t sz = strlen(p) + 1;
63 char *q = xmalloc(sz);
64 memcpy(q, p, sz);
65 return (q);
66 }
67
68 int main(int argc, char *argv[])
69 {
70 struct passwd *pw;
71 uid_t me = getuid();
72 char *myname;
73 char **env;
74 char **av;
75
76 /* --- Resolve the program name --- */
77
78 {
79 char *p, *q;
80 p = argv[0];
81 for (q = argv[0]; *q; q++) {
82 if (*q == '/')
83 p = q + 1;
84 }
85 if (*p == '-')
86 p++;
87 quis = p;
88 openlog(quis, LOG_PID | LOG_NDELAY, LOG_DAEMON);
89 }
90
91 /* --- Check the user is meant to be chrooted --- */
92
93 {
94 uid_t eff = geteuid();
95
96 setreuid(eff, me);
97 pw = getpwuid(me);
98 if (!pw) {
99 syslog(LOG_ERR, "executed by non-existant user (uid = %i)", (int)me);
100 fprintf(stderr, "%s: you don't exist. Go away.\n", quis);
101 exit(EXIT_FAILURE);
102 }
103 if (strcmp(pw->pw_shell, CHROOTSH_PATH) != 0) {
104 syslog(LOG_ERR, "executed by non-chrooted user `%s'", pw->pw_name);
105 fprintf(stderr, "%s: you aren't a chrooted user\n", quis);
106 exit(EXIT_FAILURE);
107 }
108 endpwent();
109 setreuid(me, eff);
110 }
111
112 /* --- Chroot the user --- */
113
114 {
115 char *p = xstrdup(pw->pw_dir);
116 char *q = strstr(p, "/./");
117 if (q)
118 *q = 0;
119
120 if (chdir(p) || chroot(p)) {
121 int e = errno;
122 syslog(LOG_ERR, "error entering chroot gaol: %m");
123 setuid(me);
124 fprintf(stderr, "%s: couldn't call chroot: %s\n", quis, strerror(e));
125 exit(EXIT_FAILURE);
126 }
127 setuid(me);
128 free(p);
129 }
130
131 /* --- Read the new password block --- */
132
133 myname = xstrdup(pw->pw_name);
134 pw = getpwnam(myname);
135 if (!pw) {
136 syslog(LOG_ERR,
137 "configuration error: user `%s' not defined in gaol", myname);
138 fprintf(stderr, "%s: you don't exist in the gaol\n", quis);
139 exit(EXIT_FAILURE);
140 }
141 endpwent();
142
143 /* --- Now fiddle with environment strings and suchlike --- */
144
145 {
146 size_t n;
147 char **homevar = 0;
148 for (n = 0; environ[n]; n++)
149 ;
150 env = xmalloc((n + 1) * sizeof(char *));
151
152 for (n = 0; environ[n]; n++) {
153 if (strncmp(environ[n], "HOME=", 5) == 0) {
154 char *p = xmalloc(6 + strlen(pw->pw_dir));
155 sprintf(p, "HOME=%s", pw->pw_dir);
156 homevar = &env[n];
157 env[n] = p;
158 } else if (strncmp(environ[n], "SHELL=", 6) == 0) {
159 char *p = xmalloc(7 + strlen(pw->pw_shell));
160 sprintf(p, "SHELL=%s", pw->pw_shell);
161 env[n] = p;
162 } else
163 env[n] = environ[n];
164 }
165 env[n] = 0;
166
167 /* --- Change directory (again) --- */
168
169 if (chdir(pw->pw_dir)) {
170 if (homevar) {
171 free(*homevar);
172 *homevar = "HOME=/";
173 }
174 fprintf(stderr, "No directory, logging in with HOME=/\n");
175 }
176 }
177
178 /* --- Finally, sort the argument list --- */
179
180 {
181 char *p, *q;
182 int i;
183
184 av = xmalloc((argc + 1) * sizeof(char *));
185 p = pw->pw_shell;
186 for (q = p; *q; q++) {
187 if (*q == '/')
188 p = q + 1;
189 }
190 if (argv[0][0] == '-') {
191 q = xmalloc(2 + strlen(p));
192 *q = '-';
193 strcpy(q + 1, p);
194 av[0] = q;
195 } else
196 av[0] = p;
197
198 for (i = 1; i <= argc; i++)
199 av[i] = argv[i];
200 }
201
202 /* --- Run the real shell --- */
203
204 syslog(LOG_INFO, "chroot user `%s' logged in ok", myname);
205 closelog();
206 execve(pw->pw_shell, av, env);
207 fprintf(stderr, "%s: couldn't exec `%s': %s\n",
208 quis, pw->pw_shell, strerror(errno));
209 return (EXIT_FAILURE);
210 }
211
212 /*----- That's all, folks -------------------------------------------------*/