chiark / gitweb /
Added a pile of syslog stuff, so that admins can see what this thing is
[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 -------------------------------------------------*/