1 /*
2  * the jailkit chroot() shell
3  * this program does a safe chroot() and then executes the shell
4  * that the user has within that new root (according to newroot/etc/passwd)
5  *
6  * I tried to merge some of the ideas from chrsh by Aaron D. Gifford,
7  * start-stop-daemon from Marek Michalkiewicz and suexec by the Apache
8  * group in this shell
9  *
10 
11 Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016 Olivier Sessink
12 All rights reserved.
13 
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions
16 are met:
17   * Redistributions of source code must retain the above copyright
18     notice, this list of conditions and the following disclaimer.
19   * Redistributions in binary form must reproduce the above
20     copyright notice, this list of conditions and the following
21     disclaimer in the documentation and/or other materials provided
22     with the distribution.
23   * The names of its contributors may not be used to endorse or
24     promote products derived from this software without specific
25     prior written permission.
26 
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 #include "config.h"
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <string.h>
48 #include <pwd.h>
49 #include <grp.h>
50 #include <sys/stat.h>
51 #include <sys/types.h>
52 #include <errno.h>
53 #include <syslog.h>
54 #include <limits.h>
55 #include <signal.h>
56 
57 #ifdef HAVE_SYS_CAPABILITY_H
58 #include <sys/capability.h>
59 #endif
60 
61 /* #define DEBUG */
62 
63 #ifdef DEBUG
64 #define DEBUG_MSG printf
65 #else
66 #define DEBUG_MSG(args...)
67  /**/
68 #endif
69 
70 #define PROGRAMNAME "jk_chrootsh"
71 #define CONFIGFILE INIPREFIX"/jk_chrootsh.ini"
72 
73 #include "jk_lib.h"
74 #include "utils.h"
75 #include "iniparser.h"
76 #include "passwdparser.h"
77 
78 /* doesn't compile on FreeBSD without this */
79 extern char **environ;
80 
81 /*
82 typedef struct {
83 	char *key;
84 	char *value;
85 } Tsavedenv;
86 
87 static Tsavedenv *savedenv_new(const char *key) {
88 	Tsavedenv *savedenv;
89 	char *val = getenv(key);
90 	if (!val) return NULL;
91 	savedenv = malloc(sizeof(Tsavedenv));
92 	savedenv->key = strdup(key);
93 	savedenv->value = strdup(val);
94 	return savedenv;
95 }
96 
97 static void savedenv_restore(Tsavedenv *savedenv) {
98 	if (savedenv) {
99 		setenv(savedenv->key, savedenv->value, 1);
100 		DEBUG_MSG("restored %s=%s\n",savedenv->key, savedenv->value);
101 	}
102 }
103 
104 static void savedenv_free(Tsavedenv *savedenv) {
105 	if (savedenv) {
106 		free(savedenv->key);
107 		free(savedenv->value);
108 		free(savedenv);
109 	}
110 }
111 */
112 
in_array(char ** haystack,char * needle,int needlelen)113 static int in_array(char **haystack, char * needle, int needlelen) {
114 	if (haystack && needle) {
115 		char **tmp = haystack;
116 		while (*tmp) {
117 			if (strlen(*tmp)==needlelen && strncmp(*tmp, needle, needlelen)==0) return 1;
118 			tmp++;
119 		}
120 	}
121 	return 0;
122 }
123 
unset_environ_except(char ** except)124 static void unset_environ_except(char **except) {
125 	char **tmp = environ;
126 	if (environ == NULL || *tmp==NULL || except==NULL || *except==NULL) {
127 		clearenv();
128 		return;
129 	}
130 	while (*tmp) {
131 		char* pos = strchr(*tmp, '=');
132 		if (pos == NULL) {
133 			/* invalid environment variable, are we being hacked? clear them all! */
134 			clearenv();
135 			return;
136 		}
137 		if (!in_array(except, *tmp, pos-*tmp)) {
138 			char *key = strndup(*tmp, pos-*tmp);
139 			unsetenv(key);
140 			free(key);
141 			tmp = environ;
142 			continue;
143 		}
144 		tmp++;
145 	}
146 }
147 
have_capabilities(void)148 static int have_capabilities(void) {
149 #ifdef HAVE_CAP_GET_PROC
150 	cap_t caps = cap_get_proc();
151 	if (caps) {
152 		cap_flag_value_t value_p;
153 		cap_get_flag(caps, CAP_SYS_CHROOT, CAP_EFFECTIVE,&value_p);
154 		cap_free(caps);
155 		return (value_p);
156 	}
157 #endif  /*HAVE_CAP_GET_PROC*/
158 	return 0;
159 }
160 
signal_handler(int signum)161 void signal_handler(int signum) {
162 	syslog(LOG_ERR, "abort, received signal %s (%d)", strsignal(signum),signum);
163 	exit(666);
164 }
165 
main(int argc,char ** argv)166 int main (int argc, char **argv) {
167 	unsigned int i;
168 	unsigned int use_capabilities=0;
169 	int ret;
170 	char **newargv;
171 	char *user=NULL, *tmp=NULL;
172 
173 	struct passwd *pw=NULL;
174 	struct group *gr=NULL;
175 	unsigned long ngroups_max=NGROUPS_MAX;
176 	unsigned long ngroups=0;
177 	gid_t *gids;
178 	struct passwd *intpw=NULL; /* for internal_getpwuid() */
179 	char *jaildir=NULL, *newhome=NULL, *shell=NULL;
180 	Tiniparser *parser=NULL;
181 	char **envs=NULL;
182 	unsigned int relax_home_group_permissions=0;
183 	unsigned int relax_home_other_permissions=0;
184 	unsigned int relax_home_group=0;
185 	unsigned int relax_home_owner=0;
186 	unsigned int injail_login_shell=0;
187 	char *injail_shell=NULL;
188 	unsigned int skip_injail_passwd_check=0;
189 
190 	DEBUG_MSG(PROGRAMNAME", started\n");
191 	/* open the log facility */
192 	openlog(PROGRAMNAME, LOG_PID, LOG_AUTH);
193 
194 	/* attach signal handler */
195 	signal(SIGILL,signal_handler);
196 	signal(SIGSEGV,signal_handler);
197 	signal(SIGTERM,signal_handler);
198 	signal(SIGFPE,signal_handler);
199 
200 	/* check if it PRORAMNAME that the user wants */
201 	tmp = strrchr(argv[0], '/');
202 	if (!tmp) {
203 		tmp = argv[0];
204 	} else {
205 		tmp++;
206 	}
207 
208 	if (strcmp(tmp, PROGRAMNAME) != 0 && strcmp(tmp, "su")!= 0 && strcmp(tmp, "-su")!= 0 && strcmp(tmp, "-"PROGRAMNAME)!=0) {
209 		DEBUG_MSG("wrong name, tmp=%s, &tmp[1]=%s\n", tmp, &tmp[1]);
210 		syslog(LOG_ERR, "abort, "PROGRAMNAME" is called as %s", argv[0]);
211 		exit(1);
212 	}
213 
214 	/* now test if we are setuid root (the effective user id must be 0, and the real user id > 0 */
215 	if (geteuid() != 0) {
216 		if (have_capabilities()) {
217 			use_capabilities=1;
218 		} else {
219 			syslog(LOG_ERR, "abort, effective user ID is not 0, possibly "PROGRAMNAME" is not setuid root");
220 			exit(11);
221 		}
222 	}
223 	if (getuid() == 0) {
224 		syslog(LOG_ERR, "abort, "PROGRAMNAME" is run by root, which does not make sense because user root can break out of a jail anyway");
225 		exit(12);
226 	}
227 
228 	DEBUG_MSG("get user info\n");
229 	/* get user info based on the users name and not on the uid. this enables support
230 	for systems with multiple users with the same user id */
231 	tmp = getenv("USER");
232 	if (tmp && strlen(tmp)) {
233 		user = strdup(tmp);
234 	}
235 	if (user) {
236 		pw = getpwnam(user);
237 	} else {
238 		pw = getpwuid(getuid());
239 	}
240 	if (!pw) {
241 		syslog(LOG_ERR, "abort, failed to get user information for user ID %u: %s, check /etc/passwd", getuid(), strerror(errno));
242 		exit(13);
243 	}
244 	if (!pw->pw_name || strlen(pw->pw_name)==0) {
245 		syslog(LOG_ERR, "abort, got an empty username for user ID %u: %s, check /etc/passwd", getuid(), strerror(errno));
246 		exit(13);
247 	}
248 	if (user && strcmp(user,pw->pw_name)!=0) {
249 		syslog(LOG_ERR, "abort, asked for user %s, got user info for %s", user, pw->pw_name);
250 		exit(13);
251 	}
252 	if (pw->pw_uid != getuid()) {
253 		syslog(LOG_ERR, "abort, started by user ID %u, got user info %s with user ID %d,", getuid(), pw->pw_name, pw->pw_uid);
254 		exit(13);
255 	}
256 	DEBUG_MSG("got user %s\nget group info\n",pw->pw_name);
257 	gr = getgrgid(getgid());
258 	if (!gr) {
259 		syslog(LOG_ERR, "abort, failed to get group information for group ID %u: %s, check /etc/group", getgid(), strerror(errno));
260 		exit(13);
261 	}
262 	DEBUG_MSG("get additional groups\n");
263 	/* ngroups_max = sysconf(_SC_NGROUPS_MAX);*/
264 	gids = malloc(ngroups_max * sizeof(gid_t));
265 	ngroups = getgroups(ngroups_max,gids);
266 	if (ngroups == -1) {
267 		syslog(LOG_ERR, "abort, failed to get additional group information: %s, check /etc/group", strerror(errno));
268 		exit(13);
269 	}
270 #ifdef DEBUG
271 	printf("got additional groups ");
272 	for (i=0;i<ngroups;i++) {
273 		printf("%u, ",gids[i]);
274 	}
275 	printf("\n");
276 #endif
277 
278 	/* make sure the jailkit config directory is owned root:root and not writable for others */
279 	if ( (testsafepath(INIPREFIX, 0, 0) &~TESTPATH_GROUPW) != 0 ) {
280 		syslog(LOG_ERR, "abort, jailkit configuration directory "INIPREFIX" is not safe; it should be owned 0:0 and not writable for others");
281 		exit(14);
282 	}
283 	parser = new_iniparser(CONFIGFILE);
284 	if (parser) {
285 		char *groupsec, *section=NULL, buffer[1024]; /* openbsd complains if this is <1024 */
286 		groupsec = strcat(strcpy(malloc0(strlen(gr->gr_name)+7), "group "), gr->gr_name);
287 		if (iniparser_has_section(parser, pw->pw_name)) {
288 			section = strdup(pw->pw_name);
289 		} else if (iniparser_has_section(parser, groupsec)) {
290 			section = groupsec;
291 		} else if (iniparser_has_section(parser, "DEFAULT")) {
292 			section = strdup("DEFAULT");
293 		}
294 		if (section != groupsec) free(groupsec);
295 		if (section) {
296 			unsigned int pos = iniparser_get_position(parser) - strlen(section) - 2;
297 
298 			if (iniparser_get_string_at_position(parser, section, "env", pos, buffer, 1024) > 0) {
299 				envs = explode_string(buffer, ',');
300 			}
301 			relax_home_group_permissions = iniparser_get_int_at_position(parser, section, "relax_home_group_permissions", pos, 0);
302 			relax_home_other_permissions = iniparser_get_int_at_position(parser, section, "relax_home_other_permissions", pos, 0);
303 			relax_home_group = iniparser_get_int_at_position(parser, section, "relax_home_group", pos, 0);
304 			relax_home_owner = iniparser_get_int_at_position(parser, section, "relax_home_owner", pos, 0);
305 			if (iniparser_get_string_at_position(parser, section, "injail_shell", pos, buffer, 1024) > 0) {
306 				injail_shell = strdup(buffer);
307 			}
308 			if (injail_shell) {
309 				skip_injail_passwd_check = iniparser_get_int_at_position(parser, section, "skip_injail_passwd_check", pos, 0);
310 			}
311 			injail_login_shell = iniparser_get_int_at_position(parser, section, "injail_login_shell", pos, 0);
312 			DEBUG_MSG("section %s: relax_home_group_permissions=%d, relax_home_other_permissions=%d, relax_home_group=%d, injail_shell=%s, skip_injail_passwd_check=%d\n",
313 					section, relax_home_group_permissions, relax_home_other_permissions,
314 					relax_home_group, injail_shell, skip_injail_passwd_check);
315 			free(section);
316 		} else {
317 			DEBUG_MSG("no relevant section found in configfile\n");
318 		}
319 		iniparser_close(parser);
320 	} else {
321 		DEBUG_MSG("no configfile "CONFIGFILE" ??\n");
322 	}
323 
324 	DEBUG_MSG("close filedescriptors\n");
325 	/* open file descriptors can be used to break out of a chroot, so we close all of them, except for stdin,stdout and stderr */
326 #ifdef OPEN_MAX
327     i = OPEN_MAX;
328 #elif defined(NOFILE)
329     i = NOFILE;
330 #else
331     i = getdtablesize();
332 #endif
333 	while (--i > 2) {
334 		/*printf("closing file descriptor %d\n",i);*/
335 		while (close(i) != 0 && errno == EINTR);
336 	}
337 	/* now make sure file descriptors 0 1 and 2 are valid before we (or a child) starts writing to it */
338 	while (1) {
339 		int fd;
340 		fd = open("/dev/null", O_RDWR);
341 		if (fd < 0)
342 			exit(10);
343 		if (fd > 2) {
344 			close(fd);
345 			break;
346 		} else {
347 			DEBUG_MSG("re-opening file descriptor %d\n",fd);
348 		}
349 	}
350 
351 	/* now we clear the environment, except for values allowed in /etc/jailkit/jk_chrootsh.ini */
352 	unset_environ_except(envs);
353 	if (envs) {
354 		free_array(envs);
355 	}
356 
357 	if (pw->pw_gid != getgid()) {
358 		syslog(LOG_ERR, "abort, the group ID from /etc/passwd (%u) does not match the group ID we run with (%u)", pw->pw_gid, getgid());
359 		exit(15);
360 	}
361 	if (!pw->pw_dir || strlen(pw->pw_dir) ==0) {
362 		syslog(LOG_ERR, "abort, got an empty home directory for user %s (%u)", pw->pw_name, getuid());
363 		exit(16);
364 	}
365 	if (strstr(pw->pw_dir, "/./") == NULL) {
366 		syslog(LOG_ERR, "abort, homedir '%s' for user %s (%u) does not contain the jail separator <jail>/./<home>", pw->pw_dir, pw->pw_name, getuid());
367 		exit(17);
368 	}
369 	DEBUG_MSG("get jaildir\n");
370 	if (!getjaildir(pw->pw_dir, &jaildir, &newhome)) {
371 		syslog(LOG_ERR, "abort, failed to read the jail and the home from %s for user %s (%u)",pw->pw_dir, pw->pw_name, getuid());
372 		exit(17);
373 	}
374 	DEBUG_MSG("dir=%s,jaildir=%s,newhome=%s\n",pw->pw_dir, jaildir, newhome);
375 	DEBUG_MSG("get chdir()\n");
376 	if (chdir(jaildir) != 0) {
377 		syslog(LOG_ERR, "abort, chdir(%s) failed: %s, check the permissions for %s",jaildir,strerror(errno),jaildir);
378 		exit(19);
379 	} else {
380 		char test[1024];
381 		/* test if it really succeeded */
382 		if (getcwd(test, 1024)==NULL || !dirs_equal(jaildir, test)) {
383 			syslog(LOG_ERR, "abort, the current dir is %s after chdir(%s), but it should be %s",test,jaildir,jaildir);
384 			exit(21);
385 		}
386 	}
387 
388 	/* here do test the ownership of the jail and the homedir and such
389 	the function testsafepath doe exit itself on any failure */
390 	if (!basicjailissafe(jaildir)) {
391 		syslog(LOG_ERR, "abort, %s is not a safe jail, check ownership and permissions.", jaildir);
392 		exit(53);
393 	}
394 	ret = testsafepath(pw->pw_dir, getuid(), getgid());
395 	if ((ret & TESTPATH_NOREGPATH) ) {
396 		syslog(LOG_ERR, "abort, path %s is not a directory", pw->pw_dir);
397 		exit(53);
398 	}
399 	if (!relax_home_owner && (ret & TESTPATH_OWNER) ) {
400 		syslog(LOG_ERR, "abort, path %s is not owned by %u", pw->pw_dir,getuid());
401 		exit(53);
402 	}
403 	if (!relax_home_group && (ret & TESTPATH_GROUP)) {
404 		syslog(LOG_ERR, "abort, path %s does not have group owner %u, set option 'relax_home_group' to relax this check", pw->pw_dir,getgid());
405 		exit(53);
406 	}
407 	if (!relax_home_group_permissions && (ret & TESTPATH_GROUPW)) {
408 		syslog(LOG_ERR, "abort, path %s is group writable, set option 'relax_home_group_permissions' to relax this check", pw->pw_dir);
409 		exit(53);
410 	}
411 	if (!relax_home_other_permissions && (ret & TESTPATH_OTHERW)) {
412 		syslog(LOG_ERR, "abort, path %s is writable for other, set option 'relax_home_other_permissions' to relax this check", pw->pw_dir);
413 		exit(53);
414 	}
415 	/* do a final log message */
416 	tmp = implode_array(&argv[1], argc-1, " ");
417 	syslog(LOG_INFO, "now entering jail %s for user %s (%u) with arguments %s", jaildir, pw->pw_name, getuid(), tmp);
418 	free(tmp);
419 
420 	DEBUG_MSG("chroot()\n");
421 	/* do the chroot() call */
422 	if (chroot(jaildir)) {
423 		syslog(LOG_ERR, "abort, chroot(%s) failed: %s, check the permissions for %s", jaildir, strerror(errno), jaildir);
424 		exit(33);
425 	}
426 
427 	if (use_capabilities) {
428 #ifdef HAVE_CAP_GET_PROC
429 		cap_t caps;
430 		cap_value_t capv[1];
431 		/* drop chroot capability, should we drop all other capabilities that may be used to escape from the jail too ?  */
432 		if ((caps = cap_get_proc()) == NULL) {
433 			syslog(LOG_ERR, "abort, failed to retrieve current capabilities: %s", strerror(errno));
434 			exit(101);
435 		}
436 		capv[0] = CAP_SYS_CHROOT;
437 		/* other capabilities that should/could be dropped:
438 		CAP_SETPCAP, CAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_PTRACE, CAP_SYS_ADMIN */
439 		if (cap_set_flag(caps, CAP_PERMITTED, 1, capv, CAP_CLEAR)) {
440 			syslog(LOG_ERR, "abort, failed to set PERMITTED capabilities: %s", strerror(errno));
441 			exit(102);
442 		}
443 		if (cap_set_flag(caps, CAP_EFFECTIVE, 1, capv, CAP_CLEAR)) {
444 			syslog(LOG_ERR, "abort, failed to set effective capabilities: %s", strerror(errno));
445 			exit(103);
446 		}
447 		if (cap_set_flag(caps, CAP_INHERITABLE, 1, capv, CAP_CLEAR)) {
448 			syslog(LOG_ERR, "abort, failed to set INHERITABLE capabilities: %s", strerror(errno));
449 			exit(104);
450 		}
451 		if (cap_set_proc(caps)) {
452 			syslog(LOG_ERR, "abort, failed to apply new capabilities: %s", strerror(errno));
453 			exit(105);
454 		}
455 #else
456 		/* we should never get here */
457 		exit(333);
458 #endif
459 	} else {
460 		/* drop all privileges, it seems that we first have to setgid(),
461 			then we have to call initgroups(),
462 			then we call setuid() */
463 		if (setgid(getgid())) {
464 			syslog(LOG_ERR, "abort, failed to set effective group ID %u: %s", getgid(), strerror(errno));
465 			exit(34);
466 		}
467 		if (setgroups(ngroups, gids)==-1) {
468 			syslog(LOG_ERR, "abort, failed to set additional groups: %s", strerror(errno));
469 			exit(35);
470 		}
471 		free(gids);
472 	/*	if (initgroups(pw->pw_name, getgid())) {
473 			syslog(LOG_ERR, "abort, failed to init groups for user %s (%d), check %s/etc/group", pw->pw_name,getuid(),jaildir);
474 			exit(35);
475 		}*/
476 		if (setuid(getuid())) {
477 			syslog(LOG_ERR, "abort, failed to set effective user ID %u: %s", getuid(), strerror(errno));
478 			exit(36);
479 		}
480 	}
481 	/* test for user and group info, is it the same? checks username, groupname and home */
482 	if (!skip_injail_passwd_check){
483 		char *oldpw_name,*oldgr_name;
484 		oldpw_name = strdup(pw->pw_name);
485 		oldgr_name = strdup(gr->gr_name);
486 
487 		if (user) {
488 			pw = getpwnam(user);
489 		} else {
490 			pw = getpwuid(getuid());
491 		}
492 		if (!pw) {
493 			syslog(LOG_ERR, "abort, failed to get user information in the jail for user ID %u: %s, check %s/etc/passwd",getuid(),strerror(errno),jaildir);
494 			exit(35);
495 		}
496 		if (pw->pw_uid != getuid()) {
497 			syslog(LOG_ERR, "abort, got user information in the jail for user ID %u instead of user ID %u, check %s/etc/passwd",pw->pw_uid,getuid(),jaildir);
498 			exit(35);
499 		}
500 		DEBUG_MSG("got %s as pw_dir\n",pw->pw_dir);
501 		gr = getgrgid(getgid());
502 		if (!gr) {
503 			syslog(LOG_ERR, "abort, failed to get group information in the jail for group ID %u: %s, check %s/etc/group",getgid(),strerror(errno),jaildir);
504 			exit(35);
505 		}
506 		if (strcmp(pw->pw_name, oldpw_name)!=0) {
507 			syslog(LOG_ERR, "abort, username %s differs from jail username %s for user ID %u, check /etc/passwd and %s/etc/passwd", oldpw_name, pw->pw_name, getuid(), jaildir);
508 			exit(37);
509 		}
510 		if (strcmp(gr->gr_name, oldgr_name)!=0) {
511 			syslog(LOG_ERR, "abort, groupname %s differs from jail groupname %s for group ID %u, check /etc/passwd and %s/etc/passwd", oldgr_name, gr->gr_name, getgid(), jaildir);
512 			exit(37);
513 		}
514 		if (strcmp(pw->pw_dir, newhome)!=0) {
515 			DEBUG_MSG("%s!=%s\n",pw->pw_dir, newhome);
516 			/* if these are different, it could be that getpwuid() gets the real user
517 			info (from for example ldap or nscd), and not the info inside the jail, lets
518 			test that, and if true, we should use the	shell from the internal function as well*/
519 			intpw = internal_getpwuid("/etc/passwd", getuid());
520 			if (!intpw) {
521 				DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome);
522 				syslog(LOG_ERR, "abort, failed to find user %u in %s/etc/passwd", getuid(), jaildir);
523 				exit(39);
524 			}
525 			if (!dirs_equal(intpw->pw_dir, newhome)) {
526 				DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome);
527 				syslog(LOG_ERR, "abort, home directory %s differs from jail home directory %s for user %s (%u), check /etc/passwd and %s/etc/passwd", newhome, pw->pw_dir, pw->pw_name, getuid(), jaildir);
528 				exit(39);
529 			}
530 		}
531 		free(oldpw_name);
532 		free(oldgr_name);
533 	}
534 	if (injail_shell) {
535 		shell = injail_shell;
536 	} else if (intpw) {
537 		shell = intpw->pw_shell;
538 	} else {
539 		shell = pw->pw_shell;
540 	}
541 	/* test the shell in the jail, it is not allowed to be setuid() root */
542 	testsafepath(shell,0,0);
543 
544 	/* prepare the new environment */
545 	setenv("HOME",newhome,1);
546 	setenv("USER",pw->pw_name,1);
547 	setenv("USERNAME",pw->pw_name,1);
548 	setenv("SHELL",shell,1);
549 	if (chdir(newhome) != 0) {
550 		syslog(LOG_ERR, "abort, chdir(%s) failed inside the jail %s: %s, check the permissions for %s/%s",newhome,jaildir,strerror(errno),jaildir,newhome);
551 		exit(41);
552 	}
553 
554 	/* cleanup before execution */
555 	free(newhome);
556 
557 	/* now execute the jailed shell */
558 	if (injail_login_shell) {
559 		argc = 2;
560 		newargv = malloc0((argc+1)*sizeof(char *));
561 		newargv[0] = shell;
562 		newargv[1] = "--login";
563 	} else {
564 		newargv = malloc0((argc+1)*sizeof(char *));
565 		newargv[0] = shell;
566 		for (i=1;i<argc;i++) {
567 			newargv[i] = argv[i];
568 		}
569 	}
570 	execv(shell, newargv);
571 	DEBUG_MSG(strerror(errno));
572 	syslog(LOG_ERR, "ERROR: failed to execute shell %s for user %s (%u), check the permissions and libraries of %s/%s",shell,pw->pw_name,getuid(),jaildir,shell);
573 
574 	free(jaildir);
575 	exit(111);
576 }
577