From: mdw Date: Tue, 20 Apr 1999 00:19:03 +0000 (+0000) Subject: Initial revision X-Git-Tag: 1.0.0~10 X-Git-Url: https://git.distorted.org.uk/~mdw/shells/commitdiff_plain/ed36b0a2916c0fe31f7d0779ea758c358db85fc2 Initial revision --- ed36b0a2916c0fe31f7d0779ea758c358db85fc2 diff --git a/.links b/.links new file mode 100644 index 0000000..10f134c --- /dev/null +++ b/.links @@ -0,0 +1,4 @@ +COPYING +install-sh +missing +mkinstalldirs diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..f416313 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,14 @@ +AUTOMAKE_OPTIONS = foreign + +bin_PROGRAMS = banned chrootsh ushell +man_MANS = banned.8 chrootsh.8 ushell.1 + +INCLUDES = \ + -DCHROOTSH_PATH=\"${bindir}/`echo chrootsh|sed '${transform}'`\" + +EXTRA_DIST = $(man_MANS) + +install-exec-hook: + chrootsh_prog="${bindir}/`echo chrootsh|sed '${transform}'`"; \ + chown root $${chrootsh_prog}; \ + chmod 4755 $${chrootsh_prog} diff --git a/banned.8 b/banned.8 new file mode 100644 index 0000000..b8381bc --- /dev/null +++ b/banned.8 @@ -0,0 +1,36 @@ +.TH banned 8 "20 April 1999" "Local tools" +.SH NAME +banned \- tells a user that he's banned +.SH SYNOPSIS +.B banned +.SH USAGE +Set a user's shell to the +.B banned +program's path, and put a file +.B .banned +in his or her home directory (owned by +.B root +by preference). When the user logs in, he or she will be told to go +away, given the explanation from the +.B .banned +file, and logged out again. An entry is also made in the system logs, +using the +.B LOG_AUTH +facility. +.PP +Don't put +.B banned +in the +.B /etc/shells +file! +.SH FILES +.TP 5 +.B .banned +An explanation given to a user to explain why he or she should go away. +.SH BUGS +None planned. +.SEE ALSO +.BR chrootsh (8), +.BR ushell (1). +.SH AUTHOR +Mark Wooding (mdw@nsict.org) diff --git a/banned.c b/banned.c new file mode 100644 index 0000000..2fa3565 --- /dev/null +++ b/banned.c @@ -0,0 +1,120 @@ +/* -*-c-*- + * + * $Id: banned.c,v 1.1 1999/04/20 00:19:04 mdw Exp $ + * + * Ban a user from logging in + * + * (c) 1999 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of banned. + * + * banned is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * banned is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with banned; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: banned.c,v $ + * Revision 1.1 1999/04/20 00:19:04 mdw + * Initial revision + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*----- Main code ---------------------------------------------------------*/ + +static const char *quis = "banned"; + +int main(int argc, char *argv[]) +{ + struct passwd *pw; + int fd; + char buf[BUFSIZ]; + int r; + + /* --- Resolve the program name --- */ + + { + char *p, *q; + p = argv[0]; + for (q = argv[0]; *q; q++) { + if (*q == '/') + p = q + 1; + } + quis = p; + } + + /* --- Read the user's name --- */ + + pw = getpwuid(getuid()); + if (!pw) { + fprintf(stderr, "%s: you don't exist. Go away.\n", quis); + exit(EXIT_FAILURE); + } + + /* --- Open the log file --- */ + + openlog(quis, 0, LOG_AUTH); + syslog(LOG_CRIT, "banned user `%s' attempted to log in", pw->pw_name); + + /* --- Change directory to the user's home --- */ + + if (chdir(pw->pw_dir) < 0) { + fprintf(stderr, "%s: couldn't change directory: %s\n", + quis, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* --- Open the reason file --- */ + + if ((fd = open(".banned", O_RDONLY)) < 0) { + fprintf(stderr, "%s: couldn't open `.banned' file: %s\n", + quis, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* --- Dump the reason information out --- */ + + for (;;) { + r = read(fd, buf, sizeof(buf)); + if (r == 0) + break; + else if (r < 0) { + fprintf(stderr, "%s: couldn't read: %s\n", quis, strerror(errno)); + exit(EXIT_FAILURE); + } + write(STDOUT_FILENO, buf, r); + } + + /* --- Done --- */ + + close(fd); + return (EXIT_FAILURE); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/chrootsh.8 b/chrootsh.8 new file mode 100644 index 0000000..ce232f6 --- /dev/null +++ b/chrootsh.8 @@ -0,0 +1,87 @@ +.TH chrootsh 8 "20 April 1999" "Local tools" +.SH NAME +chrootsh \- logs a user into a safe chrooted environment +.SH SYNOPSIS +.B chrootsh +.SH USAGE +Set a user's shell to the +.B chrootsh +program's path. +.PP +When run, +.B chrootsh +ensures that the current user has his or her shell set to be +.BR chrootsh . +If not, an error is raised and the program exits. +.PP +Assuming things check out OK, the user's home directory is examined. It +should be of the form +.IB gaoldir /./ homedir +where +.I gaoldir +is the path to the chroot gaol in which the user is to be imprisoned, +and +.I homedir +is the path from the root of the gaol to the user's actual home +directory. (This is for the benefit of users outside the gaol; +.B chrootsh +uses information from the gaol's +.B /etc/passwd +file to work this out. You'd do yourself a favour to make sure the two +are consistent.) +.PP +Once the new root directory is set, +.B chrootsh +drops all of its privileges, and re-reads the user's information +(presumably from a local version of the +.B /etc/passwd +file) to find the appropriate shell and home directory. It sets +appropriate values in the environment, and invokes the user's shell. +.SH EXAMPLE +Suppose +.B /home/gaol +is a carefully set-up environment for users to run in, with a minimal +set of tools installed. To set up a user +.B fred +within the gaol, make a directory +.B /home/gaol/home/fred +for the user, setting the access permissions as required. Then add a +line like +.PP +.RS 5 +.nf +.ft B +fred:*:1042:1042:Fred:/home/gaol/./home/fred:/usr/bin/chrootsh +.ft R +.fi +.RE +.PP +to the main password database (wherever that is). Then, put a line +.PP +.RS 5 +.nf +.ft B +fred:*:1042:1042:Fred:/home/fred:/bin/sh +.ft R +.fi +.RE +.PP +in the gaol's password file +.BR /home/gaol/etc/passwd . +Finally, set a sensible password for +.B fred +in the main password database, and everything ought to work. +.SH BUGS +The +.B chrootsh +program must be installed +.RB setuid- root . +While the author has made a fair effort to avoid security holes, he +might have missed something. There's no substitute for thorough +auditing. If you find a security problem, please report it to the +author as a serious bug. +.SH SEE ALSO +.BR banned (8), +.BR ushell (1). +.SH AUTHOR +Mark Wooding (mdw@nsict.org) diff --git a/chrootsh.c b/chrootsh.c new file mode 100644 index 0000000..2dfa52b --- /dev/null +++ b/chrootsh.c @@ -0,0 +1,197 @@ +/* -*-c-*- + * + * $Id: chrootsh.c,v 1.1 1999/04/20 00:19:04 mdw Exp $ + * + * Chroot gaol shell + * + * (c) 1999 EBI + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Chroot shell. + * + * chrootsh is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * chrootsh is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with chrootsh; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: chrootsh.c,v $ + * Revision 1.1 1999/04/20 00:19:04 mdw + * Initial revision + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#include +#include +#include + +extern char **environ; + +/*----- Main code ---------------------------------------------------------*/ + +#ifndef CHROOTSH_PATH +# define CHROOTSH_PATH "/usr/bin/chrootsh" +#endif + +static const char *quis = "chrootsh"; + +static void *xmalloc(size_t sz) +{ + void *p = malloc(sz); + if (!p) { + fprintf(stderr, "%s: not enough memory\n", quis); + exit(EXIT_FAILURE); + } + return (p); +} + +static char *xstrdup(const char *p) +{ + size_t sz = strlen(p) + 1; + char *q = xmalloc(sz); + memcpy(q, p, sz); + return (q); +} + +int main(int argc, char *argv[]) +{ + struct passwd *pw; + uid_t me = getuid(); + char **env; + char **av; + + /* --- Resolve the program name --- */ + + { + char *p, *q; + p = argv[0]; + for (q = argv[0]; *q; q++) { + if (*q == '/') + p = q + 1; + } + quis = p; + } + + /* --- Check the user is meant to be chrooted --- */ + + pw = getpwuid(me); + if (!pw) { + fprintf(stderr, "%s: you don't exist. Go away.\n", quis); + exit(EXIT_FAILURE); + } + if (strcmp(pw->pw_shell, CHROOTSH_PATH) != 0) { + fprintf(stderr, "%s: you aren't a chrooted user\n", quis); + exit(EXIT_FAILURE); + } + endpwent(); + + /* --- Chroot the user --- */ + + { + char *p = xstrdup(pw->pw_dir); + char *q = strstr(p, "/./"); + if (q) + *q = 0; + + if (chdir(p) || chroot(p)) { + fprintf(stderr, "%s: couldn't call chroot: %s", quis, strerror(errno)); + exit(EXIT_FAILURE); + } + setuid(me); + free(p); + } + + /* --- Read the new password block --- */ + + { + char *p = xstrdup(pw->pw_name); + pw = getpwnam(p); + free(p); + if (!pw) { + fprintf(stderr, "%s: you don't exist in the gaol\n", quis); + exit(EXIT_FAILURE); + } + endpwent(); + } + + /* --- Now fiddle with environment strings and suchlike --- */ + + { + size_t n; + for (n = 0; environ[n]; n++) + ; + env = xmalloc((n + 1) * sizeof(char *)); + + for (n = 0; environ[n]; n++) { + if (strncmp(environ[n], "HOME=", 5) == 0) { + char *p = xmalloc(6 + strlen(pw->pw_dir)); + sprintf(p, "HOME=%s", pw->pw_dir); + env[n] = p; + } else if (strncmp(environ[n], "SHELL=", 6) == 0) { + char *p = xmalloc(7 + strlen(pw->pw_shell)); + sprintf(p, "SHELL=%s", pw->pw_shell); + env[n] = p; + } else + env[n] = environ[n]; + } + env[n] = 0; + } + + /* --- Finally, sort the argument list --- */ + + { + char *p, *q; + int i; + + av = xmalloc((argc + 1) * sizeof(char *)); + p = pw->pw_shell; + for (q = p; *q; q++) { + if (*q == '/') + p = q + 1; + } + if (argv[0][0] == '-') { + q = xmalloc(2 + strlen(p)); + *q = '-'; + strcpy(q + 1, p); + av[0] = q; + } else + av[0] = p; + + for (i = 1; i <= argc; i++) + av[i] = argv[i]; + } + + /* --- Change directory (again) --- */ + + if (chdir(pw->pw_dir)) + fprintf(stderr, "No directory, logging in with HOME=/\n"); + + /* --- Run the real shell --- */ + + execve(pw->pw_shell, av, env); + fprintf(stderr, "%s: couldn't exec `%s': %s", + quis, pw->pw_shell, strerror(errno)); + return (EXIT_FAILURE); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..cab3dcd --- /dev/null +++ b/configure.in @@ -0,0 +1,5 @@ +AC_INIT(chrootsh.c) +AM_INIT_AUTOMAKE(shells, 1.0.0) +AC_PROG_CC +mdw_GCC_FLAGS +AC_OUTPUT(Makefile) diff --git a/ushell.1 b/ushell.1 new file mode 100644 index 0000000..53a8314 --- /dev/null +++ b/ushell.1 @@ -0,0 +1,37 @@ +.TH ushell 1 "20 April 1999" "Local tools" +.SH NAME +ushell \- display a user's shell +.SH SYNOPSIS +.B ushell +.I user +.SH USAGE +Writes the named user's default shell to standard output. This is +useful in scripts sometimes. In particular, it's handy in global +.B xdm/Xstartup +scripts for checking whether users have sensible shells: +.sp 1 +.RS 5 +.nf +.ft B +SHELL=`ushell $USER` +case $SHELL in + */banned) + xmessage -file $HOME/.banned + exit 1 + ;; + *) + if ! grep -q "^$SHELL" /etc/shells; then + xmessage "You're not allowed to log in this way." + exit 1 + fi + ;; +esac +.fi +.ft R +.SH BUGS +None planned. +.SH SEE ALSO +.BR banned (8), +.BR chrootsh (8). +.SH AUTHOR +Mark Wooding (mdw@nsict.org) diff --git a/ushell.c b/ushell.c new file mode 100644 index 0000000..14f017c --- /dev/null +++ b/ushell.c @@ -0,0 +1,87 @@ +/* -*-c-*- + * + * $Id: ushell.c,v 1.1 1999/04/20 00:19:04 mdw Exp $ + * + * Extract a user's shell + * + * (c) 1999 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of ushell. + * + * ushell is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ushell is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ushell; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: ushell.c,v $ + * Revision 1.1 1999/04/20 00:19:04 mdw + * Initial revision + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + +/*----- Main code ---------------------------------------------------------*/ + +static const char *quis; + +int main(int argc, char *argv[]) +{ + struct passwd *pw; + + /* --- Resolve the program name --- */ + + { + char *p, *q; + p = argv[0]; + for (q = argv[0]; *q; q++) { + if (*q == '/') + p = q + 1; + } + quis = p; + } + + /* --- Get the argument name --- */ + + if (argc != 2) { + fprintf(stderr, "Usage: %s username\n", quis); + exit(EXIT_FAILURE); + } + + /* --- Read the user information --- */ + + if ((pw = getpwnam(argv[1])) == 0) { + fprintf(stderr, "%s: user `%s' doesn't exist", quis, argv[1]); + exit(EXIT_FAILURE); + } + + /* --- Done --- */ + + puts(pw->pw_shell); + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/