binst - Easy installation of user programs
Christian Schlichtherle
chris at attron.ruhr.sub.org
Sun Jan 27 02:25:11 AEST 1991
Please excuse my bad English...
Hmm, it seems to me that this program is a little bit like BSD's
"install", although I've never seen this...
"binst" is a small program used to make user written programs
public available without having super user permissions in
order to install it. To avoid system security gaps "binst"
performs a number of (configurable) checks when installing
the program.
To install a program you normally need write permission to the
directory where the program should go, but giving write
permission to the user means a lack of system security because
the user could remove any file in the directory and for example
substitute it with a trojanic horse.
With "binst" the user does not need write permission to the
directory. Instead "binst" is a setugid-root program which
performs a number of (configurable) checks in order to maintain
system security.
#!/bin/sh
# This is a shell archive (shar 3.24)
# made 01/26/1991 15:22 UTC by chris at attron.ruhr.sub.org
# Source directory /u/chris/src/binst
#
# existing files WILL be overwritten
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 783 -r--r--r-- Makefile
# 1774 -r--r--r-- README
# 9467 -r--r--r-- binst.c
# 2146 -r--r--r-- config.h
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
then TOUCH=touch
else TOUCH=true
fi
# ============= Makefile ==============
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# @(#) Makefile 1.1 91/01/26
X#
X# Copyright (C) 1991 by Christian Schlichtherle
X# (chris at attron.ruhr.sub.org)
X#
X# Permission is hereby granted to use, copy, modify or distribute
X# this file at will unless this copyright notice is removed.
X# The author disclaims any kind of warranty.
X#
X# Makefile - Makefile for binst(C).
X#
X
X#
X# Compiler and linker flags.
X#
XCC = cc
XCFLAGS = -Ms2 -i
XLDFLAGS = -s
XLIBS =
X
X#
X# Owner, group and mode of the installed program.
X#
XOWNER = root
XGROUP = root
XMODE = 6711
X# Destination directory
XBIN = /u/bin
X
Xbinst: binst.c
X $(CC) $(CFLAGS) $(LDFLAGS) $? -o $@ $(LIBS)
X
Xinstall: $(BIN)/binst
X
X$(BIN)/binst: binst
X cp $? $@
X chown $(OWNER) $@
X chgrp $(GROUP) $@
X chmod $(MODE) $@
X
Xuninstall:
X rm -f $(BIN)/binst
X
Xclean:
X rm -f a.out core *.o binst
SHAR_EOF
$TOUCH -am 0126162191 Makefile &&
chmod 0444 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "783"; then
echo original size 783, current size $Wc_c
fi
# ============= README ==============
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
X
X @(#) README 1.1 91/01/26
X
X Copyright (C) 1991 by Christian Schlichtherle
X (chris at attron.ruhr.sub.org)
X
X Permission is hereby granted to use, copy, modify or distribute
X this file at will unless this copyright notice is removed.
X The author disclaims any kind of warranty.
X
X README - Documentation file for binst(C).
X
X
XSYNTAX
X
X binst <program> ...
X
X
XDESCRIPTION
X
X "binst" is a small program used to make user written programs
X public available without having super user permissions in
X order to install it. To avoid system security gaps "binst"
X performs a number of (configurable) checks when installing
X the program.
X To install a program you normally need write permission to the
X directory where the program should go, but giving write
X permission to the user means a lack of system security because
X the user could remove any file in the directory and for example
X substitute it with a trojanic horse.
X With "binst" the user does not need write permission to the
X directory. Instead "binst" is a setugid-root program which
X performs a number of (configurable) checks in order to maintain
X system security.
X
X All installed programs have at least 0755 permission (read
X permission is needed for shell scripts).
X All programs are installed in the directory PUBBIN (configurable
X parameter in "config.h").
X For a detailed description of the permission checkings performed
X by "binst" see the file "config.h". The behaviour of "binst"
X deeply depends on this file.
X
X
XNOTES
X
X To install "binst" you should edit "config.h" in order to adapt
X it to your system's needs and edit "Makefile" to satisfact your
X compiler. Installation is quite simple.
X
X
XRETURN VALUE
X
X "binst" always returns the status of the last installation,
X which is 0 for success and 1 otherwise.
SHAR_EOF
$TOUCH -am 0126162191 README &&
chmod 0444 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "1774"; then
echo original size 1774, current size $Wc_c
fi
# ============= binst.c ==============
echo "x - extracting binst.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > binst.c &&
X/*
X * @(#) binst.c 1.1 91/01/26
X *
X * Copyright (C) 1991 by Christian Schlichtherle
X * (chris at attron.ruhr.sub.org)
X *
X * Permission is hereby granted to use, copy, modify or distribute
X * this file at will unless this copyright notice is removed.
X * The author disclaims any kind of warranty.
X *
X * binst.c - C module for binst(C).
X */
X
X#if !defined(lint) && !defined(library)
Xstatic char sccsid[] = "@(#) binst.c 1.1 91/01/26 ";
X#endif /* not lint and not library */
X
X#include <string.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <errno.h>
X#include "config.h"
X
X#define MAXPATHLEN 80
X#define ERRBUFSIZ 255
X
Xextern char *sys_errlist[];
Xextern int sys_nerr;
X
Xextern int setjmp();
Xextern void longjmp();
Xextern void exit();
X
Xchar *prg_nam = NULL;
Xchar pubbin[] = PUBBIN;
Xjmp_buf env;
Xchar errbuf[ERRBUFSIZ + 1];
X
X/*
X * Certain messages.
X */
Xchar *message[] = {
X "Usage: %s <filename> ...\n",
X "Not owner of %s"
X};
X
X/*
X * Index of message in upper message vector.
X */
X#define USAGE 0
X#define NOT_OWNER 1
X
X/*
X * sig_list - List of signals that have to be caught.
X */
Xint sig_list[] = {
X SIGHUP,
X SIGINT,
X SIGQUIT,
X SIGTERM,
X 0
X};
X
X/*
X * sig_action - List of actions for all signals.
X */
Xint sigcatch();
Xint (*sig_action[NSIG])() = {
X (int (*)()) 0, /* invalid */
X sigcatch, /* SIGHUP */
X sigcatch, /* SIGINT */
X sigcatch, /* SIGQUIT */
X sigcatch, /* SIGILL */
X sigcatch, /* SIGTRAP */
X sigcatch, /* SIGIOT */
X sigcatch, /* SIGEMT */
X sigcatch, /* SIGFPE */
X sigcatch, /* SIGKILL */
X sigcatch, /* SIGBUS */
X sigcatch, /* SIGSEGV */
X sigcatch, /* SIGSYS */
X sigcatch, /* SIGPIPE */
X sigcatch, /* SIGALRM */
X sigcatch, /* SIGTERM */
X sigcatch, /* SIGUSR1 */
X sigcatch /* SIGUSR2 */
X /* If there are more signals they are ignored! */
X};
X
X/*
X * print_error - Outputs error messages.
X * print_error uses "s" for perror(s) and "t" for error output.
X */
Xvoid print_error(s, t)
Xchar *s;
Xchar *t;
X{
X if ((s == NULL || !*s) && (t == NULL || !*t))
X return;
X
X if (prg_nam != NULL && *prg_nam)
X (void) fprintf(stderr, "%s: ", prg_nam);
X if (errno > 0 && errno <= sys_nerr && s != NULL && *s)
X (void) fprintf(stderr, "%s: %s\n", s, sys_errlist[errno]);
X if (t != NULL && *t)
X (void) fprintf(stderr, "%s\n", t);
X
X return;
X}
X
X/*
X * build_dstname - Builds a pathname.
X * 'build_dstname' builds a new pathname and copies it to the string
X * "dst".
X * The pathname is build from the directory name "dir" and the
X * filename from pathname "src" appended.
X */
Xvoid build_path(src, dir, dst)
Xchar *src;
Xchar *dir;
Xchar *dst;
X{
X char *ptr;
X
X if ((ptr = strrchr(src, '/')) != NULL)
X ptr++;
X else
X ptr = src;
X (void) sprintf(dst, "%s/%s", dir, ptr);
X
X return;
X}
X
Xint sigcatch(num)
Xint num;
X{
X (void) signal(num, SIG_IGN);
X
X longjmp(env, num);
X
X return (-1);
X}
X
X/*
X * set_act_sig - Sets only an active signal.
X * This function sets only a signal which is "active" (i.e. not ignored).
X * It returns the old action associated with the signal.
X * Note: When you set an active signal inactive with this function, you
X * can not redefine it. Use signal(S) instead.
X */
X#if defined(INT_SIG)
Xint (*set_act_sig(sig_type, sig_func))()
Xint sig_type;
Xint (*sig_func)();
X#else /* VOID_SIG */
Xvoid (*set_act_sig(sig_type, sig_func))()
Xint sig_type;
Xvoid (*sig_func)();
X#endif /* VOID_SIG */
X{
X#if defined(INT_SIG)
X int (*old_func)();
X#else /* VOID_SIG */
X void (*old_func)();
X#endif /* VOID_SIG */
X
X /*
X * Use an algorithm to leave no gap where the program
X * can be terminated at the cost of two "signal" calls
X * when all was right.
X */
X if ((old_func = signal(sig_type, SIG_IGN)) != SIG_IGN)
X (void) signal(sig_type, sig_func);
X
X return (old_func);
X}
X
X/*
X * set_sig_grp - Sets a group of signals.
X * "sig_lst" is a zero terminated list of signals to be set.
X * The function to set the signals is pointed to by "set_fnc".
X * The new action (i.e. the new pointer to a function) for a
X * signal can be found in the vector "new_act" with the signal
X * (i.e. it's number) as it's offset.
X * If "old_act" is nonnull the old action of a signal is stored
X * here with the signal (i.e. it's number) as it's offset again.
X * If it is null the old action is stored in "new_act" instead.
X */
Xvoid set_sig_grp(sig_lst, set_fnc, new_act, old_act)
Xint sig_lst[]; /* Zero terminated list of functions */
Xint (*(*set_fnc)())(); /* Signal set function (see signal(S)) */
Xint (*new_act[NSIG])(); /* Vector of new signal actions */
Xint (*old_act[NSIG])(); /* Vector of old signal actions */
X{
X while (*sig_lst != 0) {
X if (old_act != (int (**)()) 0)
X old_act[*sig_lst] = (*set_fnc)(*sig_lst,
X new_act[*sig_lst]);
X else
X new_act[*sig_lst] = (*set_fnc)(*sig_lst,
X new_act[*sig_lst]);
X sig_lst++;
X }
X
X return;
X}
X
X/*
X * copy - copies a file from "src" to "dst".
X * If the file cannot be copied an error message is output and
X * -1 is returned.
X * No destination file is left except that this file already exists
X * and is not writable.
X * Owner, group and mode of the destination file are not reset.
X * Instead the mode is 0666 according to umask (see creat(S)).
X */
Xint copy(src, dst)
Xchar *src;
Xchar *dst;
X{
X char buf[BUFSIZ];
X int src_fd;
X int dst_fd;
X int nread;
X
X if ((src_fd = open(src, O_RDONLY)) == -1)
X return (-1);
X
X if ((dst_fd = creat(dst, 0666)) == -1) {
X (void) close(src_fd);
X print_error(src, "");
X
X return (-1);
X }
X
X while ((nread = read(src_fd, buf, sizeof(buf) / sizeof(buf[0]))) > 0)
X if (write(dst_fd, buf, nread) != nread) {
X (void) close(src_fd);
X (void) close(dst_fd);
X (void) unlink(dst);
X print_error(dst, "");
X
X return (-1);
X }
X
X if (nread == -1) {
X (void) close(src_fd);
X (void) close(dst_fd);
X (void) unlink(dst);
X print_error(src, "");
X
X return (-1);
X }
X
X (void) close(src_fd);
X (void) close(dst_fd);
X
X return (0);
X}
X
X/*
X * chall - Changes mode, owner and group of the specified file.
X */
Xint chall(file, mode, owner, group)
Xchar *file;
Xint mode;
Xint owner;
Xint group;
X{
X if (chmod(file, mode) == -1)
X return (-1);
X if (chown(file, owner, group) == -1)
X return (-1);
X
X return (0);
X}
X
X/*
X * check_files - Checks files.
X */
Xint check_files(src, dst, dst_mode, dst_owner, dst_group)
Xchar *src;
Xchar *dst;
Xint *dst_mode;
Xint *dst_owner;
Xint *dst_group;
X{
X struct stat src_stat, dst_stat;
X
X /* Get info about source file */
X if (stat(src, &src_stat) == -1) {
X print_error(src, "");
X return -1;
X }
X
X#if defined(INSTALL_OTHER)
X if (access(src, 04) == -1)
X print_error(src, "");
X return -1;
X }
X#else /* not INSTALL_OTHER */
X if (src_stat.st_uid != getuid()) {
X (void) sprintf(errbuf, message[NOT_OWNER], src);
X print_error("", errbuf);
X return -1;
X }
X#endif /* not INSTALL_OTHER */
X
X#if defined(SRC_OWNER)
X *dst_owner = src_stat.st_uid;
X *dst_group = src_stat.st_gid;
X#else /* not SRC_OWNER */
X *dst_owner = getuid();
X *dst_group = getgid();
X#endif /* not SRC_OWNER */
X
X#if defined(SETUID)
X if (((*dst_mode = src_stat.st_mode) & 07000) == 0)
X *dst_mode |= 0755;
X#else /* not SETUID */
X *dst_mode = src_stat.st_mode & ~07000 | 0755;
X#endif /* not SETUID */
X
X#if !defined(OVERWRITE)
X if (stat(dst, &dst_stat) == 0) {
X if (*dst_owner != dst_stat.st_uid) {
X (void) sprintf(errbuf, message[NOT_OWNER], dst);
X print_error("", errbuf);
X return -1;
X }
X
X#if defined(INSTALL_OTHER) && defined(SRC_OWNER) && defined(OWNER_UPDATE)
X if (*dst_owner != getuid()) {
X (void) sprintf(errbuf, message[NOT_OWNER], dst);
X print_error("", errbuf);
X return -1;
X }
X#endif /* INSTALL_OTHER and SRC_OWNER and OWNER_UPDATE */
X }
X#endif /* not OVERWRITE */
X
X return 0;
X}
X
X/*
X * binst - Installs a file in the public binary directory.
X * Returns 0 if successfull, -1 otherwise.
X */
Xint binst(src_path)
Xchar *src_path;
X{
X char dst_path[MAXPATHLEN + 1];
X int dst_mode, dst_owner, dst_group;
X int sig_num;
X
X /* Build destination pathname */
X build_path(src_path, pubbin, dst_path);
X
X if (check_files(src_path, dst_path, &dst_mode, &dst_owner,
X &dst_group) == -1)
X return -1;
X
X /*
X * Set a long jump mark.
X * If we return from a jump triggered by a signal remove the
X * destination file (it is assumed to be an incomplete copy!),
X * print an error message, restore all signal actions and
X * execute the signal's previously stored action.
X * If it returns from this action (in fact it does not return!),
X * return with an error status.
X */
X if ((sig_num = setjmp(env)) != 0) {
X (void) unlink(dst_path);
X
X (void) sprintf(errbuf, "%s removed", dst_path);
X (void) print_error("", errbuf);
X
X set_sig_grp(sig_list, signal, sig_action, (int (**)()) 0);
X
X (*sig_action[sig_num])(sig_num);
X
X return -1;
X }
X
X /*
X * Catch all important signals which are not ignored.
X * If one is catched a long jump to the previously set mark is
X * performed.
X */
X set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
X
X /*
X * Copy the files and set the permissions according to
X * the source file.
X */
X if (copy(src_path, dst_path) == -1)
X return -1;
X (void) chall(dst_path, dst_mode, dst_owner, dst_group);
X
X /*
X * Restore all previously catched signals.
X */
X set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
X
X return 0;
X}
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int status;
X
X prg_nam = argv[0];
X
X if (argc == 1) {
X (void) fprintf(stderr, message[USAGE], argv[0]);
X exit (1);
X }
X
X while (--argc)
X status = binst(*++argv);
X
X exit(-status);
X /* For your 'lint' only... */
X return -1;
X}
SHAR_EOF
$TOUCH -am 0126162191 binst.c &&
chmod 0444 binst.c ||
echo "restore of binst.c failed"
set `wc -c binst.c`;Wc_c=$1
if test "$Wc_c" != "9467"; then
echo original size 9467, current size $Wc_c
fi
# ============= config.h ==============
echo "x - extracting config.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > config.h &&
X/*
X * @(#) config.h 1.1 91/01/26
X *
X * Copyright (C) 1991 by Christian Schlichtherle
X * (chris at attron.ruhr.sub.org)
X *
X * Permission is hereby granted to use, copy, modify or distribute
X * this file at will unless this copyright notice is removed.
X * The author disclaims any kind of warranty.
X *
X * config.h - C include file for binst(C).
X */
X
X#define INT_SIG /* You have int (*signal())() */
X#undef VOID_SIG /* You have void (*signal())() */
X
X/*
X * This is the name of the public binary directory.
X */
X#define PUBBIN "/u/bin"
X
X/*
X * Define wether you should be able to install programs you do not
X * own but you can read or if you are only allowed to install your
X * own programs.
X */
X/* #define INSTALL_OTHER /* Install all programs with read permission */
X
X/*
X * Define wether the destination file's owner and group should
X * be set to the source's owner and group or if it should be
X * set to the real user id and the real group id of the process.
X * To get in effect the INSTALL_OTHER flag must be set.
X */
X#define SRC_OWNER /* Set owner and group to the source's one */
X
X/*
X * Define wether you want to be able to overwrite other user's installed
X * programs or not.
X */
X/* #define OVERWRITE /* Overwrite other user's installed programs */
X
X/*
X * The following flag appears to updates only.
X * Define wether an update to an installed program is restricted to
X * the owner of that program or not.
X * To get in effect the INSTALL_OTHER and the SRC_OWNER flag must be set
X * and the OVERWRITE flag must be cleared.
X */
X#define OWNER_UPDATE /* Only owner is allowed to make an update */
X
X/*
X * Define wether the destination file should have the set user id and
X * set group id bit on if the source file has it or not.
X * This flag also effects the sticky bit. If it is not set the sticky
X * bit will always be cleared.
X * To get in effect this flag requires the binst(C) program to
X * have the set user id bit set for root.
X * Note that all installed programs are given 0755 permission at least
X * unless they have the SETUID, SETGIG or sticky bit set.
X */
X#define SETUID /* Set user and group id bit if source has */
SHAR_EOF
$TOUCH -am 0126162191 config.h &&
chmod 0444 config.h ||
echo "restore of config.h failed"
set `wc -c config.h`;Wc_c=$1
if test "$Wc_c" != "2146"; then
echo original size 2146, current size $Wc_c
fi
exit 0
--
Snail: Christian Schlichtherle, Elbscheweg 20, 5802 Wetter 4, Germany
Email: chris at attron.ruhr.sub.org Tel.: +49 2335 7550
Politiker an die (vorderste) Front!
More information about the Alt.sources
mailing list