From ed36b0a2916c0fe31f7d0779ea758c358db85fc2 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Tue, 20 Apr 1999 00:19:03 +0000 Subject: [PATCH] Initial revision Organization: Straylight/Edgeware From: mdw --- .links | 4 ++ Makefile.am | 14 ++++ banned.8 | 36 ++++++++++ banned.c | 120 +++++++++++++++++++++++++++++++ chrootsh.8 | 87 +++++++++++++++++++++++ chrootsh.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ configure.in | 5 ++ ushell.1 | 37 ++++++++++ ushell.c | 87 +++++++++++++++++++++++ 9 files changed, 587 insertions(+) create mode 100644 .links create mode 100644 Makefile.am create mode 100644 banned.8 create mode 100644 banned.c create mode 100644 chrootsh.8 create mode 100644 chrootsh.c create mode 100644 configure.in create mode 100644 ushell.1 create mode 100644 ushell.c 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 -------------------------------------------------*/ -- [mdw]