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