super-3.30.0/0000755000104100002640000000000010732537455011260 5ustar willspgsuper-3.30.0/install-sh0000555000104100002640000001141710732537455013266 0ustar willspg#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) if [ `whoami` = root ] ; then chowncmd="$chownprog $2" else echo "**** Can't chown $2 -- we aren't root ****" fi shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 super-3.30.0/barebones.tab0000444000104100002640000000135210732537455013707 0ustar willspg# # Read: man sections super.1, super.5 # doc files sample.tab, sample.cdmount, and sample.cdumount. # # This configuration file is for the super command. # It is most often used to run commands as root. # Therefore, DO NOT ADD ANY ENTRIES until you understand how this works. # # Set global defaults: log via syslog; patterns are shell glob-type patterns. # :global syslog=y patterns=shell # Limits on arguments: ## # 0 or 1 argument per command ## :global nargs=0-1 # Arguments must be simple words w/o characters that may special to shells. # ==> N.B. Put this *after* you change the "patterns=xxx" option # :if $PATTERNS == shell :global arg1-99="[[-/:+.,_a-zA-Z0-9]]" :if $PATTERNS != shell :global arg1-99="^[-/:+.,_a-zA-Z0-9]*$$" super-3.30.0/getpass.c0000444000104100002640000001105610732537455013073 0ustar willspg#include "super.h" #include "version.h" /* glibc says to use TCSASOFT if it's available. */ #ifndef TCSASOFT #define TCSASOFT 0 #endif #ifdef HAVE_TERMIOS_H static struct termios old, new; #ifdef HAVE_TCGETATTR #define Gtty(fd, arg) tcgetattr(fd, arg) #else #ifdef TIOCGETA #define Gtty(fd, arg) ioctl(fd, TIOCGETA, arg) #else #define Gtty(fd, arg) ioctl(fd, TCGETA, arg) #endif #endif #ifdef HAVE_TCSETATTR #define Stty(fd, arg) tcsetattr(fd, TCSAFLUSH|TCSASOFT, arg) #else #define Stty(fd, arg) ioctl(fd, TCSAFLUSH, arg) #endif /* From Gordon Lack: do not turn off ICANON (erase and kill processing): * on some OS's, chars will come through in bunches of 4; and * it is incompatible with getpass(), which does erase and kill * processing anyway. */ #define ECHO_OFF(tios) ((tios).c_lflag &= ~ECHO) #else #ifdef HAVE_TERMIO_H static struct termio old, new; #define Gtty(fd, arg) ioctl(fd, TCGETA, arg) #define Stty(fd, arg) ioctl(fd, TCSETAF, arg) #define ECHO_OFF(tio) ((tio).c_lflag &= ~ECHO) #else #ifdef HAVE_SGTTY_H static struct sgttyb old, new; #define ECHO_OFF(tty) ((tty).sg_flags &= ~(ECHO)) #define Gtty(fd, arg) gtty(fd, arg) #define Stty(fd, arg) stty(fd, arg) #else #error "You do not have any of termios.h, termio.h, sgtty.h!" #endif #endif #endif /* We want to catch signals, so that we can restore terminal * settings before responding to signals. */ static void (*oldHUP)(), (*oldINT)(), (*oldQUIT)(); static void (*oldALRM)(), (*oldTERM)(), (*oldPIPE)(); static int fdin=0, fdout=1; static void restoresig(); static void setsighdl(); static void sighdl(); /* * In order to stay compatible with (very) old Unixes, we stick * with the old signal() interface. So, it won't do the right thing * if multiple signals are received quickly, but that's just tough * luck for the (ab)user -- all we really want to do is restore * terminal settings when a signal is received, and if a user is * trying to be too clever by half with signals, all they will get * is an aborted super() call and a non-echoing terminal. */ static void sighdl(sig) int sig; { /* Restore everything, then resignal */ Stty(fdin, &old); restoresig(); kill(getpid(), sig); } static void setsighdl() { oldHUP = (void (*)()) signal(SIGHUP, sighdl); oldINT = (void (*)()) signal(SIGINT, sighdl); oldQUIT = (void (*)()) signal(SIGQUIT, sighdl); oldALRM = (void (*)()) signal(SIGALRM, sighdl); oldTERM = (void (*)()) signal(SIGTERM, sighdl); oldPIPE = (void (*)()) signal(SIGPIPE, sighdl); } static void restoresig() { (void) signal(SIGHUP, oldHUP); (void) signal(SIGINT, oldINT); (void) signal(SIGQUIT, oldQUIT); (void) signal(SIGALRM, oldALRM); (void) signal(SIGTERM, oldTERM); (void) signal(SIGPIPE, oldPIPE); } int readl(fd, buf, buflen) int fd; char *buf; int buflen; /* must be > 0 */ { int n; char *s, *end; for (s=buf, end=buf+buflen; s < end; s++) { n = read(fd, s, 1); if (n != 1 || *s == '\n' || *s == '\r') { *s = '\0'; return s-buf; } } return s-buf; } /* * Returns: -1 (and print message) if there was a problem adjusting * tty settings, else number of characters in password. */ int s_getpass(prompt, use_stdin, buf, n_buf) char *prompt; /* If !null, printed as prompt. * Uses /dev/tty unless use_stdin is set, or * if /dev/tty can't be opened, in which case * it uses stderr. */ int use_stdin; /* Directs input to come from stdin instead of * /dev/tty. */ char *buf; /* Where the password is placed */ int n_buf; /* size of buf. Up to n_buf characters are written * into *buf, and then nul-terminated. */ { int nread, gtty_status; if (use_stdin || (fdin = open("/dev/tty", O_RDWR)) == -1) { fdin = 0; fdout = 2; /* use stderr for prompting when input is stdin */ } else { fdout = fdin; } /* * Turn echoing off */ gtty_status = Gtty(fdin, &old); new = old; ECHO_OFF(new); setsighdl(); if (gtty_status == 0) { Stty(fdin, &new); } if (prompt) { write(fdout, prompt, strlen(prompt)); } /* * Read password */ nread = readl(fdin, buf, n_buf); if (nread >= 0) { buf[(nread < n_buf) ? nread : (n_buf-1)] = '\0'; } if (prompt) { write(fdout, "\n", 1); } /* * Restore terminal and signal handling. */ if (gtty_status == 0) { Stty(fdin, &old); } if (fdin != 0) { close(fdin); } restoresig(); return nread; } super-3.30.0/wildmat.c0000444000104100002640000001334310732537455013067 0ustar willspgstatic const char rcsid[] = "$Id: wildmat.c,v 1.6 2004/08/11 15:11:21 will Exp $"; /* ** ** Do shell-style pattern matching for ?, \, [], and * characters. ** Might not be robust in face of malformed patterns; e.g., "foo[a-" ** could cause a segmentation violation. It is 8bit clean. ** ** Modified 3 Mar 1993 by Will Deich, will@surya.caltech.edu: ** A leading ^ means to complement the match; that is, ** wildmat(string, "^"pat) returns TRUE if string does NOT ** match the pattern. ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. ** Rich $alz is now . ** April, 1991: Replaced mutually-recursive calls with in-line code ** for the star character. ** ** Special thanks to Lars Mathiesen for the ABORT code. ** This can greatly speed up failing wildcard patterns. For example: ** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* ** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 ** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 ** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without ** the ABORT code, it takes 22310 calls to fail. Ugh. The following ** explanation is from Lars: ** The precondition that must be fulfilled is that DoMatch will consume ** at least one character in text. This is true if *p is neither '*' nor ** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic ** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With ** FALSE, each star-loop has to run to the end of the text; with ABORT ** only the last one does. ** ** Once the control of one instance of DoMatch enters the star-loop, that ** instance will return either TRUE or ABORT, and any calling instance ** will therefore return immediately after (without calling recursively ** again). In effect, only one star-loop is ever active. It would be ** possible to modify the code to maintain this context explicitly, ** eliminating all recursive calls at the cost of some complication and ** loss of clarity (and the ABORT stuff seems to be unclear enough by ** itself). I think it would be unwise to try to get this into a ** released version unless you have a good test data base to try it out ** on. */ #ifdef TEST #include #endif #define TRUE 1 #define FALSE 0 #define ABORT -1 /* What character marks an inverted character class? */ #define NEGATE_CLASS '^' /* Is "*" a common pattern? */ #define OPTIMIZE_JUST_STAR /* Do tar(1) matching rules, which ignore a trailing slash? */ #undef MATCH_TAR_PATTERN /* ** Match text and p, return TRUE, FALSE, or ABORT. */ static int DoMatch(text, p) register char *text; register char *p; { register int last; register int matched; register int reverse; for ( ; *p; text++, p++) { if (*text == '\0' && *p != '*') return ABORT; switch (*p) { case '\\': /* Literal match with following character. */ p++; /* FALLTHROUGH */ default: if (*text != *p) { #ifdef VERBOSETEST printf("fail:text=%c != pat=%c\n", *text, *p); #endif return FALSE; } #ifdef VERBOSETEST printf("match:text=%c == pat=%c\n", *text, *p); #endif continue; case '?': /* Match anything. */ #ifdef VERBOSETEST printf("match:text=%c ; pat=%c\n", *text, *p); #endif continue; case '*': while (*++p == '*') /* Consecutive stars act just like one. */ continue; if (*p == '\0') { /* Trailing star matches everything. */ #ifdef VERBOSETEST printf("trailing * matches everything\n"); #endif return TRUE; } while (*text) { if ((matched = DoMatch(text++, p)) != FALSE) { return matched; } } #ifdef VERBOSETEST printf("ABORT!\n"); #endif return ABORT; case '[': reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; #ifdef VERBOSETEST printf("char class\n"); #endif if (reverse) { /* Inverted character class. */ p++; #ifdef VERBOSETEST printf("(negated)\n"); #endif } matched = FALSE; if (p[1] == ']' || p[1] == '-') if (*++p == *text) matched = TRUE; for (last = *p; *++p && *p != ']'; last = *p) { /* This next line requires a good C compiler. */ if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) { matched = TRUE; #ifdef VERBOSETEST printf("in char class, %c matched %c or maybe %c\n", *text, *p, *(p-1)); #endif } } if (matched == reverse) { #ifdef VERBOSETEST printf("failed match to class\n"); #endif return FALSE; } continue; } } #ifdef MATCH_TAR_PATTERN if (*text == '/') return TRUE; #endif /* MATCH_TAR_PATTERN */ return *text == '\0'; } /* ** User-level routine. Returns TRUE or FALSE. */ int wildmat(text, p) char *text; char *p; { #ifdef OPTIMIZE_JUST_STAR if (p[0] == '*' && p[1] == '\0') return TRUE; #endif /* OPTIMIZE_JUST_STAR */ return (p[0] == '^') ? DoMatch(text,p+1) != TRUE : DoMatch(text, p) == TRUE; } #ifdef TEST /* Yes, we use gets not fgets. Sue me. */ extern char *gets(); int main() { char p[80]; char text[80]; printf("Wildmat tester. Enter pattern, then strings to test.\n"); printf("A blank line gets prompts for a new pattern; a blank pattern\n"); printf("exits the program.\n"); for ( ; ; ) { printf("\nEnter pattern: "); (void)fflush(stdout); if (gets(p) == NULL || p[0] == '\0') break; for ( ; ; ) { printf("Enter text: "); (void)fflush(stdout); if (gets(text) == NULL) exit(0); if (text[0] == '\0') /* Blank line; go back and get a new pattern. */ break; printf(" %s\n", wildmat(text, p) ? "YES" : "NO"); } } exit(0); /* NOTREACHED */ } #endif /* defined(TEST) */ super-3.30.0/braces.c0000444000104100002640000002102410732537455012660 0ustar willspgstatic const char rcsid[] = "$Id: braces.c,v 1.33 2004/04/30 17:00:58 will Exp $"; /* * brace.c: csh brace expansion -- includes pieces of * [t]csh's sh.misc.c and sh.glob.c. * * Modified for use as a standalone brace-globbing subroutine. * - Will Deich, Mar 93. * Modified to optionally apply braces to input string, and glob * the resulting string. This lets us take "a,b,c" and act as if * it was "{a,b,c}". * - Will Deich, Jan 96. * Modified to supply blkprint() routine. * - Will Deich, May 98. */ #include #include "version.h" /*- * Copyright (c) 1980, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include typedef void * ptr_t; #ifndef NULL #define NULL 0 #endif #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif extern void *malloc(); extern void *realloc(); extern void free(); #if 0 #define xmalloc my_malloc #define xrealloc my_realloc #define xfree my_free #else #define xmalloc malloc #define xrealloc realloc #define xfree free #endif #define GLOBSPACE 100 /* Alloc increment */ #define LBRC '{' #define RBRC '}' #define LBRK '[' #define RBRK ']' #define EOS '\0' #define strsave(s) strsavew((s), 0) static char *strsavew(); void blkfree(); void Blkfree(); static int blklen(); void blkprint(); int globbraces(v, wrap, blp) char *v; int wrap; char ***blp; { char *s; char **nv, **vl, **el; int size = GLOBSPACE; int glob1brace(); nv = vl = (char **) xmalloc((size_t) sizeof(char *) * size); *vl++ = strsavew(v, wrap); *vl = NULL; el = vl; vl = nv; for (s = *vl; s; s = *++vl) { char *b; char **vp, **bp; if ((b = strchr(s, LBRC)) && b[1] != '\0' && b[1] != RBRC) { char **bl; int len; if ((len = glob1brace(s, &bl)) < 0) { blkfree(nv); return -len; } xfree((ptr_t) s); if (len == 1) { *vl-- = *bl; xfree((ptr_t) bl); continue; } len = blklen(bl); if (&el[len] >= &nv[size]) { int l, e; l = &el[len] - &nv[size]; size += GLOBSPACE > l ? GLOBSPACE : l; l = vl - nv; e = el - nv; nv = (char **) xrealloc((ptr_t) nv, (size_t) size * sizeof(char *)); vl = nv + l; el = nv + e; } vp = vl--; *vp = *bl; len--; for (bp = el; bp != vp; bp--) bp[len] = *bp; el += len; vp++; for (bp = bl + 1; *bp; *vp++ = *bp++) continue; xfree((ptr_t) bl); } } *blp = nv; return 0; } int glob1brace(s, bl) char *s, ***bl; { char *p; int i, len; char *pm, *pe, *lm, *pl; char **nv, **vl; char gbuf[MAXPATHLEN]; int size = GLOBSPACE; nv = vl = (char **) xmalloc((size_t) sizeof(char *) * size); *vl = NULL; len = 0; /* copy part up to the brace */ for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) continue; /* check for balanced braces */ for (i = 0, pe = ++p; *pe; pe++) { if (*pe == LBRK) { /* Ignore everything between [] */ for (++pe; *pe != RBRK && *pe != EOS; pe++) continue; if (*pe == EOS) { blkfree(nv); return (-RBRK); } } else if (*pe == LBRC) i++; else if (*pe == RBRC) { if (i == 0) break; i--; } } if (i != 0 || *pe == '\0') { blkfree(nv); return (-RBRC); } for (i = 0, pl = pm = p; pm <= pe; pm++) switch (*pm) { case LBRK: for (++pm; *pm != RBRK && *pm != EOS; pm++) continue; if (*pm == EOS) { *vl = NULL; blkfree(nv); return (-RBRK); } break; case LBRC: i++; break; case RBRC: if (i) { i--; break; } /* FALLTHROUGH */ case ',': if (i && *pm == ',') break; else { char savec = *pm; *pm = EOS; (void) strcpy(lm, pl); (void) strcat(gbuf, pe + 1); *pm = savec; *vl++ = strsave(gbuf); len++; pl = pm + 1; if (vl == &nv[size]) { size += GLOBSPACE; nv = (char **) xrealloc((ptr_t) nv, (size_t) size * sizeof(char *)); vl = &nv[size - GLOBSPACE]; } } break; default: break; } *vl = NULL; *bl = nv; return (len); } static char * strsavew(s, wrap) char *s; int wrap; /* If 0: save s. If !0: save '{' s '}' */ { char *n; register char *p; if (s == NULL) s = (char *) ""; for (p = (char *) s; *p++;); n = p = (char *) xmalloc((size_t) ((p - s) * sizeof(char)) + (wrap ? 2 : 0)); if (wrap) *p++ = '{'; while ( (*p++ = *s++) ) ; if (wrap) { *(p-1) = '}'; *p = '\0'; } return (n); } void blkfree(av0) char **av0; { register char **av = av0; if (!av0) return; for (; *av; av++) xfree((ptr_t) *av); xfree((ptr_t) av0); } char ** blkdup(blk) char **blk; { int len = blklen(blk); int i; char **duplicate; duplicate = (char **) xmalloc((size_t) sizeof(char *) * (len + 1)); /* Initialize duplicate[], so allocation failures are handled properly */ for (i=0; i<=len; i++) { duplicate[i] = NULL; } for (i=0; i \"%s\"\n", p, *p); } blkfree(av0); } char ** Blkdup(str, blk) char *str; char **blk; { #ifdef __STDC__ printf("Blkdup(%p): %s\n", (void *) blk, str); #else printf("Blkdup(%#lx): %s\n", blk, str); #endif return blkdup(blk); } void blkprint(av) char **av; { int i; fprintf(stderr, "blkprint(%#lx):\n", (unsigned long) av); if (!av) return; for (i = 0; *av; av++, i++) { fprintf(stderr, "%d: %#lx\t<", i, (unsigned long) av[i]); fprintf(stderr, "%s>\n", av[i]); } } #ifdef TEST #include main(argc, argv) int argc; char **argv; { int i, status; char **p; while (*(++argv)) { status = globbraces(*argv, 0, &p); if (status == 0 - '}') printf("} error\n"); else if (status == 0 - ']') printf("] error\n"); else if (status < 0) printf("globbraces returns %d\n", status); else { printf("%s expands to:\n", *argv); while (*p) printf("\t`%s'\t\n", *p++); } printf("\nRepeat, with wrap-string-in-braces enabled:\n"); status = globbraces(*argv, 1, &p); if (status == 0 - '}') printf("} error\n"); else if (status == 0 - ']') printf("] error\n"); else if (status < 0) printf("globbraces returns %d\n", status); else { printf("%s expands to:\n", *argv); while (*p) printf("\t`%s'\t\n", *p++); } } } #endif super-3.30.0/super.5.in0000444000104100002640000016146510732537455013124 0ustar willspg.TH SUPER 5 local .\" .\" Copyright (c) 1993 by California Institute of Technology. .\" Written by William Deich. Not derived from licensed software. .\" .\" You may distribute under the terms of either the GNU General Public .\" License or the Artistic License, as specified in the README file. .\" .\" .SH NAME super, super.tab \- database of restricted commands for super(1) .SH DESCRIPTION The .I super.tab file contains the restrictions on who can execute commands with .BR super (1). It may also contain options that modify the uid and/or gid under which a command is run; the list of environment variables that are discarded before executing a command, and so on. The reader is expected to be familiar with the .BR super (1) man page. .PP If you are trying to avoid reading this lengthy man page, you need to know a few simple rules. First, for a user to successfully execute a command by typing .IR super\ commandName , the minimum entry in the .I super.tab is something like .ti +.5i .B commandName\ \ FullPathToCommand\ \ userName .br For example, the entry .ti +.5i .B cdmount\ \ /usr/local/bin/cdmount\ \ wally,dolly .br says that users .I wally and .I dolly may execute the /usr/local/bin/cdmount program by typing .IR super\ cdmount . .PP Second, when you define options in the .I super.tab file, remember that all options are orthogonal to each other, and it doesn't matter in what order they appear on a control line. Third, \fIglobal\fP options (defined on a .B :global or .B :global_options line) take effect immediately after the defining line, are valid until the end of the input or until there is a countermanding global option or pattern, and are overridden by \fIlocal\fP (per-command) options, which are defined on a regular control line. .PP Although .I super has a great many options that you can set inside the .I super.tab file, none of them are required for security, so you don't have to be intimately familiar with this entire document in order to use .I super securely. The most important options that you will probably want to use are (a) a logging option like .IR logfile= xxx or .IR syslog=y ; and (b) .IR patterns=shell , so that the default regular-expression interpretation of wildcards is changed to the more convenient shell-style glob patterns. .PP Unless modified with options in the .I super.tab file, super executes commands using effective uid root; unchanged real uid and gid; no supplementary groups; no open file descriptors save 0, 1, and 2; no environment variables except a few with safe values (see .BR super.1 ); and signal handling reset to the default. .PP When .I super uses a command from a user-supplied super file (\fI.supertab\fP in the user's home directory) these rules are modified: the real and effective uid and gid are set to the owner of the .I .supertab file, and the supplementary groups are set to the user's login groups. .PP If the special supplementary file named .IR super.init exists, it is implictly include at the start of .I super.tab and every .I .supertab file. The file resides in the same directory as .I super.tab and must be owned by root, and should be world-readable. This provides a uniform configuration file applied to every super-executed command. Note that the configuration file should contain entries that are appropriate for use in both the .I super.tab file and any per-user .I supertab file. It is not a good idea to include commands in the .I super.init file. The variable .B IS_USERTAB is defined to be ``\fIyes\fP'' if .I super is processing a per-user .supertab file, and ``\fIno\fP'' otherwise. The following pair of entries could be used in a super.init file to allow different initialization for regular use and per-user use: .sp .RS .nf \fB:if $IS_USERTAB == yes \ \ \ :include /etc/super.init.per-user\fP \fB:if $IS_USERTAB != yes \ \ \ :include /etc/super.init.as-root\fP .fi .RE .sp (The use of variables and conditional expressions is explained below, in the sections .I Variables and .IR Conditionally-included\ Control\ Lines , respectively.) .PP The .I super.tab file is formatted as a series of control lines of the form .sp .ti +.5i .B CmdPat\ \ FullPath\ \\\\ .ti 2.5i .B Options\ PermittedUsers\ PermittedTimes .\" .RE .br or .br .ti +.5i .B CmdPat1::FullPath1\ CmdPat2::FullPath2\ ...\ \\\\ .ti 2.5i .B Options\ PermittedUsers\ PermittedTimes .br or .br .ti +.5i .B \fI:\fPBuiltinCmd arguments .sp The .IR Options , .IR PermittedUsers , and .IR PermittedTimes may be mixed together in any order. At least one .I PermittedUsers field is required, but neither .I Options nor .I PermittedTimes are required. For each control line, .I Super matches the following: .RS .HP \(bu the user-entered command to a .IR CmdPat ; .HP \(bu the {user,group,host} triplet to a .I PermittedUsers entry; and .HP \(bu the current time to a .I PermittedTimes entry (the default permits any time). .RE .PP If these conditions are not satisfied, .I super ``falls through'' and tries the next control line. .PP For example, the entry .sp .RS .nf .B renice\ /etc/renice\ jack@hill jill@bucket time~8-17 .fi .RE .sp specifies that between hours 8:00 and 17:00, user Jack can renice any process on host hill, and user Jill can do so on host bucket, by simply typing .B "super renice ." .PP Control lines begin in column 1, and the fields are whitespace-separated. Note that you can either use a single .I CmdPat and .IR FullPath , separated by whitespace, or you can use a series of them in one control line by putting .RB ` :: ' between each .I CmdPat and .I FullPath pair. Whitespace may be included in a field by enclosing text in single- or double-quotes. The quoting is shell-like, in the sense that quotemarks don't have to surround the entire field, and you can switch between quotemark types in a single entry. For instance, \fBX"a\ b"Y'd\ e'\fR is equivalent to \fB"Xa\ bYd\ e"\fR. Comments begin with a `#' and continue to the end of a line. .PP There can also be blank or comment lines without any control data. .PP A control line may be continued by preceding the newline with a backslash, and indenting the continuation line with whitespace. When the multiple-line entry is read, the text just before the backslash-newline is not modified (any whitespace before the backslash will be kept), and the backslash-newline-whitespace sequence is either eliminated entirely or treated as whitespace. The rule is simple: following a letter, digit, or underscore, it is treated as whitespace. Otherwise, it is eliminated. This means that .ne 5 .sp .nf .RS \fBCmd\ \ File\ \ user1\\\fP \fB\ \ \ \ \ \ \ \ \ \ \ user2\\\fP \fB\ \ \ \ \ \ \ \ \ \ \ user3\fP .RE .fi .sp .ne 5 is equivalent to .sp .RS .B Cmd\ \ File\ \ user1 user2 user3 .RE .sp .ne 5 On the other hand, .sp .nf .RS \fBCmd\ \ File\ \ {user1,\\\fP \fB\ \ \ \ \ \ \ \ \ \ \ user2,\\\fP \fB\ \ \ \ \ \ \ \ \ \ \ user3}\fP .RE .fi .sp .ne 5 is equivalent to .sp .RS .B Cmd\ \ File\ \ {user1,user2,user3} .RE .sp That is, the sensible interpretation is done in both cases. .PP The indentation requirement for continuation lines helps .B super catch typos. Comments may be placed before each backslash-newline pair, not just at the end of a continued control line. .PP .SH The CmdPat Field .PP In response to the user typing .sp .RS .B super .IR cmd " [" " args " ], .RE .sp the .I cmd is searched for in the .I super.tab file. The .I cmd is matched against each pattern .IR CmdPat . .PP .B "Basic Use: Simple Command Patterns without Wildcards." .PP Typically, a .I CmdPat just uses plain characters without any special pattern-matching characters, so a .I cmd must be the same as the .I CmdPat string. For example: .sp .RS .B skill /usr/local/bin/skill user1 user2 user3 .RE .sp Here, any user in the list {user1, user2, user3} may type .B super skill to execute /usr/local/bin/skill. .PP .B "Advanced Use: Command Patterns with Wildcards." .PP More generally, a .IR CmdPat can be either an \fIed\fR-style pattern (``regex'' \(em the BSD\ 4.x syntax used in the re_comp()/re_exec() routines), POSIX regular expressions, or a Bourne-shell-style pattern. You can set the pattern style using the global option \fBpatterns\fR (see below). The default is ``regex'' for historical reasons; however, shell-style patterns are easier to use without errors, and most sites should use shell-style patterns. In all cases the patterns are extended to support csh-style brace expansion. For instance, .B a{x,y,z}b stands for the set of patterns .BR "axb ayb azb" . Don't put any whitespace inside the braces! .PP For convenience, there is always an implied set of braces around an entire pattern. This means that any comma-separated list .B "a,b,c" is interpreted as .BR "{a,b,c}" , and is very helpful so that you don't have to worry about getting braces just right when you build complex lists of out of (say) variables containing other lists of users. .PP All pattern matching is ``anchored'': patterns are forced to match the entire .I cmd string. .PP If the .I CmdPat is matched and the other conditions are met (such as the user being in the PermittedUser list to execute this command), .I FullPath gives the name of the actual command that will be executed with .IR execve() . If .I FullPath contains an asterisk, the asterisk is first replaced by the user's .IR cmd . .PP If you put special pattern-matching characters into the .IR CmdPat , but don't put an asterisk into .IR FullPath , you have simply given more ways a user can execute the same .I FullPath. This isn't useful, and in fact isn't a good idea at all. The power of using patterns in the .I CmdPat comes when .I FullPath includes an asterisk. For instance, a SysV-based host might have .ne 5 an entry in the .I super.tab file that looks like: .sp .RS \fB/usr/bin/{lp,lpstat,disable,enable,cancel} * \\\fP .br .B \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :operators uid=0 .RE .sp This would allow anybody in the "operators" group to have root access to the line printer commands (the \fIuid=0\fP tells .B super to set the real uid to 0, not just the effective uid). .ne 3 For instance, if the user typed: .sp .RS .BI "super /usr/bin/disable " some_printer .RE .sp then the .I FullPath (``\fB*\fR'') would be replaced by .BR /usr/bin/disable , which would be the command to exec. .sp More conveniently, the .I super.tab .ne 5 file could have a line like: .sp .RS \fB{lp,lpstat,disable,enable,cancel} /usr/bin/* \\\fP .br .B \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :operators uid=0 .RE .sp In this case, the user can type .sp .RS .BI "super disable " some_printer .RE .sp The asterisk-replacement ability also lets a user execute any of an entire directory of commands, using a .I super.tab entry like the following: .sp .RS \fBop/* /usr/local/super/scripts/* :operators uid=0 .RE .sp In this case, the user can type .sp .RS .BI "super op/" xyz .RE .sp and .I super will execute .I /usr/local/super/scripts/op/xyz. .PP The asterisk-replacement capability is useful but potentially dangerous, because it may unintentionally open the door to programs you hadn't intended to give away. It is a sensible precaution to restrict asterisk-replacement to entries where the valid-user list includes trusted users only. .PP If you .I completely trust some users, but want logging of all actions executed as root, .ne 5 you could use: .sp .RS .B /* \ \ * \ \ \fIReallyReallyTrustedUsers\fP .RE or .RS .B /.* \ \ * \ \ \fIReallyReallyTrustedUsers\fP .RE .sp (depending on whether \fBpatterns=shell\fP, \fBpatterns=regex\fP, or \fBpatterns=posix\fP). The trusted users can now execute any command. Note that the pattern begins with a slash, to ensure that the .I cmd must be an absolute path \(em this helps avoid accidental execs of the wrong program. .PP If you were really going to give everything away as shown above, you'd probably want to exclude any public-area workstations, require the trusted users to periodically give their passwords, and set the real uid=root (instead of just the effective .ne 5 uid), so the entry might be modified to read something like: .sp .RS .nf \fB/* \ \ * \ \ \fITrustedUsers\fP \\ \fB\ \ \ \ \ \ \ \ \ !{\fIPatternsOfPublicWorkstations\fP} \\\fP \fB\ \ \ \ \ \ \ \ \ password=y timeout=5 uid=0\fP .fi .RE .sp .PP .SH The FullPath Field .PP The .I FullPath field gives the name of the actual command that will be executed, and if it contains an asterisk, the asterisk is first replaced by the user's .IR cmd string. The .I FullPath can optionally contain a list of initial arguments that precede any arguments passed by the user. For example, .sp .RS \fBxyz "/usr/local/bin/blah \-o1 \-o2 \-xrm 'a b c'" ...\fR .RE .sp specifies that when a valid user types .BR "super xyz" , the command to execute is .B /usr/local/bin/blah and its arguments will be .RS argv[1]: \fB\-o1\fR .br argv[2]: \fB\-o2\fR .br argv[3]: \fB\-xrm\fR .br argv[4]: \fBa b c\fR .RE followed by any arguments that the user put on the super command line. Note: asterisk replacement is only done on the filename part of the .IR FullPath , not on the arguments. You can safely include asterisks in the argument list. For security, the user's .I cmd may not contain any whitespace or backslashes. .PP The .I FullPath string is parsed using rules similar to the Bourne shell rules for backslashes in quoted strings, namely: .RS .br (a) backslash-newline is discarded; .br (b) Otherwise, if outside a quoted substring, \fB\\\fIx\fR \(-> plain \fIx\fR, which will not be treated as a delimiter, quotemark, or comment character; .br (c) Otherwise, inside a quoted substring of \fIFullPath\fR: .RS \fB\\\\\fR \(-> \fB\\\fR; .br \fB\\\fR\fIq\fR \(-> \fIq\fR, where .I q is the quote character that encloses the .I FullPath string; .br other backslashes are preserved: \fB\\x\fR \(-> \fB\\x\fR. .RE .RE .PP After writing a command with such backslash escapes, you should certainly use .RB `` super\ \-d\ cmd '' to check that your args are being parsed as expected before you offer this command to your users. .PP The same .I cmd can be listed several times in the .I super.tab file, in which case the first entry that allows the user to execute the command is chosen. The EXAMPLES section shows how this can be useful. .PP .SH Permitted Users .PP Permitted users are those who may execute the specified \fICmd\fP's. Entries for any number of permitted users are given after the .I CmdPat and .IR FullPath fields. Local options \(em options that apply to this command only \(em may also appear anywhere after the .IR FullPath . Options are distinguished from permitted users because options all have the form .IR key = value , whereas permitted-user entries may not contain unescaped equal signs. Each whitespace-separated word is a pattern in one of the formats .in +.5i .sp \(bu [\fBuser~\fP]\fIuser\fR[\fB:\fR][\fB@\fIhost\fR] .sp \(bu [\fBuser~\fP]\fB:\fIgroup\fR[\fB@\fIhost\fR] .sp \(bu [\fBuser~\fP]\fIuser\fR[\fB:\fIgroup\fR][\fB@\fIhost\fR] .sp .in -.5i Note that the .B user~ part is optional. The user's login name must match the .I user pattern; the user must belong to a group whose name matches the .I group pattern; and the hostname must match the .I host pattern. If the .I user, .I group, or .I host part is not given, there are no corresponding restrictions. .sp If the user is root, .I super acts as if all permitted-user patterns are preceded by the pattern .B user~root \(em that is, root's rule is default-allow, instead of the default-deny rule that applies to all ordinary users. .sp By default, the ``group'' field is first matched against named groups to which the user belongs, and then against the user's decimal gid \(em this allows the user to be put in a group in the /etc/passwd file that isn't given a name in the /etc/group file. (If you want to change the rules for using decimal gid, see the use of MATCH_DECIMAL_UID and MATCH_DECIMAL_GID in .I super.c for details.) .sp Since you can restrict users to particular hosts, a single .I super.tab file can be shared among many different machines. If the .I host part is of the form .BI + xyz , then .I xyz is interpreted as a netgroup name and any host in netgroup .I xyz is matched. In that case, .I xyz is taken literally, and .I not interpreted as a pattern to be matched. Note: netgroup lookup is only implemented if the function .I innetgr() is available. .sp If the .I host part doesn't match the hostname, it might be because the pattern and actual hostnames contain two different (but both valid) incomplete versions of the fully-qualified domain name (FQDN). By default, if the .I host part fails to match the hostname, the FQDN is looked up and all of the ways of naming the host are matched against the pattern. For example, if the FQDN is \fIspacely.sprockets.com\fP, .B super will first try .IR spacely.sprockets.com , then .IR spacely.sprockets , and finally .IR spacely . This can be turned off; see option .BR gethostbyname . (You might want to turn it off because using nameserver lookup can reduce security a bit \(em your host may query a nameserver on another host to obtain the FQDN, and (a) that nameserver or an intermediate host along the way could have been subverted, or (b) another host could impersonate the nameserver. In either case your computer could receive incorrect hostnames.) .PP The patterns for valid users, groups, and hosts follow the same rules for the .IR CmdPat s, described above: they can be entered with either .IR ed -style or Bourne-shell-style patterns (depending on the setting of the .B patterns global option); csh-style brace expansion is allowed; and all pattern matching is ``anchored'': patterns are forced to match the entire username, groupname, or hostname. .PP To make it easy to exclude some users/groups/hosts, any of these patterns can be negated by prefixing the pattern with `\fB!\fP'. If a negated pattern is matched, the user may \fInot\fP execute the command, even if there was a previous non-negated pattern that the user matched. All patterns are read left-to-right, and the last matched pattern ``wins''. Thus if the user/group/host list is .sp .RS .B j.* !jo .br or .br .B user~j.* !user~jo .RE .sp then the first entry allows any username beginning with `\fBj\fP' to execute the command, but the second entry disallows user `\fBjo\fP'. If entered in the reverse order, .sp .RS .B !jo j.* .RE .sp then the second entry, `\fBj.*\fP', allows all users beginning `\fBj\fP', and therefore the first entry has no effect. .PP .SH Permitted Times .PP The .B time condition restricts the days and times during which this command may be matched. If the execution time isn't acceptable, then super ignores the control line, and ``falls through'' to inspect the next entry, just as it does if the user/group/host aren't acceptable. A time condition looks like: .ti +.5i .BI time~ pattern .sp with .IR pattern s that look like: .sp .RS .\" Older .BR macros limit the number of arguments, so we insert .\" the font alternation explicitly in these examples (blecch!) .ta 3i \fIPattern Example\fP .br \fBhh\fR[\fB:mm\fR]\fB\-hh\fR[\fB:mm\fR][\fB/dayname\fR] 13:30-17/monday .br \fR{\fB<\fR,\fB>\fR,\fB<=\fR,\fB>=\fR}\fBhh\fR[\fB:mm\fR][\fB/dayname\fR] <17/tues .br \fBdayname\fP Friday .fi .RE .PP The first form explicitly specifies an interval during which the command may be used. Times may not go past midnight; to specify the night between Monday and Tuesday, you must do something like: .RS .B time~{17:30-24:00/mon,0-8/tues} .RE .sp The second form for time patterns allows you to use logical operators. The Monday-night example could equally have been rendered as: .RS .B time~{>17:30/mon,<8/tues} .RE (There is a tiny difference in the two examples above: in the first example, the time range includes 17:30 and 8:00; in the second example, the time range is 17:31\-07:59. Use \fBtime~{>=17:30/mon,<=8/tues}\fP to make the interpretation identical to the first example.) .PP If there are a series of time patterns, they are evaluated left-to-right, and the rightmost matching pattern is used. To permit execution between 17:30 Monday and 8:00 Tuesday, but exclude 0:00 to 1:00 Tuesday, use: .RS .B time~{>=17:30/mon,<=8/tues}\ \ !time~{0-1/tues} .RE .PP By default, valid .IR dayname s are English, but if your system supports the .IR setlocale( 3 ) function, the global option .BI lang= zzz will set the valid names to those of locale .IR zzz . Valid .IR dayname s are either (a) the full names of the chosen language; (b) an official abbreviated day name for that language; (c) a 3-or-more character abbreviation of the full weekday; or (d) \fB*\fP, meaning any day. (You can check on super's valid daynames by executing .IR super\ \-d , which will show the default names of the weekdays at or near the top of its debugging output, and show the new weekday names that take effect when the .BI lang= zzz option is encountered.) .PP Time patterns have a special defaulting rule when the execution time is not in one of the intervals in the time list: .RS \(bu if .I all time patterns are negated, .I super permits execution at any time not in one of the listed intervals; .br \(bu otherwise, there is at least one non-negated pattern, and .I super defaults to deny execution at times outside the specified acceptable intervals. .RE The reason is that the natural interpretation of a series of negated conditions, such as .RS .B !time~{0-8,17-24} !time~{sat,sun} .RE is to infer that all other times are acceptable for execution. On the other hand, if there are any ordinary, non-negated times, such as .RS .B time~8-17/{mon,tues,wed,thu,fri} .RE the natural interpretation is that any times not explicitly mentioned are not acceptable. .PP Note that explicit braces are important in the above list. If they were missing, the implied braces around the entire pattern would render this equivalent to .RS .B "time~8-17/mon time~tues time~wed time~thu time~fri" .RE That is, the permitted times are 8-17h on Monday, and any time on Tuesday through Friday. .PP .SH Global Conditions .ta 1i 2i 3i 4i 5i 6i .PP Global options and conditions affect the overall .B super processing. To set them, you must use a line like .sp .RS \fB:global\fP \fIGlobal\ Options\ And\ Patterns\fP .RE or .RS \fB:global_options\fP \fIGlobal\ Options\ And\ Patterns\fP .RE .sp For backwards compatibility, you can alternatively use .RS .sp \fB/ / \fIGlobalOptionsAndPatterns\fR .sp .RE but this use is discouraged. .PP These so-called ``global'' options and conditions actually take effect immediately after the line on which they appear, and are valid until the end of the input or until there is a countermanding global option or pattern. To have a global option or pattern affect the entire file, you must place it as the \fIfirst non-comment line\fR of the .I super.tab file. .PP If there are any PermittedUser or PermittedTime conditions on the global settings line, they are applied to each following command in the .I super.tab file. The conditions look like .sp .RS \fB:global \fIcond cond ... \fB<>\fP \fIcond cond ...\fR .RE .sp PermittedUser and PermittedTime conditions to the left of ``\fB<>\fP'' are processed .I before the local (per-command) conditions; conditions to the right of ``\fB<>\fP'' are processed .I after the per-command conditions. If ``\fB<>\fP'' is missing, all conditions are processed after the local conditions. Example 1: .sp .RS .B :global jan <> !@+badhosts .RE .sp says that user .I jan can usually execute any command, but under no circumstances will a user on any host in netgroup .I badhosts be allowed to execute any command. (User .I jan will not be allowed to execute a command if the per-command conditions disallow it, or if .I jan is on one of the .I badhosts computers). .sp Example 2: .RS .B :global !root <> .RE .sp changes .IR root 's default setting from default-allow to default-deny, just like ordinary users. Root will only be given execute permission for entries that explicitly allow root on the per-entry line. .sp Global PermittedUser (PermittedTime) conditions take effect on the line on which they are defined, and are good until another set of global PermittedUser (PermittedTime) conditions is entered on another .B :global_option line. That is, a new global condition line replaces any previous global conditions. .PP One sensible approach to using global conditions is to put conditions that allow users to execute commands \fIbefore\fR the per-command conditions are processed, and to put negating patterns (for users/groups/hosts that are never to be allowed to execute anything) \fIafter\fR the per-command conditions. .PP (Global options are discussed below, together with local options). .SH Conditionally-included Control Lines .PP Control lines can be conditionally included by using the .B :if control line. This can be helpful when using a single .I super.tab file for hosts with different architectures, or hosts in different NIS domains, etc. The syntax is: .sp .RS \fB:if \fIleft \ \ op \ \ \fIright\fP \ \ \ \ \fImoreText\fP .RE .sp The expression .I left op right is evaluated, and if true, .I moreText is evaluated as an ordinary control line. The valid comparison operators are: .ta 0.5i 1i 1.5i 2i 2.5 3i 3.5 4i 4.5 5i 5.5 6i .in +.5i .sp \(bu == string equality .br \(bu != string inequality .br \(bu ~ glob match string .I left against pattern .I right .br \(bu !~ negated glob-match. .br .in -.5i For example, you could include a file of commands only valid on Sun4-type machines as follows: .sp .RS .nf \fB:if $UNAME_MACHINE ~ sun* \\ \fB\ \ \ \ \ \ \ \ \ :include \ /Path/To/Sun4/File\fR .fi .RE .RB (UNAME_MACHINE is a variable automatically defined by .IR super ; see the following section on variables.) .sp If you wanted to exclude Sun4c-type machines from using the file, you could modify this to be: .sp .RS .nf \fB:if $UNAME_MACHINE ~ sun* \\ \fB\ \ \ \ :if $UNAME_MACHINE != sun4c \\ \fB\ \ \ \ \ \ \ \ \ :include \ /Path/To/Sun4/File\fR .fi .RE .sp There are no boolean operators provided, but note that there is an implicit boolean .B and available by concatenating .B :if commands, as shown in the second example above. .SH Variables .PP .B Super offers variables to make it easier to handle entries that are duplicated or are constructed out of other entries. Variables are defined by typing .sp .RS .B :define VariableName VariableDefinition .RE .sp or they may be imported from the environment by using .sp .RS .BI ":getenv " [ EnvVarName ...] .RE .sp If you use the .B :getenv command, then the values of any imported environment variables may only contain the following ``safe'' characters: .B \-/:+._a-zA-Z0-9. If ``bad'' characters are found in a value, the entire value is replaced with an empty string. Note that these imported variables do .I not enter the environment of any executed command; they simply become part of the super.tab variable set. .PP The .I VariableName should be made up only of letters, digits, and/or underscore. (You can actually use any characters you wish, but super doesn't promise to work correctly if you use characters outside the standard set.) .PP The .I VariableDefinition begins at the first non-whitespace character after the .I VariableName and continues up to but not including the final newline. Comments embedded on the variable definition line(s) are deleted before the variable definition is stored. A variable definition may be continued across multiple lines by preceding each newline with a backslash, and indenting the continuation line with whitespace. Just as for regular control lines, the backslash-newline-whitespace sequence is treated as whitespace if it follows a letter, digit, or underscore; otherwise, it is eliminated. For example, .sp .nf \fB .RS :define Users user1,\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ user2,\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ user3 .RE .fi and .RS :define Users user1,user2,user3 .RE \fR .sp are equivalent definitions. Unlike Makefiles, the variable definitions are not scanned first and then the file re-scanned. Instead, variables take effect at the point they are defined, and remain in effect until they are re-defined or end of file \(em thus variables definitions must precede their first use in the file. Variables may contain other variables (which must have already been defined). Variable substitution is done when a line is first read. A line is never re-scanned after variable substitution. Variables are used in a file by typing .sp .RS .B $VariableName .RE .sp or .sp .RS .B $(VariableName) .RE .sp The special variable .B $$ is replaced by a single .RB `` $ ''. Any other name .BI $ X (where .I X is not a letter, digit, or underscore) is an error. Because a line is never re-scanned after variable substitution, the following sequence: .sp .nf .RS .B :define A $$ .B :define B A .B :define C $B $$B .B $C .RE .fi .sp defines .B C to be simply .RB `` A\ $B ''. .PP Variables can be helpful in grouping users or hosts together. For example, you might restrict access to a command so that it can't be run from a public-access workstation: .nf .RS .B :define Room103_WS hosta,hostb,hostc,hostd .B :define Room105_WS hoste,hostf,hostg,hosth .B :define Room106_WS +nonprivate .B :define PublicWorkstations $Room103_WS,$Room105_WS,$Room106_WS .B SomeCmd FullPathHere !@$(PublicWorkstations) .RE .fi .PP In the above example, we have taken advantage of the implied braces that are always placed around any pattern, so that the comma-separated list of workstations is brace-expanded into .B !@hosta .B !@hostb\ ...\ !@hoste .BR !@hostf\ ...\ !@+nonprivate . .ta 1i 2i 3i 4i 5i 6i .PP Some variables are automatically defined by .I super. .PP After super determines whether it is processing a per-user .supertab (see super(1)), it defines .B IS_USERTAB to be ``\fIyes\fP'' if .I super is processing a per-user .supertab file, and ``\fIno\fP'' otherwise. The allows the super.init to act differently depending on how it is being invoked. .PP When the top-level .I super.tab file is opened, .B SUPER_OWNER is set to the login name of the owner, and .B SUPER_HOME is set to the home directory of the owner. This can be useful in per-user .I .supertab files, especially when they include files shared among several accounts. For example, each person's .I .supertab file could be simply .sp .RS .B :include /opt/proj/common.supertab owner=cristy .RE .sp Then, the .I /opt/proj/common.supertab file can use entries like the following: .sp .RS .B :global logfile=$SUPER_HOME/.superlog .br .B * /project/tools/$SUPER_OWNER/* :toolgroup .RE .sp Because the .B SUPER_HOME and .B SUPER_OWNER variables apply to the top-level per-user files, they always refer to per-user locations. .PP Super defines the built-in variable .B CALLER to be the the login name of the of account invoking super, and .B CALLER_HOME is the home directory of .BR $CALLER . Sample use: .RS .nf \fB sam /usr/sbin/sam group~operator uid=0 \\ env=DISPLAY \\ setenv=XAUTHORITY=$CALLER_HOME/.Xauthority \fP .fi .RE Here, the .I operator group can execute .I sam as root, and the GUI will display at the caller's display (due to the use of .BR env=DISPLAY ). Since the XAUTHORITY environment variable is set to the caller's .I .Xauthority file, this will give the caller access to the same display(s) to which s/he already has access. .PP The following variables are defined when super starts up. They can be useful in conditionally-included lines .RB ( :if lines). If your host doesn't supply these functions, or doesn't support some of the values that .I super tries to fetch, the corresponding variable will be initialized to an empty string. (Use .B super\ \-b to print the names and values of all builtin variables. This makes it simple to see what variable values to check in .B :if lines.) .ta 2i 2.5i .PP From the .I gethostname() or .I sysinfo() function: .in +.5i \(bu HOSTNAME Hostname, possibly canonicalized. .br \(bu HOST Hostname, short (unqualified). .br .in -.5i .PP From the .I getdomainname() function: .in +.5i \(bu NIS_DOMAIN domain set for NIS purposes. .br .in -.5i .PP From the .I sysinfo() function: .in +.5i \(bu SI_SYSNAME Name of operating system. .br \(bu SI_HOSTNAME Name of node. .br \(bu SI_RELEASE Release of operating system. .br \(bu SI_VERSION Version field of utsname. .br \(bu SI_MACHINE Kind of machine. .br \(bu SI_ARCHITECTURE Instruction set arch. .br \(bu SI_HW_SERIAL Hardware serial number. .br \(bu SI_HW_PROVIDER Hardware manufacturer. .br \(bu SI_SRPC_DOMAIN Secure RPC domain. .br \(bu .in -.5i .PP From the .I uname() function: .in +.5i \(bu UNAME_SYSNAME Operating system name. .br \(bu UNAME_NODENAME The nodename. .br \(bu UNAME_RELEASE Operating system release. .br \(bu UNAME_VERSION Operating system version. .br \(bu UNAME_MACHINE Machine hardware name (class). .br .RE .ta 0.5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i 4.0i 4.5i 5.0i 5.5i 6.0i 6.5i 7.0i .SH Options .PP The configuration file can specify a wide variety of options, such as requiring the user's password before executing some commands, or restricting the command-line arguments to match certain patterns. .PP .I Options are handled very differently from .I conditions (conditions include user, group, host, and time). If a control line's conditions aren't met, super falls through and tries the next control line in the file. After finding an acceptable control line, super will execute the command if the options are satisfied; otherwise, it stops and doesn't search the .I super.tab file any further. .PP Options can be divided into (a) \fIlocal\fP options, which are defined on a regular control line, and apply only to that control line; and (b) \fIglobal\fP options, which are defined on a .B :global or .B :global_options line, take effect immediately after the line, and are valid until the end of the input or until there is a countermanding global option or pattern. .PP All options are orthogonal to each other. It doesn't matter in what order they appear on a control line. .PP Some options can be given as either local or global options. If both are used, the local setting overrides the global one. .PP Two special names can be used with any of the options that take user or group ids as arguments: .BI owner= xxx, .BI uid= xxx, .BI euid= xxx, .BI gid= xxx, .BI egid= xxx, .BI u+g= xxx, .BI groups= xxx, .BI addgroups= xxx. These names are .BR , meaning the owner of the file to be executed (or the owner's group, whichever is appropriate in the context); and .BR , meaning the owner or group of the user calling super. The angle brackets are literally part of the name. These have the same values as the built-in variables .B CALLER and .B OWNER (see the .I Variables section, above). For example, the options .RS gid=Foo uid= .RE would change the group to .IR Foo , but leave the uid unchanged. .PP The recognized options are: .PP .I "Group 1. Options Affecting How Superfiles Are Read and Processed." .HP \fBpatterns=\fIxxx\fR .br .B (Global) Specifies the pattern-matching type for conditions and options. The string .I xxx must be one of: .RS .HP .B posix \(em patterns are POSIX regular expressions. You can use .RB `` posix/extended '' for extended regular expressions; .RB `` posix/icase '' for case-insensitive regular expressions; or .RB `` posix/extended/icase '' for both. See your regular-expression man pages for details. .HP .B regex \(em patterns are ed-style regular expressions, using the rules embodied in the BSD\ 4.x routines .IR re_comp()/re_exec() , with the addition of csh-style brace expansion. This is the default for historical reasons, but most people prefer to use shell-style patterns here, and it is recommended that you put \fBpatterns=shell\fP (see below) in your global options list. .HP .B shell \(em patterns are approximately Bourne-shell style, with the addition of csh-style brace expansion and the special .BI [[ chars ]] pattern. The patterns are formed from: .RS .HP \\x force x to be a plain character; .HP ? matches any single character; .HP * matches any sequence of 0 or more chars; .HP [\fIchars\fP] matches any single character in the set; .HP [^\fIchars\fP] matches any single char NOT in the set; .HP [[\fIchars\fP]] When the pattern begins with .BR [[ , and ends with .BR ]] , then each and every character in the string must match the ordinary square-bracket pattern .BI [ chars ] (or \fB[\fP^\fIchars\fP\fB]\fP). .HP ^\fIpat\fP inverts the sense of the match \(em the string must NOT match the pattern. .RE .RE .HP \fBlang=\fIzzz\fR .br .B (Global) This option sets the language used for weekdays (in time conditions). Here, .I zzz may be any locale available on your host. For example, .B lang=de would typically cause .I super to use German names. The default is the .B C locale, hence English names. .HP \fBrelative_path=\fIy\fR|\fIn\fR .br .B (Global) If \fIy\fR, FullPathNames can be relative instead of absolute. By default this is disallowed, because it is almost always a very foolish (unsafe) thing to do. .HP \fBgroup_slash=\fIy\fR|\fIn\fR .br .B (Global) If \fIy\fR, group names can contain a slash. By default this is disallowed, so that .B super can catch certain typos in the .I super.tab file. (Namely, .B super can catch errors in which an entry is of the form .IB Cmd : File instead of the required .IB Cmd :: File. The trouble is that .IB Cmd : File looks syntactically like .IB user : group, and can therefore be mistaken for a valid part of a control line. But the filename will contain a slash \(em unless you have unwisely enabled the .B relative_path option \(em so disallowing slashes allows .B super to flag the line as syntactically invalid.) .HP \fBgethostbyname=\fIy\fR|\fIn\fR .br .B (Global) Enables or disables the use of .I gethostbyname() to find the fully-qualified domain name (see the discussion in the .BR "Permitted Users" section, which describes the security issues associated with enabling this option.) Default: enabled (if your host supports gethostbyname()). .PP .I "Group 2. Logging Options." .HP \fBlogfile=\fIfname\fR .br .B (Global) Enables logging to a local file. Each invocation of .B super (aside from ones for help) generates an entry in file .IR fname . .HP \fBloguid=\fIxxx\fR .br .B (Global) If logging is enabled with logfile=\fIfname\fR, the logfile will be opened for writing using uid=\fIxxx\fR (can be either a username or numeric uid). This option allows you to have the file created/opened under another uid that does have cross-host access, such as the uid of a system manager. (See .I timestampuid=xxx for additional comments). Default: loguid=0. .HP \fBmail="\fImail-command\fB"\fR .br .B (Local|Global) Notices of super failures are piped to the shell command .IR mail-command . This is independent of the setting of the .B logfile and .B syslog options. For instance, \fImail="mail -s Super joeblow"\fR will cause error messages to be mailed to user .I joeblow (on some systems you may need to substitute .I mailx for .IR mail ). Note: the .I mail-command is executed by passing it as an argument to .IR popen(3) . This is safe to execute because of the clean environment assured by .B super. .HP \fBmailany="\fImail-command\fB"\fR .br .B (Local|Global) This is identical to the .I mail option, except that .I mailany sends notification of successful invocations as well as errors. .HP \fBrlog_host=\fIhostname\fR .br .B (Global) Tells super which host's syslog daemon is to receive log messages when option .B syslog=y is enabled. The option has no effect if used after the first message is logged: once the logger has been opened, it is not re-opened if the \fBrlog_host\fP is changed. Default: the local host. Note: One could instead configure the .I syslog.conf file to forward the messages to a central machine. .HP \fBsyslog=\fIy\fR|\fIn\fR .br .B (Global) Logging information is passed to the logs maintained by the .I syslogd daemon. This is independent of the setting of the .B logfile option (above). Error messages are by default logged at priority LOG_ERR and successful attempts to run programs are logged at priority LOG_INFO. (See options .I syslog_error and .I syslog_success to change these levels.) .HP \fBsyslog_error=\fIxxx\fR .br .B (Global) If syslog is enabled (see the .I syslog option), then by default super logs error messages using .I syslog(3) code .B LOG_ERR. This option changes the code to .IR xxx , where .I xxx is any of the usual .I syslog(3) priority and/or facility codes, such as .B LOG_WARNING or .BR LOG_LOCAL7|LOG_ERR . The .BI LOG_ xxx words can be separated by whitespace, dot, and/or ``|'', but of course you must use quotes if whitespace is included. The leading "LOG_" is optional, and the value is case-insensitive. For example, .B LOG_LOCAL7|LOG_ERR can alternatively be written as .BR local7.err . Super doesn't know what are sensible codes \(em it's up to the .I super.tab writer to choose meaningful values. For instance, if you put .ti +.5i .B\ syslog_error="LOG_INFO\ |\ LOG_ERR"\ \fI(bad!)\fP .br then you will get both those values or'd together and passed to .I syslog(). .HP \fBsyslog_success=\fIxxx\fR .br .B (Global) This option is just like .BR syslog_error , except that it applies to successful-execution messages instead of error messages. Default: .B LOG_INFO . .PP .I "Group 3. Extra Help Information for Users." .HP .BI info= xxx .br .B (Local) The string .I xxx is printed when giving help to users. It should be set to a helpful one-line description of the command. .PP .I "Group 4. Password and Other Restrictions Before Approval." .HP \fBmaxlen=\fR[\fImmm\fB,\fR]\fInnn\fR .br .B (Local|Global) Each argument must be no more than .I mmm characters long (including the terminating null), and the sum length of all arguments must not exceed .I nnn characters. A negative value means that no limit is applied. The defaults for .I mmm and .I nnn are set by the compile-time manifest constants MAXLEN1ARG and MAXLENARGS, which are usually 1000 and 10,000 characters, respectively. .HP \fBnargs=\fR[\fImmm\fB\-\fR]\fInnn\fR .br .B (Local|Global) The user is required to enter .I mmm - nnn arguments to the command. If just .I nnn is given, the user must enter exactly .I nnn arguments. These arguments are in addition to any arguments entered in the command part of the .I super.tab file. The default is to allow the user to enter any number of arguments. .HP \fBarg\fR[\fImmm\fB\-\fR]\fInnn\fB=\fIsss\fR .br .B (Local|Global) This means that the .IR nnn 'th or .IR mmm\-nnn 'th arguments must match pattern .IR sss . (Arguments are numbered from\ 1.) The pattern must be enclosed in quotes if it contains whitespace. Note that this option does not .I require that there be .IR mmm \- nnn arguments; it only says what those arguments must look like, if entered. You can use this option several times on one line, with different .IR mmm \- nnn values each time, to apply different patterns to different arguments. If more than one pattern applies to a given argument, all of those patterns must be matched. An empty pattern ("") is special: it has the effect of .I unsetting (removing) any previous patterns for the matching [\fImmm\fR\-]\fInnn\fR. This can be useful if you want to change .B :global settings, instead of adding to them. If there are local \fBarg\fR[\fImmm\fB\-\fR]\fInnn\fR option(s), they completely replace all global \fBarg\fR[\fImmm\fB\-\fR]\fInnn\fR values, even if the local .IR mmm \- nnn values do not overlap with the global values. .HP \fBowner=\fIxxx\fR .br .B (Local|Global) This option specifies that the .I FullPath (after asterisk-substitution) must be owned by user (or uid) \fIxxx\fR, or else it won't be executed. .HP \fBauth=\fIy\fR|\fIn\fR .br .B (Local|Global) If \fIy\fR, user authentication is required before the command is executed. The default authentication method is Unix password authentication. See also the options .IR authprompt , .IR authtype , .IR authuser , .IR timeout , and .IR renewtime , and be sure to read the warning under .I timestampbyhost. .HP \fBauthprompt=\fImessage\fR .br .B (Local|Global) Specifies the prompt used when authenticating the user (usually the default prompt is fine). Variable substitution is done on the prompt before printing. .HP \fBauthtype=\fItype\fR .br .B (Local|Global) Specifies the type of authentication used when .IR auth=y . The .I type can be .B password or .B PAM (if PAM is supported on your system). The default is .BR password . If PAM authentication is used, .I super uses the service name .RB `` super '' when looking for authentication in your system PAM configuration files. .HP \fBauthuser=\fIusername\fR .br .B (Local|Global) Specifies the user whose authentication is required when .IR auth=y . The default is the password (or other authentication) for the user who invoked super. .HP \fBpassword=\fIy\fR|\fIn\fR .br .B (Local|Global) This is a deprecated option; it has been replaced by the .I auth and .I authtype options. .B Password=y is equivalent to .B auth=y authtype=password ; and .B Password=n is equivalent to .B auth=n. .HP \fBrenewtime=\fIy\fR|\fIn\fR .br .B (Global) If \fIy\fR, the user's timestamp file is updated to the current time whenever an authentication-requiring command is executed. The result is that a user who frequently executes authentication-requiring commands won't need to re-authenticate until more than .I timeout minutes elapse since the last such command. Otherwise, the user will need to re-authenticate .I timeout minutes after last entering the password. The default is \fIn\fR. .HP \fBtimeout=\fIm\fR .br .B (Local|Global) User authentication is good for \fIm\fR minutes; that is, the command may be executed without re-authenticating for \fIm\fR minutes after the previous authentication (for any command). After \fIm\fR minutes, user authentication will be required again before the command can be executed. If \fItimeout\fR is zero or negative, authentication is required every time the command is used. The timestamp for user \fIusr\fR is recorded in the file \fBTIMESTAMP_DIR\fR directory (see \fBtimestampbyhost\fR and the FILES section, below). .HP \fBtimestampbyhost=\fIy\fR|\fIn\fR .br .B (Global) If \fIy\fR (default), the timestamp files are given names that are unique on each host. For instance, \fIjouser@somehost\fR will be given a timestamp file named \fITIMESTAMP_DIR/somehost/jouser\fR, where \fITIMESTAMP_DIR\fR is defined in the FILES section. If \fItimestmapbyhost=n\fR, the timestamp files are given names that are unique to each user, but not unique per host. For instance, \fIjouser\fR on any host will be given a timestamp file named \fITIMESTAMP_DIR/jouser\fR. .br .I WARNING: The hostname used is that from .I gethostname(). Note that this is not necessarily unique across internet domains, since it is frequently not a fully-qualified domain name. Therefore you should not share timestamp directories with hosts outside the local domain. (Generally such connections don't exist, but one .I could crossmount the timestamp directory disk...) .HP \fBtimestampuid=\fIxxx\fR .br If a password is required, the time at which it was entered is recorded as the mtime of a timestamp file. The timestamp file is normally created with owner=root; however, this option causes it to be created/modified using uid=\fIxxx\fR (\fIxxx\fR can be either a username or numeric uid). This option is useful when a network of hosts are sharing a cross-mounted timestamp directory. Note that networks are typically configured to not allow root on one host to have root access to files on another host, which will forbid root on other hosts from creating the timestamp file unless it's world-writable. This option allows you to have the file created/opened under another uid that does have cross-host access, such as the uid of a system manager. Default: timestampuid=0. .HP \fBcheckvar=\fIname\fR[,...] .br .B (Local) Each .I name in the comma-separated list is a .I super.tab variable which the user must enter at a prompt from .I super. For example, you might have a .B super shutdown command which halts the computer. If you execute this on the wrong host there may be some very annoyed users! So, you can include .BR checkvar=HOST , and the user will have to type the correct hostname in response to a prompt from .I super. .PP .I "Group 5. Modifications to Environment Before Executing Command." .HP .BI uid= xxx .br .B (Local) Sets the real uid to .I xxx just before executing the command. If option .B euid isn't used, also sets the effective uid to \fIxxx\fP. The uid .I xxx is first tried as a login name and then as a number. If the options .BI uid =xxx and .BI u+g =yyy (see below) are used together, then the .B u+g option only sets the group\ id, and not the user\ id. .HP .BI euid= xxx .br .B (Local) Sets the effective uid to .I xxx just before executing the command. The uid .I xxx is first tried as a login name and then as a number. .HP .BI gid= yyy .br .B (Local) Sets the real gid to .I yyy just before executing the command. If option .B egid isn't used, also sets the effective gid to \fIyyy\fP. The gid .I yyy is first tried as a group name and then as a number. .HP .BI egid= yyy .br .B (Local) Sets the effective gid to .I yyy just before executing the command. The gid .I yyy is first tried as a group name and then as a number. .HP .BI u+g= zzz .br .B (Local) Sets the real uid to .IR zzz , the real gid to .IR zzz 's login gid, and the supplementary groups list to .IR zzz 's supplementary groups just before executing the command. If the \fBeuid\fP and/or \fBegid\fP option aren't given, the effective uid and/or gid are also set. The options .I u+g and .BI gid=yyy conflict with each other, and may not be used together. .HP \fBgroups=\fIname\fR[,...] .br .B (Local|Global) By default, the user's supplementary groups list is deleted before executing a command (unless the option .B u+g is used). This option instead sets the group list to \fIname\fR[,...] .HP \fBaddgroups=\fIname\fR[,...] .br .B (Local|Global) This option adds the listed groups to the supplementary groups list. Since the default is to provide an empty supplementary groups list, this option usually has the same effect as the plain .B groups option. However, if the options .BI u+g= foo .BI addgroups= a,b,c are used, then the supplementary groups list is composed of user .IR foo 's supplementary groups plus \fIa, b\fR, and \fIc\fR. .HP \fBargv0=\fIname\fR .br .B (Local) Execute the command will execute with its first argument (that is, the argument conventionally denoted as .IR argv[0] ), set to .IR name . As a convenient shorthand, the value .BR (the angle brackets are literally part of the name) means to use the .I FullPath specified in the .I super.tab file. By default, .I argv[0] is set to .IR Cmd , the name of the .I super command invoked by the user, regardless of the actual path being invoked. However, some programs will not run properly unless .I argv[0] has a particular value. For example, suppose you want to permit users to safely mount zip disks, and you use something like: .ti +.5i .B zipmount "/etc/mount -o nosuid /dev/xz10 /zip" .br This command will fail if .I /etc/mount requires that it be invoked with .I argv[0] set to .RI [ .../ ] mount, because .I super will use the name .I zipmount. However, you can put .B argv0= into your super.tab file, and then the mount command will work properly. .HP \fBenv=\fIname\fR[,...] .br .B (Global|Local) Each .I name in the comma-separated list is an environment variable which should .I not be deleted before executing the .IR Cmd ; these variables are in addition to the normal variables created or passed by .B super (TERM, IFS, PATH, USER, LOGNAME, HOME, ORIG_USER, ORIG_LOGNAME, ORIG_HOME, LINES, COLUMNS, SUPERCMD). Be careful here; environment variables can sometimes be abused to create security holes. If you use the option more than once, the later instance overrides the earlier one, instead of adding to it. Similarly, using it as a local option completely overrides any global setting. .HP \fBmaxenvlen=nnn .br .B (Global|Local) Specifies the maximum length of an environment variable definition (including name, equal sign, value, and trailing null character). The default is given by the compile-time manifest constant MAXENVLEN, usually 1000 characters. A negative value means no limit. .HP \fBcd=\fIdir\fR .br .B (Local|Global) Just before executing the command, .I super changes the working directory to .IR dir . .HP \fBsetenv=\fIvar\fB=\fIxxx\fR .br .B (Local|Global) The environment variable .I var is defined to have the value .IR xxx , and is passed on when executing the .IR Cmd . You can add several environment variable definitions by using the option more than once. .HP \fBfd=\fIn\fR[,...] .br .B (Local) Each file descriptor .I n in the comma-separated list should .I not be closed before executing the .I Cmd. These descriptors are added to the usual set of descriptors kept open, namely 0, 1, 2. .HP \fBnice=\fIn\fR .br .B (Local|Global) changes the ``nice'' value of the executed command by an amount .I n from the default level. (Positive increments reduce the command's priority; negative increments increase it.) .HP \fBumask=\fInnn\fR .br .B (Local|Global) sets the umask of any executed command to .IR n . A leading .B 0x or .B 0X in \fInnn\fP means a hexadecimal value; otherwise, a leading .B 0 means octal; otherwise it's decimal. .PP .I "Group 6. Other Options" .HP .BI print= message .br .B (Local) If the rest of the line is matched, then .B super prints the specified .I message just before executing the command. .HP .BI die= message .br .B (Local) If the rest of the line is matched, then .B super does variable-substitution on the specified message .IR message , prints it, and exits. This lets you conveniently set up some ``stop'' conditions, and use the die option to prevent super from looking at any line past the stop conditions. Otherwise, you'd have to individually attach the stop conditions to every control line. .SH Include Files .PP A .I super.tab file can include other files by means of an entry like .RS .BI :include \ filename\ [ \ owner= xxx\ ]\ [ \ group= yyy\ \ ] .RE or .RS .BI :optinclude \ file\ [ \ owner= xxx\ ]\ [ \ group= yyy\ \ ] .RE If the .I file isn't an absolute path, it is taken to be relative to the directory containing the .I super.tab file. Include files may be nested up to the system limit on the number of simultaneously-open file descriptors. .PP The .BI owner= xxx option specifies that the .I file must be owned by user .I xxx; the .BI group= yyy options specifies that the .I file must belong to group .I yyy. If .BI group= yyy is specified, then the file can be group-writable; by default, the file must be writable only by owner. This can be useful for a collection of accounts that are operated together as part of a single project \(em the several of accounts can share .I .supertab files by .BI :include -ing files belonging to the trusted user .I xxx and/or group .I yyy. Notes: .RS .PP 1. The regular root-owned .I super.tab file can also use the .I owner= or .I group= constructs, but it's not a good idea. Don't do it. .PP 2. Beware of the transitive nature of this trust: the file owned by .I xxx can in turn include a file owned by yet another user. You might wind up trusting a user you didn't intend to trust! .RE .PP The difference between .B :include and .B :optinclude is that the former generates an error if the named file doesn't exist, whereas the latter (optional-include) silently ignores files that don't exist. .PP .I WARNING: You should use .B :optinclude with great caution, and be sure not to depend on that file being present. It is easy to imagine a scenario in which an administrator carelessly changes an entry so that the wrong permission is granted if an :optinclude'd file was missing. .SH FILES .TP .I @SUPERDIR@/super.tab The location of the .I super.tab file on your system. .TP .I @SUPERDIR@/super.init The location of the .I super.init file on your system. .TP .IR @TIMESTAMP_DIR@/ username Default location of the file whose \fImtime\fR is used as the timestamp for the last time the user entered his or her password for password-requiring commands. Check your installation for the directory used on your system. .SH EXAMPLES .ta 1i 4i .HP Example 1. The control line .sp .in +.5i .nf doit /usr/local/bin/doit \\ me \\ you@{h1,h32} \\ ja.*:ok_j \\ :goodguys .fi .in -.5i .sp allows /usr/local/bin/doit to be run setuid-root by .in +.5i \(bu user .B me on any host, .br \(bu user .B you on hosts .B h1 and .BR h32 ; .br \(bu any users named .B ja.* in group .BR ok_j ; .br \(bu and anybody in group .BR goodguys . .br .in -.5i .HP Example 2. The pair of control lines .sp .in +.5i .nf doit /usr/local/bin/doit \\ u+g=smith env=TZ,TAPE \\ password=y timeout=0 \\ jo@PublicWorkstation doit /usr/local/bin/doit \\ u+g=smith env=TZ,TAPE \\ jo .fi .in -.5i .sp allows user .B jo to run /usr/local/bin/doit with uid\ =\ \fBsmith\fP, gid\ =\ \fBsmith\fP's login gid, and keeping the environment variables TZ and TAPE in addition to the standard set. If user .B jo is at .BR PublicWorkstation , the first entry will match, requiring jo's password every time the command is used; otherwise, .I super will match at the second entry, and no password is needed to run the command. .HP Example 3. Here is an entry restricting CD-ROM mounting on different hosts: .B tas is the only user who may mount CD's on .BR elgar ; anybody in group .B xyz may mount CD's on .B alpha or .BR delta ; and anybody on a host in the netgroup .B india may mount a CD on the .B india hosts. However, user .B jo may never run \fIcdmount\fP, regardless of his or her group or host (assuming that there is no overriding global pattern that permits .B jo to use the command). Note that shell-style patterns are used, not regex-style patterns. .sp .in +.5i .nf cdmount /usr/local/bin/cdmount \\ tas@elgar \\ :xyz@{alpha,delta} \\ *@+india \\ !jo .fi .in -.5i .sp .SH "SEE ALSO" .BR super (1). super-3.30.0/Makefile.in0000444000104100002640000002153510732537455013331 0ustar willspg srcdir = @srcdir@ VPATH = @srcdir@ CC = @CC@ CFLAGS = @CFLAGS@ USER_DEFS = @DEFS@ INSTALL = @INSTALL@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ # # DESTDIR NOTE: # At build time: DESTDIR has _nothing_ to do with the paths used. # At install time: All paths are relative to DESTDIR. # # This lets you make a test installation by doing "make DESTDIR=/xyz install", # and then visually verifying that all files are correctly located # w.r.t. DESTDIR and have correct permissions. This is also useful for # generating an RPM. # However, since the compiled-in paths _never_ include DESTDIR, a # correctly functioning install for runtime use must do simply "make install". # DESTDIR= prefix = @prefix@ exec_prefix = @exec_prefix@ bindir=@bindir@ sysconfdir = @sysconfdir@ localstatedir = @localstatedir@ mandir = @mandir@ # # Where the super(1) binary is installed # BINDIR = $(bindir) # # Name of the timestamps directory # TIMESTAMP_DIR=$(localstatedir)/super/timestamps D_TIMESTAMP_DIR=-DTIMESTAMP_DIR=\"$(TIMESTAMP_DIR)\" # # Where the super.tab and super.init files are installed: # SUPERDIR=$(sysconfdir) D_SUPERDIR=-DSUPERDIR=\"$(SUPERDIR)\" # # If your system supports "const", define D_CONST to be "", but if # your system doesn't support "const", define D_CONST to be "-Dconst=". # (When used in CFLAGS, it will define away the const keyword for # systems that don't support it, but have no effect on those that do.) # D_CONST=@ConstDef@ # # # Where the user man page is placed. # MAN1DIR = $(mandir)/man1 # Do _not_ include a leading dot in the extension! MAN1EXT = 1 # # Where the man page for the super.tab file is placed. # MAN_FORMAT_DIR = $(mandir)/man5 # Do _not_ include a leading dot in the extension! MAN_FORMAT_EXT = 5 # SYSLOG_PRIORITY specifies the priority of syslog messages. # If you don't define it, the default is LOG_ERR. # (Regardless of this setting, _successful_ executions are logged # at priority LOG_INFO.) # If you are using standard syslog(), you may define it symbolically, # for example: # -DSYSLOG_PRIORITY=LOG_ERR # or # -DSYSLOG_PRIORITY="(LOG_LOCAL1 | LOG_WARNING)" # But if you are using rsyslog(), you should define it differently: # its value depends on the machine which will _receive_ the log # messages, NOT the sending machine. It should be defined in the # Makefile because the value can differ on the machine that compiles # and runs super, compared to the value on the log host. # For example, if your receiving machine is a Sun running SunOS 4.1.3, # or HP-UX 8.x or 9.x, using -DSYSLOG_PRIORITY='((17<<3)+4)' will set # the priority of the networked syslog to the facility LOG_LOCAL1, with # the priority LOG_WARNING. The log machine should have a line that # matches this in its syslog.conf file; for the above priority, use # an entry like: # /etc/syslog.conf:local1.warning /var/adm/super.log # SYSLOG_PRIORITY=LOG_ERR D_SYSLOG_PRIORITY=-DSYSLOG_PRIORITY=$(SYSLOG_PRIORITY) # Even if this system is PAM-capable, don't use unless WITH_PAM is defined. D_WITH_PAM=-DWITH_PAM=@with_pam@ BASIC_DEFS = $(D_SUPERDIR) $(D_TIMESTAMP_DIR) $(D_SYSLOG_PRIORITY) $(D_CONST) $(D_WITH_PAM) # # ################################################################### # You probably don't have to edit anything below here. # ################################################################### # COMPILE = $(CC) -c $(BASIC_DEFS) $(USER_DEFS) -I. $(INCLUDES) $(CPPFLAGS) $(CFLAGS) LINK = $(CC) $(LDFLAGS) -o $@ .SUFFIXES: .SUFFIXES: .c .o .in .c.o: $(COMPILE) $< .in: sed -e 's!@SUPERDIR@!$(SUPERDIR)!g' \ -e 's!@SAFE_PATH@!@SafePath@!g' \ -e 's!@TIMESTAMP_DIR@!$(TIMESTAMP_DIR)!g' < $< > $@ #################################################################### # You really shouldn't have to modify anything below this line. #################################################################### MOST_SRC= $(SUPER_SRC) $(SETUID_SRC) SUPER_C_SRC = super.c approve.c checks.c colon.c braces.c error.c \ getpass.c gsgroups.c s_hsearch.c options.c pam.c \ p_regex.c s_regex.c s_re_fail.c rsyslog.c \ strqtokS.c time.c utils.c wildmat.c SUPER_H_SRC = s_hsearch.h version.h options.h super.h SUPER_SRC = $(SUPER_C_SRC) $(SUPER_H_SRC) SETUID_SRC = setuid.c SUPER_OBJ= super.o approve.o checks.o colon.o braces.o error.o \ getpass.o gsgroups.o s_hsearch.o options.o \ p_regex.o s_regex.o s_re_fail.o rsyslog.o \ strqtokS.o time.o utils.o wildmat.o @LIBOBJS@ # Files that go into the shar file. The files after $(MOST_SRC) # are those that are conditionally compiled via the configure-substituted # LIBOBJS. ALL= README README.Y2K INSTALL INSTALL.notes Artistic Copying WhatsNew \ configure configure.in install-sh localsys.h mkdir_p \ Makefile.in super.1.in super.5.in config.h.in \ setuid.1.in super.spec.in barebones.tab \ sample.tab sample.cdmount sample.cdumount \ $(MOST_SRC) misc_conv.c pam_misc.h all: config.h super setuid super.1 super.5 setuid.1 super: config.h $(SUPER_OBJ) $(CC) $(LDFLAGS) -o super $(SUPER_OBJ) $(LIBS) debug: config.h $(SUPER_OBJ) $(CC) $(LDFLAGS) -o super $(SUPER_OBJ) $(LIBS) /usr/lib/debug/malloc.o setuid: setuid.o $(CC) $(LDFLAGS) -o setuid setuid.o config.h: @echo "'config.h' doesn't exist or is out of date compared to config.h.in..." @echo "You must run './configure' to generate config.h." @echo "If you are making 'super' for the first time on this system," @echo "you should probably do a 'make veryclean' before executing ./configure." @exit 1 cflow: cflow $(SUPER_C_SRC) > cflow.out cflow -r $(SUPER_C_SRC) > cflow.rev # NOTICE NOTICE NOTICE! # You must install super as "super", and not use any other program name. # This is because at run-time, the program assumes that if it's invoked # with a different name, it must have been invoked via a symlink, and # it treats # % myothernameforsuper args # as if you typed # % super myothernameforsuper args # If you insist on installing under another name, then you must # change the #define ONETRUENAME from "super" to your other # name, and edit the documentation to match. install: install-bin install-man install-bin: super setuid ./mkdir_p -p755 $(DESTDIR)/$(BINDIR) ./mkdir_p -p755 $(DESTDIR)/$(localstatedir) ./mkdir_p -p755 $(DESTDIR)/$(sysconfdir) ./install-sh -c -o root -m 04755 super $(DESTDIR)/$(BINDIR)/super ./install-sh -c -o root -m 0755 setuid $(DESTDIR)/$(BINDIR)/setuid test -f $(DESTDIR)/$(sysconfdir)/super.tab && \ echo "Not overwriting existing file $(DESTDIR)/$(sysconfdir)/super.tab" || \ ./install-sh -c -o root -m 0644 barebones.tab \ $(DESTDIR)/$(sysconfdir)/super.tab install-man: super.1 setuid.1 super.5 ./install-sh -c -o root -m 0644 super.1 \ $(DESTDIR)/$(MAN1DIR)/super.$(MAN1EXT) ./install-sh -c -o root -m 0644 setuid.1 \ $(DESTDIR)/$(MAN1DIR)/setuid.$(MAN1EXT) ./install-sh -c -o root -m 0644 super.5 \ $(DESTDIR)/$(MAN_FORMAT_DIR)/super.$(MAN_FORMAT_EXT) clean: -rm -f super setuid *.o distclean veryclean: clean -rm -f super.1 super.5 setuid.1 config.h config.cache config.status config.log $(ALL): co $@ tellversion: version.h ( echo "#include " ; \ echo '#include "version.h"' ; \ echo 'main() {printf("%s.%s",Version,Patchlevel);exit(0);}') > temp.c $(CC) -o tellversion temp.c rm temp.c # Because of the wide variation in shar commands, the shar arguments # used below sticks to a minimal set, and we generate various shar file # headers by hand. shar super.shar: $(ALL) tellversion V=super-`./tellversion`; mkdir $$V && cp $(ALL) $$V && \ (echo "Submitted-by: will@ucolick.org" ; \ echo "Archive-name: $$V/part01" ; echo "" ; \ echo "---- Cut Here and feed the following to sh ----" ; \ shar $$V ) > super.shar && rm -rf $$V && cp -p super.shar $$V.shar tar super.tar: $(ALL) tellversion V=super-`./tellversion`; mkdir $$V && cp $(ALL) $$V && \ tar -cf super.tar $$V && rm -rf $$V # Make both super.tgz and copy it to the version'd -tar.gz form that # rpm wants. tgz super.tgz: $(ALL) tellversion V=super-`./tellversion`; mkdir $$V && cp $(ALL) $$V && \ gtar -czf super.tgz $$V && rm -rf $$V && cp -p super.tgz $$V-tar.gz # Create an RPM spec file. Note that super.spec is copied to a # versioned .spec file of the form wanted by rpm. (The non-versioned # form gives us a simple makefile targett.) spec super.spec: super.spec.in tellversion sed -e "s!@version@!`./tellversion`!" super.spec.in > super.spec cp -p super.spec super-`./tellversion`-`./rpmrelease`.spec # # Only invoke this if you want to create source and binary rpm's from # this source tree. # # To create rpm's: set rpmdir to the directory tree (e.g. /usr/src/redhat) # in which you want to create the RPM's. rpmdir=/u/will/myrpm rpm: super.tgz super.spec tellversion cp super-`./tellversion`-`./rpmrelease`.spec $(rpmdir)/SPECS cp super-`./tellversion`-tar.gz $(rpmdir)/SOURCES rpmbuild -ba --buildroot /var/tmp/super-`./tellversion` \ $(rpmdir)/SPECS/super-`./tellversion`-`./rpmrelease`.spec depend: makedepend -- $(CFLAGS) -- $(SRC) super-3.30.0/super.c0000444000104100002640000016332310732537455012570 0ustar willspgstatic const char rcsid[] = "$Id: super.c,v 1.613 2007/12/20 19:14:30 will Exp $"; /* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "super.h" #include "version.h" /* * Super allows users to execute other programs, particularly * scripts, as root (or another user/group), without unduly * compromising security. * * Use: * * $0 -h, $0 -V * ...give usage info or print just the version number. * * $0 [-H | -f] [-F superfile] [ -T hh[:mm][/day] ] [-U uid] [-G gid] * ...lists allowed commands. * * $0 [-r path] [-o path] [args...] * ...execute command. * * $0 -b * ...lists builtin variables (useful when creating super.tab). * * $0 [-d | -D | -t] [-F superfile] [-T time] [-U uid] [-G gid] [-M mach] \ * [-r reqpath] [--] [commandname [args...]] * $0 [-d | -D | -t] [-F superfile] [-T time] [-U uid] [-G gid] [-M mach] \ * [-r reqpath] -o path [--] [args...] * ...debug mode (-d, -D) or test mode (-t). * * $0 -c [superfile] * ...just check syntax of the superfile. * * Options: * -b -- print the "builtin" variables, then exit. * -c [superfile] -- check syntax of superfile, but don't execute anything. * -d -- debug mode: show what would be done, * but don't actually execute a command. * -D -- verbose debug mode: same as -d, plus tell more about variables. * -t -- test mode: test if requested command is valid, but don't * execute it. Exit code=0 if valid, else 1. * -F superfile -- names the super file to use; for testing only. * No command will actually be executed. * -G gid -- act as if the invoking user was group gid; for testing only. * No command will actually be executed. * -M mach -- act as if the machine (hostname) was mach; for testing only. * No command will actually be executed. * -T hh[:mm][/day] -- act as if the command is executed at the specified * time; for testing only. No command will actually be executed. * -h -- usage: print usage info, then exit. * -H -- a long-winded listing of allowed commands for this user, * then exit. * -f -- (just the facts, ma'm) a version of -H that prints no extra * info, just a list of what you can execute, using the format: * Cmd FullPath [initial args] * Cmd FullPath [initial args] * ... * Useful for scripts that want a list of what you may execute. * -S -- force stdin to be used for reading passwords. * -U uid -- act as if the invoking user was user uid; for testing only. * No command will actually be executed. * -V -- print version information, then exit. * -o file -- Per-user .supertab linking: if /path/to/xyz is a symlink * to a user's personal .supertab file, and the .supertab file * begins with #! /path/to/super -o, then the shell will invoke * super with arguments like super -o /path/to/xyz [args], * and super will treat this as 'super :xyz [args]. * MUST be last argument; everything following -o file is treated * as user's arguments. * -r path -- error if the FullPath isn't the same file as this path. * For sanity checking; a program can use * test "X$SUPERCMD" = "X$prog" || \ * exec /usr/local/bin/super -r $0 $prog ${1+"$@"} * and it will be an error if 'super ' isn't going to * invoke this file, ie $0. * * The super.tab file names each command that super will execute, and * says who can use it. See super.tab.summary for an overview. */ /* Non-STD-C implementations do not have uniform ways of pasting strings * together. So we will compose the actual superfile and super.init * names at runtime. */ char superfile_writable[MAXPATHLEN+100];/* The super.tab file -- put it * into a char array so we can * overwrite it later, if nec. */ char *superfile = superfile_writable; char superfile_init[MAXPATHLEN+100]; /* The super.init file */ /* Global info */ GlobalInfo globalinfo = { "", /* owner (required owner of file) */ NULL, /* chdir_path (char *) */ 0, /* relative_path (bool) */ 0, /* group_slash (bool) */ MAXENVLEN, /* maximum length of environment variable defn */ NULL, /* additional permitted envvars */ 0, /* nice_incr (int) */ 0, /* mask (umask) */ MAXLEN1ARG, /* maximum length of a single argument */ MAXLENARGS, /* maximum length of all arguments, combined */ {-1,-1}, /* min, max number of args (-1 = no limit) */ {NULL,0,0,NULL}, /* argpats */ { /* Global password requirements */ 0, /* bool: is authentication required? */ SUPER_AUTH_PASSWORD, /* authentication method, if required */ 5, /* timeout (min) */ 0, /* renewtime (bool) */ 1, /* perhost (bool) */ "", /* authuser */ "", /* user (user who owns timestampuid file) */ NULL}, /* prompt */ {0,NULL,NULL}, /* userbefore: list of u/g/h pats before per-cmd pats */ {0,NULL,NULL}, /* userafter: list of u/g/h pats after per-cmd pats */ {0,NULL}, /* b_a_text: list of original text for above */ 1, /* user_clear: (bool: clear if new val seen) */ {{0,0,0,0}, /* timebefore: permitted times before per-cmd pats */ NULL}, {{0,0,0,0}, /* timeafter: permitted times after per-cmd pats */ NULL}, 1, /* time_clear: clear if new val seen */ 0, /* use_after: set to !0 when we see <> */ { NULL, /* log: FILE *fp */ "", /* filename */ "", /* user: value of loguid=xxx */ 0, /* uid: UID under which we open logfile */ -1, /* pid: PID of the logger process */ 0, /* newfile: !0 if logfile given but not yet used */ 0, /* newuid: !0 if loguid given but not yet used */ LOG_INFO }, /* syslog() priority for success message */ "", /* mailcmd */ 0, /* mail_success (bool) */ 1, /* use gethostbyname (bool) */ {0}, /* groups[]: gid's of supplementary groups */ GROUPS_NOTSET, /* ngroups: number of supplementary groups */ 0, /* groups_added */ {NULL}, /* first element of the setenv array. We keep this * at end of global struct, so that we don't have * to initialize every element in order to reach other * struct elements. */ }; /* The list of currently open files */ FileList *currfile = NULL; char authInitMsg1[1024] = ""; /* message from auth init, if any */ char authInitMsg2[1024] = ""; /* suppl message from auth init, if any */ int authInitErrno = 0; /* set to !0, if there's an errno to go * with the authInitMsg1. */ /* The struct of what things we've matched */ Conditions matches; /* The localinfo struct is filled in a bit at a time until it completely * describes the caller, the program to invoke, any options * set in the control line, etc. */ UserInfo userinfo; LocalInfo localinfo = { {NULL, -1, 0, "", 0, 0}, /* Initialize ProgMatch empty */ /* Other elements that need * start initializers are done * through explict assignment. */ }; extern char *s_re_comp P__(( char *)); /* regular-expression compiler */ int shell_compare P__(( char * )); /* s_re_comp()-style i/f to wildmat() */ extern int s_re_exec P__(( char * )); /* regular-expression comparison */ char *shell_compile P__(( char * )); /* s_re_exec()-style i/f to wildmat() */ char *prog; /* this program */ int debug=0; /* Set by the debug options flag */ int use_stdin=0; /* Set by the -S flag */ int it_came_from_cmdline=0; /* Set by -F/-T/-U/-G/-M flags */ int test_mode=0; /* Set by -t flag */ int check_syntax=0; /* Set by the -c options flag */ int using_user_supertab = 0; /* !0 means using a user's .supertab */ SimpleList Var_Value = {NULL, NULL}; /* Routines used to compile/match user/group/host patterns */ char *(*pat_compile) P__((char *)) = s_re_comp; int (*pat_compare) P__((char *)) = s_re_exec; int need_re_anchor = 1; /* For strqtokS */ unsigned char my_qm[256]; /* our quotemarks */ unsigned char my_cc[256]; /* our comment characters */ /* Core dump restrictions were shamelessly borrowed from Wietse * Venema's logdaemon code, to disable core dumps with cleartext * or shadow passwords. */ #ifdef RLIMIT_CORE struct rlimit old_core_limit; struct rlimit new_core_limit; #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int main(argc, argv) int argc; char **argv; { int status, n_builtin; char *s, *cmd, *path, *user; char **arglist, **envp; extern char *error_prog; int iarg, givehelp, giveversion, verbosity, printvars; char *o_file; /* The argument to -o xxx */ char *r_path; /* The argument to -r path */ #ifdef RLIMIT_CORE getrlimit(RLIMIT_CORE, &old_core_limit); new_core_limit.rlim_cur = 0; new_core_limit.rlim_max = old_core_limit.rlim_max; setrlimit(RLIMIT_CORE, &new_core_limit); #endif check_stdio(); sprintf(superfile_writable, "%s/%s", SUPERDIR, "super.tab"); sprintf(superfile_init, "%s/%s", SUPERDIR, "super.init"); s = strrchr(argv[0], '/'); prog = (s && *(s+1)) ? s+1 : argv[0]; error_prog = ONETRUENAME; /* same as prog, but used by Error() */ debug = check_syntax = giveversion = givehelp = printvars = 0; verbosity = HELP_BASIC; /* only matters if *givehelp != 0 */ o_file = NULL; r_path = NULL; error_srcfile = superfile; /* error messages w/ line nums refer to this */ error_line = -1; if (add_variable("$", "$") == -1) /* Built-in variable $$ -> "$" */ return 1; if (init_userinfo() == -1) /* Initialize userinfo struct. */ return 1; init_globalinfo(); /* Initialize globalinfo struct. */ init_localinfo(); /* Initialize localinfo struct. */ add_variable("PATTERNS", "regex"); /* default pattern lookup */ add_builtin_variables(); /* Define variables that describe this system */ if (get_encrypted_pw()!=0) { /* Get caller's encrypted password while we */ /* definitely have privs. This allows */ /* .supertab files to do password checking. */ *userinfo.encr = '\0'; *userinfo.salt = '\0'; if (geteuid() != 0) { sprintf(authInitMsg2, "\tWon't be able to do password-checking. \ Note: this copy of super is not running setuid-root, \ so it can't check passwords on modern Unix systems.\n\n"); } else { sprintf(authInitMsg2, "\tWon't be able to do authentication \ (password-checking, or whatnot).\n\n"); } } /* Decide if we were invoked as "super cmd args...", or * as a link: cmd args... */ if (strcmp(prog, ONETRUENAME) == 0) { /* Invoked as super [options] cmd [arg ...]. */ iarg = do_options(argc, argv, &givehelp, &giveversion, &verbosity, &printvars, &o_file, &r_path); if (iarg < 0 || (argv[0] == NULL && !(givehelp || giveversion))) { /* User screwed up; give minimal help */ fprintf(stderr, "Type %s -h for usage information.\n", prog); exit(1); } if (o_file) { /* Cmd is last component of the o_file path, e.g. * -o a/b/c means the cmd is "c". */ if ((cmd = strrchr(o_file, '/'))) { /* found last slash in path */ cmd++; if (*cmd == '\0') cmd = NULL; /* shouldn't ever happen */ } else { /* there is no slash */ cmd = o_file; } argv += iarg - 1; /* Skip over the super options */ } else { /* Cmd is next argument on cmd line, if any */ cmd = argv[iarg]; argv += iarg; /* Skip over the super options */ if (!cmd || !*cmd) { /* No cmd was given after options. */ if (!giveversion) /* If user didn't give -V, and didn't */ givehelp = 1; /* ...give cmd, default is givehelp */ cmd = NULL; } } /* Test if we simply print variables, then bail out. */ if (printvars) { printf("Builtin variables:\n"); hprint(HS_VARS, print_variable); exit(0); } } else { /* It's been invoked via link to super. Therefore any options * go to the command, not to super. */ s = strrchr(argv[0], '/'); cmd = (s && *(s+1)) ? s+1 : argv[0]; } if (debug) debug_hello(); init_strqtokS(); /* * Check if we need to switch to processing a user's super file */ using_user_supertab = 0; if (o_file) { /* Have `-o file' */ using_user_supertab = 1; user_supertab(o_file, 1, cmd); } else if (cmd && (s=strchr(cmd, ':'))) { /* Have user:command */ using_user_supertab = 1; user = cmd; if (s == user) Error(0, 1, "Commands may not begin with `:'\n"); *s = '\0'; /* null-terminate the `user' part */ cmd = s+1; if (!*cmd) { /* No cmd given after `user:' */ if (!giveversion) /* If user didn't give -V, and didn't */ givehelp = 1; /* ...give cmd, default is givehelp */ cmd = NULL; } user_supertab(user, 0, cmd); } /* Set a variable that a super.tab (or super.init) can use to determine * if we're processing a user's .supertab or not. */ if (add_variable("IS_USERTAB", using_user_supertab ? "yes" : "no") == -1) exit(1); if (check_syntax) Error(0,0, "Checking syntax of superfile `%s'\n", superfile); /* Print version if explicitly requested or if giving help */ if ((givehelp && verbosity != HELP_FACTS) || giveversion) (void) printf("%s version %s patchlevel %s\n", prog, Version, Patchlevel); /* If giving version, and not giving help, and there's no command, stop */ if (giveversion && !givehelp && !cmd) exit(0); /* Check for permission to execute, and change uid/gid as necessary */ error_counter = 0; /* incremented by Error() */ if ((path = approve(cmd, givehelp, verbosity)) == NULL) { return 1; } else if (*path == '\0') { /* shouldn't try to execute anything */ if (check_syntax) { return (error_counter) ? 1 : 0; } else { return 0; } } /* Get the arglist for the command, and null-terminate cmd if not * already done so. Do this before things like get_owner, because * newargs() parses paths that look like "command args" and separates * out the command part. */ arglist = newargs(path, argv, &n_builtin); /* Check argument lengths */ if (check_arglistlen(argv) != 0) return 1; /* Determine ownership of the program */ if (get_owner(path, &localinfo.file_uid, &localinfo.file_gid) != 0) return 1; /* Sanity check */ if (check_syntax) Error(0, 2, "Abort: shouldn't ever get here when check_syntax is set!\n"); /* Check that the file to execute has proper ownership */ if (check_owner() != 0) return 1; /* If nice increment is negative, we have to do it here, while we * are still root (note that the uid= option can be used to run * as non-root, and we can't do negative nice's as non-root). Positive * nice increments are done later, just before exec'ing, so that we * don't have to do the rest of _this_ program at reduced priority. */ if (localinfo.nice_incr < 0) { if (it_came_from_cmdline) { Error(0, 0, "Not applying nice increment = %d because of flag -F/-T/-U/-G/-M.\n", rcl_nice_incr()); } else if (test_mode) { /* silently don't apply nice increment */ } else if (set_nice_incr() == -1) { return 1; } } /* Check authorization requirements. * Just as for negative nice increment, this require root privileges * to read a shadow password file or switch to another uid for writing * the timestamp file. */ if (!test_mode) { if (check_auth(cmd) != 0) { return 1; } } /* Set uid/gid if necessary */ if (using_user_supertab) { /* Already changed to user's uid/gid earlier */ status = 0; } else { status = set_u_g(); } /* Button up for security, and get a modified environment */ envp = buttonup(cmd); if (!envp) return 1; if (r_path) { /* User supplied '-r path' check if it matches actual fullpath */ if (check_rpath(r_path, path) != 0) { return 1; } } /* Change directory if requested */ if (status != -1) status = set_chdir(); /* Set the umask value */ set_umask(); if (debug || it_came_from_cmdline) { debug_print(path, arglist, envp, n_builtin); } if (status == -1) { if (debug || it_came_from_cmdline) { fprintf(stderr, "\n\t(This command would not be executed \ due to previously-reported problem)\n"); } return 1; } if (debug) { fprintf(stderr, "\n\t(Your command is ok, but isn't executed in debug mode.)\n"); return 0; } else if (it_came_from_cmdline) { fprintf(stderr, "\n\t(Your command is ok, but isn't executed because of one or \ more -F/-T/-U/-G/-M flags.)\n"); return 0; } else if (test_mode) { /* Command is ok, but isn't executed because we're in test mode */ return 0; } /* Do checks required by a checkvar=a,b,c... list */ if (check_var_value() != 0) return 1; /* Log an informational message at LOG_INFO priority, not at * the usual error priority. */ { #ifdef HAVE_SYSLOG extern int error_priority; int old_pri = error_priority; error_priority = globalinfo.log.syslog_success; #endif logmsg(cmd, arglist); #ifdef HAVE_SYSLOG error_priority = old_pri; #endif } /* Close the logfile writer, if any: we are done logging, and going * to exec the prog. */ close_writer(); /* If nice increment is positive, we do it here, just before * exec'ing. Negative nice increments were done earlier, before * any change-uid's. */ if (localinfo.nice_incr > 0) if (set_nice_incr() == -1) return 1; /* If print option is set, write message before executing command */ if (localinfo.print) puts(localinfo.print); #ifdef RLIMIT_CORE /* Re-enable core dumps. */ setrlimit(RLIMIT_CORE, &old_core_limit); #endif if (execve(path, arglist, envp) == -1) { #ifdef INTERPRETER_HACK if (errno == ENOEXEC) { /* Open the file, check for "#!interpreter [argument]" */ FILE *fp; char *interp, *argument, line1[1024]; if ((fp = fopen(path, "r")) && /* open the file */ fgets(line1, sizeof(line1), fp) && /* read first line */ strchr(line1, '\n') && /* not too long? */ (strncmp(line1, "#!", 2) == 0) && /* begins "#!"? */ (interp = strtok(line1+2, " \t\n"))) { /* has interpreter? */ argument = strtok(NULL, " \t\n"); /* get opt argument */ /* Adjust the arglist -- recall it has room for this */ if (argument) { arglist -= 2; arglist[0] = arglist[2]; arglist[1] = argument; arglist[2] = path; } else { arglist--; arglist[0] = arglist[1]; arglist[1] = path; } (void) execve(interp, arglist, envp); } } #endif /* If here, we failed to exec the prog. Re-open the logfile we * closed above and write a message. */ if (*globalinfo.log.filename != '\0') { int save_errno = errno; opensuperlog(); errno = save_errno; } (void) Error(1,1, "command `%-.500s': Couldn't exec `%s': ", cmd, path); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Set options; return index of arg that follows options, or -1 on error. * N.B. The flags are assumed to be initialized BY THE CALLER. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int do_options(argc, argv, givehelp, giveversion, verbosity, printvars, o_file, r_path) int argc; char **argv; int *givehelp, *giveversion, *verbosity, *printvars; char **o_file, **r_path; { int iarg; char *mhost, *s, *t; #ifndef HAVE_LOCALTIME char daynum; #endif int takes_optional_superfile; long l; struct passwd *pw; /* NOTE WELL: THE CALLER IS EXPECTED TO HAVE INITIALIZED THE ARGUMENTS * TO THE DESIRED DEFAULT VALUES. It's not repeated here because * this routine isn't called for super invoked via symlink, and * it's misleading to give the impression that the options are always * going to be init'd here. */ *verbosity = HELP_BASIC; /* only matters if *givehelp != 0 */ for (iarg = 1; iarg < argc && argv[iarg][0] == '-'; iarg++) { if (strcmp(argv[iarg], "--") == 0) { /* End of options */ iarg++; break; } if (checkarg(argv[iarg]) != 0) return -1; for (s = &argv[iarg][1]; *s; s++) { takes_optional_superfile = 0; switch (*s) { case 'c': check_syntax = 1; takes_optional_superfile = 1; break; case 'F': it_came_from_cmdline = 1; takes_optional_superfile = 1; break; case 'G': it_came_from_cmdline = 1; if (*(s+1)) { /* User gave -Ggid */ t = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave -G gid */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; t = argv[iarg]; } else { return Error(0, 0, "No gid specified after option -G\n"); } l = findgid(1, localinfo.group); if (l == -1) return Error(0,0,"Invalid gid specified after option -G\n"); else userinfo.orig_gid = l; userinfo.caller.pw_gid = l; break; case 'M': it_came_from_cmdline = 1; if (*(s+1)) { /* User gave -Mmach */ mhost = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave -M mach */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; mhost = argv[iarg]; } else { return Error(0, 0, "No machine specified after option -M\n"); } if (strlen(mhost) > sizeof(userinfo.hostname)-1) Error(0, 1, "Machine name too long -- max allowed is %d\n", sizeof(userinfo.hostname)-1); strcpy(userinfo.hostname, mhost); if (canonicalize_hostname(userinfo.hostname, sizeof(userinfo.hostname)) == -1) return -1; /* also set lowercase version */ strcpy(userinfo.lc_hostname, userinfo.hostname); strtolower(userinfo.lc_hostname); /* also adjust short form to match */ if ((t = strchr(mhost, '.'))) *t = '\0'; if (add_variable("HOST", mhost) == -1) exit(1); break; case 'T': it_came_from_cmdline = 1; if (*(s+1)) { /* User gave -Ttime */ t = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave -T time */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; t = argv[iarg]; } else { return Error(0, 0, "No time specified after option -T\n"); } if (readtime(t, &userinfo.ourtime.min, &userinfo.ourtime.day) != 0) return -1; break; case 'U': it_came_from_cmdline = 1; if (*(s+1)) { /* User gave -Uuid */ t = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave -U uid */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; t = argv[iarg]; } else { return Error(0, 0, "No uid specified after option -U\n"); } pw = getpwentry(1, t); if (!pw) { return -1; } else { /* Act as if we really were the named user */ userinfo.orig_uid = pw->pw_uid; userinfo.orig_gid = pw->pw_gid; userinfo.caller.pw_uid = pw->pw_uid; userinfo.caller.pw_gid = pw->pw_gid; if (!(userinfo.caller.pw_name = strdup(pw->pw_name))) (void) Error(0, 2, "failed to malloc space for passwd struct field.\n"); if (!(userinfo.caller.pw_passwd = strdup(pw->pw_passwd))) (void) Error(0, 2, "failed to malloc space for passwd struct field.\n"); if (!(userinfo.caller.pw_dir = strdup(pw->pw_dir))) (void) Error(0, 2, "failed to malloc space passwd struct field.\n"); fprintf(stderr, "\n\tActing as if uid=%d (%s), gid=%d\n\n", pw->pw_uid, pw->pw_name, pw->pw_gid); } break; case 'r': if (*(s+1)) { /* User gave `-rpath' */ *r_path = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave `-r path' */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; *r_path = argv[iarg]; } else { return Error(0, 0, "No file specified after option -r\n"); } break; case 'o': if (*(s+1)) { /* User gave `-ofile' */ *o_file = s+1; s += strlen(s) - 1; } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave `-o file' */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; *o_file = argv[iarg]; } else { return Error(0, 0, "No file specified after option -o\n"); } /* The `-o file' is always the end of options -- everything * else is an argument to the user's command. * Note that we have to return here (or else "goto") else * we won't break out of the outer for-loop. */ iarg++; return iarg; case 'b': *printvars = 1; break; case 't': test_mode = 1; break; case 'd': debug = 1; break; case 'D': debug = 2; break; case 'S': use_stdin = 1; break; break; case 'V': *giveversion = 1; break; case '?': *givehelp = 1; *verbosity = HELP_USAGE; break; case 'h': *givehelp = 1; *verbosity = HELP_USAGE; break; case 'f': *givehelp = 1; *verbosity = HELP_FACTS; break; case 'H': *givehelp = 1; *verbosity = HELP_FULL; break; default: return Error(0, 0, "Unrecognized option `%c'\n", *s); } /* Check for optional superfile */ if (takes_optional_superfile) { if (*(s+1)) { /* User gave -Xfile (where X is -c/-F) */ superfile = s+1; s += strlen(s) - 1; if (*o_file) { Error(0, 0, "*** Warning: requested file named \ by `-o %s' is overridden by file `%s'", *o_file, superfile); *o_file = NULL; } } else if ((iarg+1 < argc) && argv[iarg+1][0] != '-') { /* User gave -X file */ iarg++; if (checkarg(argv[iarg]) != 0) return -1; superfile = argv[iarg]; if (*o_file) { Error(0, 0, "*** Warning: requested file named \ by `-o %s' is overridden by file `%s'", *o_file, superfile); *o_file = NULL; } } else { /* No file was given. Use the default super file */ } /* Verify that this user has permission to access the file */ if (access(superfile, R_OK) == -1) Error(1, 1, "You can't read `%s': ", superfile); error_srcfile = superfile; if (strcmp(superfile, SUPERFILE) != 0) { /* User has selected a different file. Don't allow * data-driven attacks via a user-supplied superfile: * if our real uid isn't root, reset our effective uid * to the real uid. */ if (getuid() != 0) { setuid(getuid()); fprintf(stderr, "\t** Since you have supplied a super.tab file that isn't the default,\n"); fprintf(stderr, "\t** and your real uid isn't root, we're going to change back to your\n"); fprintf(stderr, "\t** real uid for this test. That protects us against attacks via\n"); fprintf(stderr, "\t** nasty constructions inside user-supplied super.tab files.\n"); fprintf(stderr, "\t** Not that we don't trust you...\n\n"); fprintf(stderr, "\t** Now using: ruid=%d euid=%d **\n\n", getuid(), geteuid()); } } } } } /* Default operation: give help if no args */ if (argc == 1) *givehelp = 1; return iarg; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Print the debug startup lines */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void debug_hello() { char *s = dayname(userinfo.ourtime.day); fprintf(stderr, "\n\tExecuting: %s -%c:\n", prog, (debug < 2) ? 'd' : 'D'); fprintf(stderr, "\tYou are: user=%s gid=%d hostname=%s\n\n", userinfo.caller.pw_name, userinfo.caller.pw_gid, userinfo.hostname); fprintf(stderr, "\tStart time=%d:%02d/%s (hr*60+min=%d daycode=%d)\n", userinfo.ourtime.min/60, userinfo.ourtime.min%60, s, userinfo.ourtime.min, userinfo.ourtime.day); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Print the debug info */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void debug_print(path, arglist, envp, n_builtin) char *path; char **arglist; char **envp; int n_builtin; { char *s, *t, **p, **sp; char *cdpath; int isglobal, j, iarg; ArgRangePat *argpats, *arp; fprintf(stderr, "==============================================================\n"); fprintf(stderr, "\nSuper file is `%s'\n", superfile); fprintf(stderr, "\n\tPermitted times for execution (in reverse input order):\n"); if (globalinfo.timebefore.next != 0 || localinfo.time.next != 0 || globalinfo.timeafter.next != 0) { for (j = 0; j<3; j++) { TimeList *tl; switch (j) { case 0: isglobal=1; tl = globalinfo.timeafter.next; break; case 1: isglobal=0; tl = localinfo.time.next; break; default: isglobal=1; tl = globalinfo.timebefore.next; break; } for ( ; tl ; tl=tl->next) { fprintf(stderr, "\t\t%stime~%d:%02d-%d:%02d/%s (%s)\n", tl->te.invert ? "!" : "", tl->te.begin / 60, tl->te.begin % 60, tl->te.end / 60, tl->te.end % 60, dayname(tl->te.day), isglobal ? "global def" : "per-cmd def"); } } } else { fputs(" (unrestricted)\n", stderr); } fputs("\n", stderr); (void) fprintf(stderr, "\tCommand: <%s>\n", arglist[0]); (void) fprintf(stderr, "\tPath: <%s>\n", path); for (sp=arglist; *sp; sp++) ; (void) fprintf(stderr, "\tArgc: %d\n", (int) (sp - arglist)); (void) fprintf(stderr, "\tMax len, 1 arg: %ld Max len, all args: %ld\n", localinfo.maxlen1arg, localinfo.maxlenargs); for (sp=arglist; *sp; sp++) { iarg = sp - arglist; (void) fprintf(stderr, "\tArgv[%d]: <%s>\n", iarg, *sp); if (iarg > n_builtin) { argpats = (localinfo.argpats.next) ? localinfo.argpats.next : globalinfo.argpats.next; for (arp=ARnext(argpats, iarg-n_builtin); arp; arp = ARnext(arp->next, iarg-n_builtin)) { fprintf(stderr, "\t\tMust match pattern: %s\n", arp->pat); } } } if (localinfo.usr_args[0] < 0) { (void) fprintf(stderr, "\tAny number of user-entered args allowed.\n"); } else if (localinfo.usr_args[0] == localinfo.usr_args[1] && localinfo.usr_args[0] == 0) { (void) fprintf(stderr, "\tNo user-entered args are allowed.\n"); } else if (localinfo.usr_args[0] == localinfo.usr_args[1]) { (void) fprintf(stderr, "\t%d user-entered arg%s required.\n", localinfo.usr_args[0], localinfo.usr_args[0] == 1? " is" : "s are"); } else { (void) fprintf(stderr, "\t%d - %d user-entered args are required.\n", localinfo.usr_args[0], localinfo.usr_args[1]); } (void) fprintf(stderr, "\tCommand executes with nice increment = %d.\n", rcl_nice_incr()); (void) fprintf(stderr, "\tCommand executes with umask set to 0%o.\n", rcl_umask()); cdpath = localinfo.chdir_path ? localinfo.chdir_path : globalinfo.chdir_path; (void) fprintf(stderr, "\tCommand executes with working directory = %s\n", cdpath && *cdpath ? cdpath : ""); (void) fprintf(stderr, "\tMax length of user-supplied env. var's (name+value): "); if (localinfo.maxenvlen < 0) fprintf(stderr, "unrestricted\n"); else fprintf(stderr, "%d chars\n", localinfo.maxenvlen); (void) fprintf(stderr, "\tAdditional permitted user's environment variables:\n"); if (localinfo.env == NULL || localinfo.env[0] == NULL) { fprintf(stderr, "\t\t(none)\n"); } else { for (p=localinfo.env; *p; p++) (void) fprintf(stderr, "\t\t%s\n", *p); } (void) fprintf(stderr, "\tEnvironment variables defined with setenv=var=:\n"); if (localinfo.setenv[0] == NULL && globalinfo.setenv[0] == NULL) { (void) printf("\t\t(none)\n"); } else { for (p=globalinfo.setenv; *p; p++) (void) printf("\t\t%s\n", *p); for (p=localinfo.setenv; *p; p++) (void) printf("\t\t%s\n", *p); } (void) fprintf(stderr, "\tComplete list of environment variables and values:\n"); if (envp[0] == NULL) { (void) printf("\t\t(none)\n"); } else { for (p=envp; *p; p++) (void) printf("\t\t%s\n", *p); } (void) fprintf(stderr, "\tFile descriptors not to be closed:\n\t\t0,1,2"); if (localinfo.fdlist) (void) fprintf(stderr, ",%s", localinfo.fdlist); (void) fprintf(stderr, "\n\n\tID's:\treal effective\n"); (void) fprintf(stderr, "\tuid\t%d\t%d\n", getuid(), geteuid()); (void) fprintf(stderr, "\tgid\t%d\t%d\n", getgid(), getegid()); #ifdef HAVE_GETGROUPS { GETGROUPS_T groups[NGROUPS_MAX]; int ng = Getgroups(NGROUPS_MAX, groups); (void) fprintf(stderr, "\tSupplementary groups list:\n\t\t"); if (ng == 0) { (void) fprintf(stderr, "(none)"); } else { for (j=0; jpw_name; (void) construct_user_superfile(user); if (stat(superfile, &stu) == -1) { Error(1, 1, "Can't stat file `%s': ", superfile); } if (stu.st_dev != sto.st_dev || stu.st_ino != sto.st_ino) { Error(0, 1, "The file `%s' points to a file owned by `%s', \ but it isn't the expected file `%s'\n", file_or_user, pass->pw_name, superfile); } } else { /* Have username */ user = file_or_user; pass = construct_user_superfile(user); } error_srcfile = superfile; if (initgroups(user, pass->pw_gid) == -1) Error(1, 1, "Can't set groups to those of user %s, group %d:\n\t\ Command <%s:%-.500s>; uid=%d, euid=%d: ", user, pass->pw_gid, user, cmd, getuid(), geteuid()); if ((i=setgid(pass->pw_gid)) == -1) { Error(1, 1, "Can't set gid to %d: ", pass->pw_gid); } else if ((j=getgid()) != pass->pw_gid) { Error(1, 1, "setgid(gid=%d) returned %d, but getgid() returned %d!", pass->pw_gid, i, j); } if ((i=setuid(pass->pw_uid)) == -1) { Error(1, 1, "Can't set uid to %d: ", pass->pw_uid); } else if ((j=getuid()) != pass->pw_uid) { Error(0, 1, "setuid(uid=%d) returned %d, but getuid() returned %d!", pass->pw_uid, i, j); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Construct's a user's .supertab file, and place it into the superfile. * Return a pointer to the passwd struct for the user. * Exit if there are any errors. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct passwd * construct_user_superfile(user) char *user; { struct passwd *pass; char *s; superfile[0] = '\0'; if (!(pass = getpwnam(user))) Error(0, 1, "No such user as `%s'\n", user); if (pass->pw_dir[0] == '\0') Error(0, 1, "No home directory for user `%s'?!\n", user); if ((strlen(pass->pw_dir) + strlen(PERUSER_SUPERFILE) + 1) > sizeof(superfile_writable)) Error(0, 1, "User %s's +<%s> pathlen exceeds %d?!\n", user, PERUSER_SUPERFILE, sizeof(superfile_writable)); (void) strcpy(superfile, pass->pw_dir); s = superfile + strlen(superfile) - 1; if (*s != '/') *(++s) = '/'; strcpy(s+1, PERUSER_SUPERFILE); return pass; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Log a super call -- If "args" isn't a null ptr, it's printed inside * parentheses, with whitespace separating the arguments. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void logmsg(cmd, args) char *cmd; char **args; { char *ec, *logbuf, **ap; int e; int loglen = strlen(cmd) + 4; /* Determine buffer length needed to hold all arguments */ if (args) for (ap = args; *ap; ap++) loglen += strlen(*ap) + 1; if (!(logbuf = malloc(loglen))) (void) Error(0, 2, "failed to malloc space for logging command\n"); if (args) { sprintf(logbuf, "%s (", cmd); for (ap = args; *ap; ) { strcat(logbuf, *ap++); strcat(logbuf, " "); } logbuf[loglen-3] = ')'; logbuf[loglen-2] = '\n'; logbuf[loglen-1] = '\0'; } else { sprintf(logbuf, "%s\n", cmd); } /* Log the message using Error(), but * - make sure msg doesn't go to stderr; * - if not mail_success, don't let msg go to error_command, either. */ e = error_stderr; ec = error_command; if (localinfo.mail_success == 0 || (localinfo.mail_success == -1 && globalinfo.mail_success==0)) error_command = NULL; error_stderr = 0; Error(0, 0, "%s", logbuf); error_stderr = e; error_command = ec; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get the arglist for the command, and null-terminate cmd if nec */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char ** newargs(path_plus, argv, n_builtin) char *path_plus; /* string = "path [options]". Null-terminate and put * options into front of arglist. */ char **argv; /* rest of arguments for arglist (placed after * the options from the path_plus string). */ int *n_builtin; /* returned w/ number of args in path_plus */ { int nuser, nalloc, iarg, nargs, nxtra; char **arglist, **ap; char *s; ArgRangePat *argpats, *arp; /* Count user-entered args. */ for (ap = argv; *ap; ) ap++; /* Check number of user-entered args is ok. */ nargs = ap - argv - 1; if (localinfo.usr_args[0] >= 0) { if (nargs < localinfo.usr_args[0] || nargs > localinfo.usr_args[1]) { if (localinfo.usr_args[0] == localinfo.usr_args[1] && localinfo.usr_args[0] == 0) (void) Error(0, 2, "you may not give any arguments to `%-.500s'\n", argv[0]); else if (localinfo.usr_args[0] == localinfo.usr_args[1]) (void) Error(0, 2, "You must give %d argument%s to `%-.500s'\n", localinfo.usr_args[0], localinfo.usr_args[0] == 1 ? "" : "s", argv[0]); else (void) Error(0, 2, "You must give %d - %d arguments to `%-.500s'\n", localinfo.usr_args[0], localinfo.usr_args[1], argv[0]); } } /* Check that each user-entered argument matches its pattern, if given */ for (iarg = 1; iarg <= nargs; iarg++) { argpats = (localinfo.argpats.next) ? localinfo.argpats.next : globalinfo.argpats.next; for (arp=ARnext(argpats, iarg); arp; arp = ARnext(arp->next, iarg)) { if (arp->pat && match_pattern(0, 1, argv[iarg], arp->pat) != 1) (void) Error(0, 2, "Your argument #%d <%-.500s> must match pattern <%s>\n", iarg, argv[iarg], arp->pat); } } /* Start off with space for user-entered args + 100 args in super.tab. * We'll re-alloc if necessary. */ nuser = (ap - argv) + 3; nalloc = nuser + 100; arglist = (char **) malloc(sizeof(char *) * nalloc); if (!arglist) (void) Error(1, 2, "failed to malloc space for %d ptrs: ", nalloc); /* Leave room for two extra args at front, in case we are handling * the "#! interpreter [opt]" file for OS's that don't support it. */ arglist += 2; /* Copy the extra args from super.tab to the arglist, * re-allocing the arglist as the number of args grows. * First set up arglist[0]: depending on the value of localinfo.argv0, * either copy argv[0] to the arglist, or use the super.tab-supplied value. */ s=strqtokS(path_plus, SEP, QM, "", 1); /* FullPath */ if (localinfo.argv0 && (strcmp(localinfo.argv0, "") == 0)) { /* Use the actual path */ arglist[0] = s; argv++; } else if (localinfo.argv0) { /* Use the path named in the argv0 option in the super.tab file */ arglist[0] = localinfo.argv0; argv++; } else { /* Use the name by which this command was invoked. */ arglist[0] = *argv++; } for(nxtra=0, ap = &arglist[1], s=strqtokS(NULL, SEP, NULL, NULL, 1); s; s = strqtokS(NULL, SEP, NULL, NULL, 1)) { nxtra++; if (nuser + nxtra >= nalloc) { char **newarglist; nalloc *= 2; newarglist = (char **) realloc((void *) arglist, nalloc); if (!newarglist) (void) Error(1, 2, "failed to realloc space for %d ptrs: ", nalloc); ap = newarglist + (ap - arglist); arglist = newarglist; } *ap++ = s; } /* Now add the user-supplied args at the end */ *n_builtin = ap - arglist - 1; while (*argv) *ap++ = *argv++; *ap = NULL; return arglist; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get a safe environment for execution of the command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char ** buttonup(cmd) char *cmd; /* name of command being started */ { /* Depending on the ability to close-on-exec, either: * close all descriptors save 0,1,2 and the super.tab-specified fd list; * or mark them close-on-exec. * Resets all signal-handling to SIG_DFL. * Discards all env. variables save for TERM, LINES, COLUMNS, and * any variables listed in the super.tab file. * Don't allow TERM to have any but [-/:+._a-zA-Z0-9]. * Don't allow LINES, COLUMNS to have anything but digits. * To these are added reasonable values for IFS, PATH, USER, HOME. * USER and HOME refer to the uid under which the command is executed; * LOGNAME is set to the same as USER, and SUPERCMD is set to cmd. * ORIG_USER, ORIG_LOGNAME, and ORIG_HOME refer to the user who invoked * super (these are values computed by super, not passed in by the caller). * CALLER and CALLER_HOME are set to the same as ORIG_USER and ORIG_HOME, * respectively. * Returned: * NULL on error; * otherwise, a pointer to the modified environment list. */ int i, j, n, fd, maxfd; char **p, *s; int fd_log; static char *env[200]; static char User[100]; /* USER */ static char Logname[100]; /* LOGNAME (same as USER) */ static char Home[MAXPATHLEN+5]; /* HOME */ static char OrigUser[100]; /* ORIG_USER */ static char Caller[100]; /* CALLER (same as ORIG_USER) */ static char OrigLogname[100]; /* ORIG_LOGNAME */ static char OrigHome[MAXPATHLEN+9]; /* ORIG_HOME */ static char CallerHome[MAXPATHLEN+12]; /* CALLER_HOME (same as ORIG_HOME) */ static char SafePath[1206]; /* SAFE_PATH */ static char Cmd[1205]; /* SUPERCMD */ #ifndef signal /* If signal() isn't a macro, then declare it explicitly -- it's too * much of a mess to figure out whether a given operating system * has declared it or not. (Any __STDC__ system should be declaring * it, but there are several OS's that seem to mess this up.) */ SIGNAL_T (*signal())(); #endif /* don't close logfile yet */ fd_log = globalinfo.log.fp ? fileno(globalinfo.log.fp) : -1; maxfd = MAXFD; #ifdef HAVE_FCNTL_H #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif for (fd=3; fd <= maxfd; fd++) if (localinfo.fd[fd] == 0 && fd != fd_log) (void) fcntl(fd, F_SETFD, FD_CLOEXEC); #else #ifdef HAVE_IOCTL_FIOCLEX for (fd=3; fd <= maxfd; fd++) if (localinfo.fd[fd] == 0 && fd != fd_log) (void) ioctl(fd, FIOCLEX, NULL); #else for (fd=3; fd <= maxfd; fd++) if (localinfo.fd[fd] == 0 && fd != fd_log) (void) close(fd); #endif #endif for (i=0; i sizeof(SafePath)-6) { Error(0, 0, "%t\n\tRidiculously long SAFE_PATH.\n"); return NULL; } /* I've screwed up SAFE_PATH so often (and so have others) that I'm gonna * put this check into the code... */ if (strncmp(SAFE_PATH, "PATH=", 5) == 0) (void) strcpy(SafePath, SAFE_PATH); else (void) sprintf(SafePath, "PATH=%s", SAFE_PATH); if (strlen(cmd) > sizeof(Cmd)-5) { Error(0, 0, "%t\n\tRidiculously long original string.\n"); return NULL; } (void) sprintf(Cmd, "SUPERCMD=%s", cmd); (void) strcpy(Home, "HOME="); (void) getlogdir(s, Home+5); (void) sprintf(OrigHome, "ORIG_HOME=%s", userinfo.caller.pw_dir); (void) sprintf(CallerHome, "CALLER_HOME=%s", userinfo.caller.pw_dir); i = 0; env[i] = Getenv("TERM"); if (env[i] && checkenv("TERM", env[i]+5, "^[-/:+._a-zA-Z0-9]*$") != -1) i++; env[i] = Getenv("LINES"); if (env[i] && checkenv("LINES", env[i]+6, "^[0-9]*$") != -1) i++; env[i] = Getenv("COLUMNS"); if (env[i] && checkenv("COLUMNS", env[i]+8, "^[0-9]*$") != -1) i++; env[i++] = SAFE_IFS; env[i++] = SafePath; env[i++] = User; env[i++] = Logname; env[i++] = Home; env[i++] = Cmd; env[i++] = OrigUser; env[i++] = Caller; env[i++] = OrigLogname; env[i++] = OrigHome; env[i++] = CallerHome; /* Now add the extra environment variables requested in the * super.tab file. Make a linear search each time, so that we * don't define the same name twice. Yes, this will be extraordinarily * inefficient if there are many variables, but in real life, there * aren't too many to do this... */ for (p=localinfo.env; p && *p && i < NELEM(env)-1; p++) { n = strlen(*p); for (j=0; j < i; j++) { if (strncmp(env[j], *p, n) == 0 && env[j][n] == '=') { /* name is already in use, at index j. */ break; } } s = Getenv(*p); if (s) { env[j] = s; if (strlen(env[j])+1 > localinfo.maxenvlen) { Error(0, 0, "%t\n\tDefinition for envvar %s exceeds \ maxenvlen=%d.\n", *p, localinfo.maxenvlen); return NULL; } if (j == i) { i++; } } } for (p = globalinfo.setenv; *p && i < NELEM(env)-1 ; ) { n = strchr(*p, '=') + 1 - *p; for (j=0; j < i; j++) { if (strncmp(env[j], *p, n) == 0) { /* name is already in use, at index j. */ break; } } env[j] = *p++; if (j == i) { i++; } } for (p = localinfo.setenv; *p && i < NELEM(env)-1 ; ) { n = strchr(*p, '=') + 1 - *p; for (j=0; j < i; j++) { if (strncmp(env[j], *p, n) == 0) { /* name is already in use, at index j. */ break; } } env[j] = *p++; if (j == i) { i++; } } if (i >= NELEM(env)-1) { Error(0, 0, "%t\n\tAsked to save too many \ environment variables (max allowed %d).\n", NELEM(env)-1); return NULL; } env[i] = (char *) NULL; return &env[0]; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check that all arguments are within the permissible limits. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_arglistlen(argv) char **argv; { /* Check that all arguments meet the length restrictions. * A length restriction < 0 means unlimited size. * Returns 0 if all ok; else prints error message and returns 1. */ long totlen; long l; char **p; if (localinfo.maxlen1arg < 0 && localinfo.maxlenargs < 0) return 0; for (totlen = 0, p = argv; *p; p++) { l = (long) strlen(*p) + 1; totlen += l; if (localinfo.maxlen1arg >= 0 && l > localinfo.maxlen1arg) return Error(0, 0, "Maximum length of each argument = %d chars\n", localinfo.maxlen1arg); } if (localinfo.maxlenargs >= 0 && totlen > localinfo.maxlenargs) return Error(0, 0, "Maximum total length of arguments = %d chars\n", localinfo.maxlenargs); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Take various system information (from sysinfo(), uname(), etc) * and turn it into variables. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void add_builtin_variables() { char *s, buf[1000]; if (add_variable("HOSTNAME", userinfo.hostname) == -1) exit(1); /* Add an unqualified version of HOSTNAME */ strcpy(buf, userinfo.hostname); if ((s=strchr(buf, '.'))) { *s = '\0'; } if (add_variable("HOST", buf) == -1) exit(1); if (add_sysinfo_variables() == -1) /* Makes empty def'ns if no sysinfo() */ exit(1); if (add_uname_variables() == -1) /* Makes empty def'ns if no uname() */ exit(1); #ifdef HAVE_GETDOMAINNAME if (getdomainname(buf, sizeof(buf)) != -1) { if (add_variable("NIS_DOMAIN", buf) == -1) exit(1); } #else if (add_variable("NIS_DOMAIN", "") == -1) exit(1); #endif } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Initialize the globalinfo struct. Only call this once; thereafter, use * option_global_clear_settings(). Note that very little work is done in * this routine, because almost all fields are properly initialized in the * structure declaration/initialization statement. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void init_globalinfo() { int i; init_umask(1); for (i=0; i<=MAXSETENV; i++) globalinfo.setenv[i]=NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Initialize the localinfo struct. Only call this once; thereafter, use * option_local_clear_settings(). */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void init_localinfo() { int i; localinfo.info = localinfo.chdir_path = localinfo.die = localinfo.print = NULL; localinfo.env = NULL; for (i=0; i<=MAXSETENV; i++) localinfo.setenv[i]=NULL; localinfo.fdlist = NULL; localinfo.mask = -1; localinfo.maxenvlen = globalinfo.maxenvlen; localinfo.maxlen1arg = globalinfo.maxlen1arg; localinfo.maxlenargs = globalinfo.maxlenargs; localinfo.file_uid = UID_NOTSET; localinfo.file_gid = GID_NOTSET; localinfo.nice_incr = globalinfo.nice_incr; localinfo.checkvar = NULL; /* Don't init to global ngroups, because we need to be able to tell * later on whether local groups=xxx or global groups=xxx was used. */ localinfo.ngroups = GROUPS_NOTSET; localinfo.groups_added = 0; localinfo.argpats.pat = NULL; localinfo.argpats.arg1 = -1; localinfo.argpats.arg2 = -1; localinfo.argpats.next = NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Look up some of the most basic user information. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int init_userinfo() { struct passwd *usrpw; userinfo.ourtime.start = time(NULL); #ifdef HAVE_LOCALTIME { struct tm *tm_p = localtime(&userinfo.ourtime.start); userinfo.ourtime.min = tm_p->tm_hour*60 + tm_p->tm_min; userinfo.ourtime.day = tm_p->tm_wday; } #else userinfo.ourtime.min = (userinfo.ourtime.start/60) % (24*60); userinfo.ourtime.day = daynum(userinfo.ourtime.start); #endif /* * We want the hostname (fully-qualified if possible), as well as a * lower-cased version (to try and deal with mixed case hostnames). */ if (get_canonical_hostname(userinfo.hostname, sizeof(userinfo.hostname)) == -1) return -1; strcpy(userinfo.lc_hostname, userinfo.hostname); strtolower(userinfo.lc_hostname); userinfo.orig_uid = getuid(); userinfo.orig_gid = getgid(); usrpw = getpwuid(userinfo.orig_uid); if (!usrpw) return Error(0, 0, "Couldn't get your password entry."); memcpy(&userinfo.caller, (void *) usrpw, sizeof(struct passwd)); if (add_variable("CALLER", userinfo.caller.pw_name) == -1) return -1; if (add_variable("CALLER_HOME", userinfo.caller.pw_dir) == -1) return -1; /* Since the string fields that we need are overwritten by later * calls to getpwxxx(), make private copies: */ if (!(userinfo.caller.pw_name = strdup(usrpw->pw_name))) (void) Error(0, 2, "failed to malloc space for passwd struct field.\n"); if (!(userinfo.caller.pw_passwd = strdup(usrpw->pw_passwd))) (void) Error(0, 2, "failed to malloc space for passwd struct field.\n"); if (!(userinfo.caller.pw_dir = strdup(usrpw->pw_dir))) (void) Error(0, 2, "failed to malloc space passwd struct field.\n"); error_user = userinfo.caller.pw_name; userinfo.orig_mask = umask(022); /* Get orig umask, and set to 022 */ (void) umask(userinfo.orig_mask); /* ...so restore curr val */ return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Store the desired umask; set the actual umask; recall the desired umask */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void init_umask(is_global) int is_global; { if (is_global) { globalinfo.mask = userinfo.orig_mask; } else { localinfo.mask = -1; } } void store_umask(mask, is_global) int mask; int is_global; { if (is_global) globalinfo.mask = mask; else localinfo.mask = mask; } void set_umask() { umask( (localinfo.mask >= 0) ? localinfo.mask : globalinfo.mask); } int rcl_umask() { return (localinfo.mask >= 0) ? localinfo.mask : globalinfo.mask; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check if -r path matches actual path. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_rpath(r_path, xpath) char *r_path; char *xpath; { struct stat r_stat, xstat; if (stat(r_path, &r_stat) == -1) { return Error(1, 0, "Caller used `-r %-.500s', but stat of that \ path failed: ", r_path); } if (stat(xpath, &xstat) == -1) { return Error(1, 0, "Caller used `-r %-.500s'; the super.tab file \ gave path `%s', and the stat of the latter file failed: ", r_path, xpath); } if (r_stat.st_dev != xstat.st_dev || r_stat.st_ino != xstat.st_ino) { return Error(0, 0, "File sanity-check mismatch: \ caller used `-r %-.500s' (dev=%ld,inode=%ld); the super.tab file \ gave path `%s' (dev=%ld,inode=%ld): these are not the same file.\n", r_path, (long) r_stat.st_dev, (long) r_stat.st_ino, xpath, (long) xstat.st_dev, (long) xstat.st_ino); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Change directory, if required */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int set_chdir() { char *path = localinfo.chdir_path ? localinfo.chdir_path : globalinfo.chdir_path; if (!path || !*path) return 0; if (chdir(path) == -1) return Error(1, 0, "Failed to change directory to ``%s'': ", path); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Make sure that stdin, stdout, stderr are all open; die * if we cannot do so. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void check_stdio() { struct stat stat; if (fstat(0, &stat) == -1 && !freopen("/dev/null", "r", stdin)) { exit(1); } if (fstat(1, &stat) == -1 && !freopen("/dev/null", "w", stdout)) { exit(1); } if (fstat(2, &stat) == -1 && !freopen("/dev/null", "w", stderr)) { exit(1); } #ifdef HAVE_FILENO if (fileno(stdin) != 0) { exit(1); } if (fileno(stdout) != 1) { exit(1); } if (fileno(stderr) != 2) { exit(1); } #endif } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Store/set/recall niceness */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void store_nice_incr(nice_incr, is_global) int nice_incr; int is_global; { if (is_global) globalinfo.nice_incr = nice_incr; else localinfo.nice_incr = nice_incr; } int set_nice_incr() { if (localinfo.nice_incr && nice(localinfo.nice_incr) == -1) return Error(1, 0, "Failed to apply a ``nice'' increment = %d: ", localinfo.nice_incr); return 0; } int rcl_nice_incr() { return localinfo.nice_incr; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Frees all elements in a SimpleList, except the one it's given. * The "next" field of that element is set NULL. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void free_SimpleList(sl) SimpleList *sl; { SimpleList *slp; if (!sl || !sl->next) return; slp = sl->next; sl->next = NULL; for (sl=sl->next ; sl; sl = slp) { slp = sl->next; free(sl->pat); free(sl); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Frees all elements in a Simple2List, except the one it's given. * The "next" field of that element is set NULL. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void free_Simple2List(sl) Simple2List *sl; { Simple2List *slp; if (!sl || !sl->next) return; slp = sl->next; sl->next = NULL; for (sl=sl->next ; sl; sl = slp) { slp = sl->next; free(sl->pat); free(sl); } } super-3.30.0/pam_misc.h0000444000104100002640000000410410732537455013216 0ustar willspg/* $Id: pam_misc.h,v 1.1 2000/09/12 20:19:41 will Exp $ */ /* $Log: pam_misc.h,v $ * Revision 1.1 2000/09/12 20:19:41 will * Initial revision * * Revision 1.1.1.1 1998/07/12 05:17:15 morgan * Linux PAM sources pre-0.66 * * Revision 1.3 1997/01/04 20:15:52 morgan * added timeout to misc_conv * * Revision 1.2 1996/12/01 03:27:00 morgan * add env prototypes * * Revision 1.1 1996/07/06 19:31:38 morgan * Initial revision * * Revision 1.1 1996/07/06 19:16:30 morgan * Initial revision */ #ifndef __PAMMISC_H #define __PAMMISC_H #include /* functions defined in pam_misc.* libraries */ extern int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr); #include extern time_t pam_misc_conv_warn_time; /* time that we should warn user */ extern time_t pam_misc_conv_die_time; /* cut-off time for input */ extern const char *pam_misc_conv_warn_line; /* warning notice */ extern const char *pam_misc_conv_die_line; /* cut-off remark */ extern int pam_misc_conv_died; /* 1 = cut-off time reached (0 not) */ extern int (*pam_binary_handler_fn)(const void *send, void **receive); /* * Environment helper functions */ /* transcribe given environment (to pam) */ extern int pam_misc_paste_env(pam_handle_t *pamh , const char * const * user_env); /* char **pam_misc_copy_env(pam_handle_t *pamh); This is no longer defined as a prototype because the X/Open XSSO spec makes it clear that PAM's pam_getenvlist() does exactly what this was needed for. A wrapper is still provided in the pam_misc library - so that legacy applications will still work. But _BE_WARNED_ it will disappear by the release of libpam 1.0 . */ /* delete environment as obtained from (pam_getenvlist) */ extern char **pam_misc_drop_env(char **env); /* provide something like the POSIX setenv function for the (Linux-)PAM * environment. */ extern int pam_misc_setenv(pam_handle_t *pamh, const char *name , const char *value, int readonly); #endif super-3.30.0/s_re_fail.c0000444000104100002640000000071210732537455013345 0ustar willspgstatic const char rcsid[] = "$Id: s_re_fail.c,v 1.6 2004/04/30 17:00:58 will Exp $"; #ifdef vms #include stdio #else #include #endif #include "config.h" #ifdef HAVE_STDLIB_H #include #endif /* * s_re_fail: * internal error handler for s_re_exec. * * should probably do something like a * longjump to recover gracefully. */ void s_re_fail(s, c) char *s; char c; { (void) fprintf(stderr, "%s [opcode %o]\n", s, c); exit(1); } super-3.30.0/misc_conv.c0000444000104100002640000002264710732537455013415 0ustar willspg/* * $Id: misc_conv.c,v 1.1 2000/09/12 20:19:41 will Exp $ * * A generic conversation function for text based applications * * Written by Andrew Morgan */ #ifdef linux #define _GNU_SOURCE #include #endif #include #include #include #include #include #include #include #include #include #include "pam_misc.h" #ifdef DEBUG #define D(x) printf x #else #define D(x) #endif #define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */ #define CONV_ECHO_ON 1 /* types of echo state */ #define CONV_ECHO_OFF 0 /* * external timeout definitions - these can be overriden by the * application. */ time_t pam_misc_conv_warn_time = 0; /* time when we warn */ time_t pam_misc_conv_die_time = 0; /* time when we timeout */ const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n"; const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n"; int pam_misc_conv_died=0; /* application can probe this for timeout */ static void pam_overwrite(char *str) { memset(str, ' ', strlen(str)); } static char * x_strdup(char *s) { return ((s) ? strdup(s) : NULL); } static void pam_misc_conv_delete_binary(void **delete_me) { if (delete_me && *delete_me) { unsigned char *packet = *(unsigned char **)delete_me; int length; length = (packet[0]<<24)+(packet[1]<<16)+(packet[2]<<8)+packet[3]; memset(packet, 0, length); free(packet); *delete_me = packet = NULL; } } /* These function pointers are for application specific binary conversations. One or both of the arguments to the first function must be non-NULL. The first function must return PAM_SUCCESS or PAM_CONV_ERR. If input is non-NULL, a response is expected, this response should be malloc()'d and will eventually be free()'d by the calling module. The structure of this malloc()'d response is as follows: { int length, char data[length] } For convenience, the pointer used by the two function pointer prototypes is 'void *'. The ...free() fn pointer is used to discard a binary message that is not of the default form. It should be explicitly overwritten when using some other convention for the structure of a binary prompt (not recommended). */ int (*pam_binary_handler_fn)(const void *send, void **receive) = NULL; void (*pam_binary_handler_free)(void **packet_p) = pam_misc_conv_delete_binary; /* the following code is used to get text input */ volatile static int expired=0; /* return to the previous signal handling */ static void reset_alarm(struct sigaction *o_ptr) { (void) alarm(0); /* stop alarm clock - if still ticking */ (void) sigaction(SIGALRM, o_ptr, NULL); } /* this is where we intercept the alarm signal */ static void time_is_up(int ignore) { expired = 1; } /* set the new alarm to hit the time_is_up() function */ static int set_alarm(int delay, struct sigaction *o_ptr) { struct sigaction new_sig; sigemptyset(&new_sig.sa_mask); new_sig.sa_flags = 0; new_sig.sa_handler = time_is_up; if ( sigaction(SIGALRM, &new_sig, o_ptr) ) { return 1; /* setting signal failed */ } if ( alarm(delay) ) { (void) sigaction(SIGALRM, o_ptr, NULL); return 1; /* failed to set alarm */ } return 0; /* all seems to have worked */ } /* return the number of seconds to next alarm. 0 = no delay, -1 = expired */ static int get_delay(void) { time_t now; expired = 0; /* reset flag */ (void) time(&now); /* has the quit time past? */ if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) { fprintf(stderr,"%s",pam_misc_conv_die_line); pam_misc_conv_died = 1; /* note we do not reset the die_time */ return -1; /* time is up */ } /* has the warning time past? */ if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) { fprintf(stderr, "%s", pam_misc_conv_warn_line); pam_misc_conv_warn_time = 0; /* reset warn_time */ /* indicate remaining delay - if any */ return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now:0 ); } /* indicate possible warning delay */ if (pam_misc_conv_warn_time) return (pam_misc_conv_warn_time - now); else if (pam_misc_conv_die_time) return (pam_misc_conv_die_time - now); else return 0; } /* read a line of input string, giving prompt when appropriate */ static char *read_string(int echo, const char *prompt) { struct termios term_before, term_tmp; char line[INPUTSIZE]; struct sigaction old_sig; int delay, nc, have_term=0; D(("called with echo='%s', prompt='%s'.", echo ? "ON":"OFF" , prompt)); if (isatty(STDIN_FILENO)) { /* terminal state */ /* is a terminal so record settings and flush it */ if ( tcgetattr(STDIN_FILENO, &term_before) != 0 ) { D(("")); return NULL; } memcpy(&term_tmp, &term_before, sizeof(term_tmp)); if (!echo) { term_tmp.c_lflag &= ~(ECHO); } have_term = 1; } else if (!echo) { D(("")); } /* set up the signal handling */ delay = get_delay(); /* reading the line */ while (delay >= 0) { fprintf(stderr, "%s", prompt); /* this may, or may not set echo off -- drop pending input */ if (have_term) (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp); if ( delay > 0 && set_alarm(delay, &old_sig) ) { D(("")); break; } else { nc = read(STDIN_FILENO, line, INPUTSIZE-1); if (have_term) { (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); if (!echo || expired) /* do we need a newline? */ fprintf(stderr,"\n"); } if ( delay > 0 ) { reset_alarm(&old_sig); } if (expired) { delay = get_delay(); } else if (nc > 0) { /* we got some user input */ char *input; if (nc > 0 && line[nc-1] == '\n') { /* terminate */ line[--nc] = '\0'; } else { line[nc] = '\0'; } input = x_strdup(line); pam_overwrite(line); return input; /* return malloc()ed string */ } else if (nc == 0) { /* Ctrl-D */ D(("user did not want to type anything")); fprintf(stderr, "\n"); break; } } } /* getting here implies that the timer expired */ if (have_term) (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); memset(line, 0, INPUTSIZE); /* clean up */ return NULL; } /* end of read_string functions */ int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr) { int count=0; struct pam_response *reply; if (num_msg <= 0) return PAM_CONV_ERR; D(("allocating empty response structure array.")); reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); if (reply == NULL) { D(("no memory for responses")); return PAM_CONV_ERR; } D(("entering conversation function.")); for (count=0; count < num_msg; ++count) { char *string=NULL; switch (msgm[count]->msg_style) { case PAM_PROMPT_ECHO_OFF: string = read_string(CONV_ECHO_OFF,msgm[count]->msg); if (string == NULL) { goto failed_conversation; } break; case PAM_PROMPT_ECHO_ON: string = read_string(CONV_ECHO_ON,msgm[count]->msg); if (string == NULL) { goto failed_conversation; } break; case PAM_ERROR_MSG: if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) { goto failed_conversation; } break; case PAM_TEXT_INFO: if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) { goto failed_conversation; } break; #ifdef PAM_BINARY_PROMPT case PAM_BINARY_PROMPT: { void *pack_out=NULL; const void *pack_in = msgm[count]->msg; if (!pam_binary_handler_fn || pam_binary_handler_fn(pack_in, &pack_out) != PAM_SUCCESS || pack_out == NULL) { goto failed_conversation; } string = (char *) pack_out; pack_out = NULL; break; } #endif default: fprintf(stderr, "erroneous conversation (%d)\n" ,msgm[count]->msg_style); goto failed_conversation; } if (string) { /* must add to reply array */ /* add string to list of responses */ reply[count].resp_retcode = 0; reply[count].resp = string; string = NULL; } } /* New (0.59+) behavior is to always have a reply - this is compatable with the X/Open (March 1997) spec. */ *response = reply; reply = NULL; return PAM_SUCCESS; failed_conversation: if (reply) { for (count=0; countmsg_style) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: pam_overwrite(reply[count].resp); free(reply[count].resp); break; #ifdef PAM_BINARY_PROMPT case PAM_BINARY_PROMPT: pam_binary_handler_free((void **) &reply[count].resp); break; #endif case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* should not actually be able to get here... */ free(reply[count].resp); } reply[count].resp = NULL; } /* forget reply too */ free(reply); reply = NULL; } return PAM_CONV_ERR; } super-3.30.0/INSTALL0000444000104100002640000001531410732537455012313 0ustar willspgBasic Installation ================== The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create - a `Makefile' in each directory of the package; - the `config.h' files containing system-dependent definitions; - a shell script `config.status' that you can run in the future to recreate the current configuration; - the man pages super.1 and super.5; - a file `config.cache' that saves the results of its tests to speed up reconfiguring; - and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given at the bottom of the `README' file, so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile super is: 1. `cd' to the directory containing the super's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. Inspect the generated file `Makefile', and verify that its configuration is satisfactory. If you have to adjust the makefile, please send a description of your changes to the address given at the end of the README file. 2. Type `make' to compile the package. 3. Type `make install' to install the programs and any data files and documentation. 4. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Common Configure Options for Super ================================== By default, super is built so that the package's files are installed in /usr/local/bin, /usr/local/man, etc. You can control this with options to configure as follows: o PREFIX (override with --prefix=DIR) is set to /usr/local; o PREFIX/bin (override with --exec-prefix=DIR) holds the "super" and "setuid" binaries; o PREFIX/man (override with --mandir=DIR) holds the man pages; o PREFIX/etc (override with --sysconfdir=DIR) holds the configuration file that super reads at runtime; o PREFIX/var (override with --localstatedir=DIR) holds the timestamp directory that super uses to keep track of when users last told it their passwords. Additionally, the rsyslog feature is enabled by default (see the man page, super.5, for details); you can override this with --disable-rsyslog. Run `configure --help' for more information. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. super-3.30.0/checks.c0000444000104100002640000016266210732537455012677 0ustar willspgstatic const char rcsid[] = "$Id: checks.c,v 1.190 2007/03/07 15:04:41 will Exp $"; /* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "super.h" #include "version.h" #include "s_hsearch.h" #define MAX_KEYLEN 1000 /* Large enough? */ static char keybuf[MAX_KEYLEN]; static char *YES = "Y"; static char *NO = "N"; #ifdef HAVE_INNETGR /* #define netgrp_u_compare(pattern, user) innetgr(pattern, NULL, user, NULL) #define netgrp_h_compare(pattern, host) innetgr(pattern, host, NULL, NULL) */ static int created_user_table = 0; static netgrp_u_compare(pattern, user) char *pattern; char *user; { ENTRY item, *found_item; int passed, klen; if (!created_user_table) { if (!s_hcreate(HS_USER, 1000)) { return Error(0, 0, "%tCouldn't allocate hash table for user ng processing\n"); } created_user_table = 1; } /* Catenate pattern and user for the key such that * "abc" + "de" is not the same as "ab" + "cde". * Use "\n", as that will have been stripped from input before we get here. */ if (snprintf(keybuf, MAX_KEYLEN, "%s\n%s", pattern, user) >= MAX_KEYLEN) { return Error(0, 0, "%tpattern and user too large for user ng processing\n"); } item.key = keybuf; if (found_item = s_hsearch(HS_USER, item, FIND)) { return found_item->data == YES? 1: 0; } passed = innetgr(pattern, NULL, user, NULL); /* Have to make this key a permanent copy for the hash */ klen = strlen(keybuf); item.key = malloc(klen + 1); if (!item.key) { return Error(0, 0, "%tout of memory for user ng processing\n"); } strcpy(item.key, keybuf); item.data = passed? YES: NO; if (!s_hsearch(HS_USER, item, ENTER)) { return Error(0, 0, "%thash set failure for user ng processing\n"); } return passed; } static int created_host_table = 0; static netgrp_h_compare(pattern, host) char *pattern; char *host; { ENTRY item, *found_item; int passed, klen; if (!created_host_table) { if (!s_hcreate(HS_HOST, 1000)) { return Error(0, 0, "%tCouldn't allocate hash table for host ng processing\n"); } created_host_table = 1; } /* Catenate pattern and user for the key such that * "abc" + "de" is not the same as "ab" + "cde". * Use "\n", as that will have been stripped from input before we get here. */ if (snprintf(keybuf, MAX_KEYLEN, "%s\n%s", pattern, host) >= MAX_KEYLEN) { return Error(0, 0, "%tpattern and host too large for host ng processing\n"); } item.key = keybuf; if (found_item = s_hsearch(HS_HOST, item, FIND)) { return found_item->data == YES? 1: 0; } passed = innetgr(pattern, host, NULL, NULL); /* Have to make this key a permanent copy for the hash */ klen = strlen(keybuf); item.key = malloc(klen + 1); if (!item.key) { return Error(0, 0, "%tout of memory for host ng processing\n"); } strcpy(item.key, keybuf); item.data = passed? YES: NO; if (!s_hsearch(HS_HOST, item, ENTER)) { return Error(0, 0, "%thash set failure for host ng processing\n"); } return passed; } #else #define netgrp_u_compare(p, u) 0 #define netgrp_h_compare(p, h) 0 #endif int get_setting P__ (()); #ifdef _HPUX_SOURCE #ifdef HAVE_ISCOMSEC char *bigcrypt(); #else /* If we don't have iscomsec() on this HP system, fake it -- otherwise * we'll have to #ifdef the use of iscomsec(), and it's cleaner code * if we don't. */ int iscomsec() { return 0; } #endif #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check that an environment variable only includes allowed characters */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns 0 if pat matched; -1 otherwise. */ int checkenv(name, value, pat) char *name; /* variable name to check (e.g. "TERM") */ char *value; /* contents of variable (e.g. "vt100") */ char *pat; /* pattern that value must match */ { int len; if (!value) return -1; if (debug) (void) fprintf(stderr, "\tcheckenv args: name=\"%s\"; value=\"%s\"; pat=\"%s\"\n", name, value, pat); /* Environment variables are always checked with s_re_comp/s_re_exec: * the patterns are fixed internally, not supplied by the user. */ if (s_re_comp(pat)) { return Error(0, 0, "%t\n\tcheckenv(): couldn't compile pattern `%-.500s'.\n", pat); } if (s_re_exec(value) != 1) { return Error(0, 0, "checkenv(): $%.100s (=%.100s) doesn't match pattern %-.500s.\n", name, value, pat); } /* Limit the value to a reasonable length (MAXENVLEN chars) */ len = strlen(value); if (len > MAXENVLEN) { return Error(0, 0, "Imported environment variables may not \ exceed %d chars; you passed a string of length %d!\n", MAXENVLEN, len); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check the checkvar=name,... list. * If the list isn't empty, use /dev/tty for input. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns 0 if list ok; -1 otherwise. */ int check_var_value() { int l, ntry, match; char buf[500]; char *varname, *truevalue; int ivar; FILE *prompt_fp; char *prompt_dev="/dev/tty"; /* This is implemented as an inefficient operation, but it doesn't * matter because we _assume_ the number of variables to be small * and it's only invoked once. */ if (!localinfo.checkvar || !localinfo.checkvar[0]) return 0; /* no checkvar list */ if (!(prompt_fp = fopen(prompt_dev, "r+"))) { return Error(0, 0, "Can't open %s to test checkvar=name,...\n", prompt_dev); } if (localinfo.checkvar[1]) { /* There must be more than one variable */ fprintf(prompt_fp, "%c%s needs you enter some variables \ before proceeding...\n", toupper(prog[0]), prog+1); } else { fprintf(prompt_fp, "%c%s needs you to enter the %s variable \ before proceeding.\n", toupper(prog[0]), prog+1, localinfo.checkvar[0]); } for (ivar=0; localinfo.checkvar[ivar]; ivar++) { varname = localinfo.checkvar[ivar]; truevalue = get_variable(varname); if (!truevalue) { /* Ouch, checkvar=xxx is used, but xxx isn't defined! */ fclose(prompt_fp); return Error(0, 0, "%t\n\tError in super.tab file: \ `checkvar=%s' is used, but variable %s isn't defined!\n", varname, varname); } for (ntry=0, match=0; ntry < MAXTRY && !match; ntry++) { if (ntry == 0) { fprintf(prompt_fp, "Enter %s ( for reminder): ", varname); } else { fprintf(prompt_fp, "Enter %s (expecting `%s'): ", varname, truevalue); } fflush(prompt_fp); if (!fgets(buf, sizeof(buf), prompt_fp)) { if (feof(prompt_fp)) { fclose(prompt_fp); return Error(0, 0, "can't read %s -- stream was closed!\n", prompt_dev); } else if (ferror(prompt_fp)) { fclose(prompt_fp); return Error(0, 0, "error reading %s\n", prompt_dev); } else { fclose(prompt_fp); return Error(0, 0, "??? feof() and ferror() return 0, \ but I can't read %s\n", prompt_dev); } } if (strlen(buf) == sizeof(buf)-1) { fclose(prompt_fp); return Error(0, 0, "Ridiculously long value <%.300s...> \ returned for variable %s\n", buf, varname); } l = strlen(buf); if (buf[l-1] == '\n') buf[l-1] = '\0'; match = (strcmp(buf, truevalue) == 0); if (!match) { fprintf(prompt_fp, "Variable %s incorrect\n", varname); } } if (!match) { fclose(prompt_fp); return Error(0, 0, "Never got variable %s entered correctly.\n", varname); } } fclose(prompt_fp); /* all variables are ok. */ return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Compare a value to a pattern */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns 0 if pat matched; -1 otherwise. */ int check_value(value, pat) char *value; /* value to check */ char *pat; /* pattern that value must match */ { if (!value) return -1; if (debug) (void) fprintf(stderr, "\tcheck_value args: value=\"%s\"; pat=\"%s\"\n", value, pat); if (s_re_comp(pat)) { return Error(0, 0, "%t\n\tcheck_value(): couldn't compile pattern `%-.500s'.\n", pat); } if (s_re_exec(value) != 1) { return Error(0, 0, "check_value(): value doesn't match pattern %-.500s.\n", pat); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Option checking -- ensure that options to super are reasonable strings. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns 0 if reasonable; -1 otherwise. */ int checkarg(str) char *str; { int len; static int optlen_tot = 0; /* running length of all options to super */ /* Limit each option to a reasonable length (MAXOPTLEN chars) */ len = strlen(str); if (len > MAXOPTLEN) { return Error(0, 0, "Command-line options may not \ exceed %d chars; you passed a string of length %d!\n", MAXOPTLEN, len); } /* Limit the combined option to length MAXOPTLEN_TOT chars */ optlen_tot += len; if (optlen_tot > MAXOPTLEN_TOT) { return Error(0, 0, "The total length of command-line options \ may not exceed %d chars!\n", MAXOPTLEN_TOT); } /* Ensure the option pattern matches OPT_PATTERN */ if (check_value(str, OPT_PATTERN) != 0) return -1; return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Look up owner of a file, return uid and gid of owner */ /* Return 0 on success, -1 & print message on failure */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int get_owner(file, uid_p, gid_p) char *file; uid_t *uid_p; gid_t *gid_p; { /* Return 0 if file ownership ok; -1 if not ok */ struct stat st; if (!file || *file == '\0') return Error(0, 0, "get_owner(): passed null ptr or empty string\n"); if (stat(file, &st) == -1) return Error(1, 0, "stat() failed on file `%s': ", file); *uid_p = st.st_uid; *gid_p = st.st_gid; return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check ownership of the file */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_owner() { /* Return 0 if file ownership ok; -1 if not ok */ struct passwd *owner_pw; if (*localinfo.owner == '\0') return 0; /* no checks required */ /* Convert desired-owner string to a uid */ owner_pw = getpwentry(1, localinfo.owner); if (!owner_pw) return -1; if (localinfo.file_uid != owner_pw->pw_uid) return Error(0, 0, "Actual owner of `%s' is uid %d, but superfile \ requires owner to be %d (%s).\n", localinfo.progs.cmd_file[localinfo.progs.match].File, localinfo.file_uid, owner_pw->pw_uid, owner_pw->pw_name); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Gets an entry from the password file. Optionally accepts special bracketed * name (e.g. or ). Accepts names or text uid's. * Returns ptr to password entry. The password entry may be that returned * by getpwnam(), or it may be one already stored in a super-owned struct; * you can't make any assumptions about it -- therefore don't modify it. * * The returned pointer points to an area that may be overwritten by later * calls to the getpwxxx() routines; therefore if the caller wants to save * the data, the data must be copied. * * On error, print message and return NULL. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct passwd * getpwentry(allow_brackets, username) int allow_brackets; /* allow special names like */ char *username; /* name to translate */ { struct passwd *pw; int l = strlen(username); if (allow_brackets && username[0] == '<' && username[l-1] == '>') { /* Translate special name */ if (strcmp(username, "") == 0) { if (localinfo.file_uid != UID_NOTSET) { pw = getpwuid(localinfo.file_uid); } else { Error(0, 0, "%t: getpwentry() Internal Error!\n\tFile owner not yet known!\n"); return NULL; } } else if (strcmp(username, "") == 0) { pw = &userinfo.caller; } else { Error(0, 0, "%t\n\t\tUnknown special name %s\n", username); return NULL; } } else { /* Regular name or number */ pw = getpwnam(username); if (!pw) { char c; int i, numeric; numeric = (sscanf(username, "%d%c", &i, &c) == 1); if (numeric) pw = getpwuid(i); } } if (!pw) { Error(0, 0, "%t\n\tNo such user or uid as `%s' in password file.\n", username); return NULL; } return pw; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Gets a group entry. * Accepts text gid's or names. * Returns ptr to group entry. * * The returned pointer points to an area that may be overwritten by later * calls to the getgrxxx() routines; therefore if the caller wants to save * the data, the data must be copied. * * On error, print message and return NULL. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct group * getgrentry(name) char *name; /* name to translate */ { struct group *gr; char c; int i, numeric; gr = getgrnam(name); if (!gr) { numeric = (sscanf(name, "%d%c", &i, &c) == 1); if (numeric) gr = getgrgid(i); } if (!gr) { Error(0, 0, "%t\n\tNo such group or gid as `%s'.\n", name); return NULL; } return gr; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Set supplementary groups according to the specified args */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE_GETGROUPS int set_suppl_groups() { return 0; } #else int set_suppl_groups() { GETGROUPS_T *addgroups_p, *groups_p, groups[NGROUPS_MAX]; GETGROUPS_T gotten_groups[NGROUPS_MAX]; int naddgroups, ngroups; int i; /* Set the supplementary groups */ if (geteuid() != 0) { /* Can't set supplementary groups if we've changed to some other uid */ return 0; } if (*localinfo.u_g) { /* Default is to take from that user. (Don't worry if there is no * such user; it'll get noticed later.) Conflicts with local * option groups=xxx, which is disallowed. */ if (localinfo.ngroups != GROUPS_NOTSET && !localinfo.groups_added) return Error(0, 0, "%t\n\t\tu+g=xxx conflicts with groups=yyy \ and may not be used in the same entry\n"); initgroups(localinfo.user, userinfo.new_gid); /* Check for local or global addgroups */ if (localinfo.ngroups != GROUPS_NOTSET) { addgroups_p = localinfo.groups; naddgroups = localinfo.ngroups; } else if (globalinfo.ngroups != GROUPS_NOTSET && globalinfo.groups_added) { addgroups_p = globalinfo.groups; naddgroups = globalinfo.ngroups; } else { addgroups_p = NULL; naddgroups = 0; } ngroups = Getgroups(NGROUPS_MAX, gotten_groups); if (ngroups == -1) return Error(1, 0, "%t Getgroups() failed: "); if (ngroups + naddgroups > NGROUPS_MAX) return Error(1, 0, "%t\n\t\taddgroups=xxx adds too many groups."); for (i = 0; i < ngroups; i++) groups[i] = gotten_groups[i]; for (groups_p = &groups[ngroups], i=0; i < naddgroups; i++) *groups_p++ = *addgroups_p++; ngroups += naddgroups; } else if (localinfo.ngroups != GROUPS_NOTSET) { /* There are some explicit local groups=xxx */ if (Setgroups(localinfo.ngroups, localinfo.groups) == -1) return Error(1, 0, "Failed to set supplementary groups list: "); } else if (globalinfo.ngroups != GROUPS_NOTSET) { /* There is an explicit global groups=xxx or addgroups=xxx */ if (Setgroups(globalinfo.ngroups, globalinfo.groups) == -1) return Error(1, 0, "Failed to set supplementary groups list: "); } else { /* Default is no supplementary groups */ if (Setgroups(0, localinfo.groups) == -1) return Error(1, 0, "Failed to clear supplementary groups list: "); } return 0; } #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Set user, group, and supplementary groups according to the specified args */ /* Side effect: if localinfo.user is numeric, change it to a name */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int set_u_g() { /* Return 0 on success, -1 on failure */ SETGRENT_T setgrent(); void endgrent(); int i, j, k = -1; int found_gid = -1, found_egid = -1; struct passwd *pw = NULL; int use_setreuid; /* true iff we need to use setreuid() */ int use_setregid; /* true iff we need to use setregid() */ uid_t uid_pw_uid = -1, euid_pw_uid = -1; gid_t u_g_pw_gid = -1; char *uid_pw_name = NULL, *euid_pw_name = NULL; /* * Start by looking up user id's and group id's. We'll assign * actual values after we've looked it all up. */ /* First, get the group id's specified by {e,}gid=xxx */ if (*localinfo.group) { found_gid = findgid(1, localinfo.group); if (found_gid == -1) { return Error(0, 0, "%t\n\tCan't set gid: no such group as `%s' in group file.\n", localinfo.group); } } if (*localinfo.egroup) { found_egid = findgid(1, localinfo.egroup); if (found_egid == -1) { return Error(0, 0, "%t\n\tCan't set egid: no such group as `%s' in group file.\n", localinfo.egroup); } } /* Second, get the password entries specified by {e,}uid=xxx, u+g=xxx */ if (*localinfo.u_g && !*localinfo.user) { /* u+g=zzz was used, but uid=xxx was not. So, set user from u+g. */ strcpy(localinfo.user, localinfo.u_g); } if (*localinfo.user) { pw = getpwentry(1, localinfo.user); if (!pw) return -1; uid_pw_uid = pw->pw_uid; uid_pw_name = strdup(pw->pw_name); if (!uid_pw_name) return Error(0, 0, "%t\n\tfailed to malloc space for uid_pw_name=<%s>\n", pw->pw_name); } if (*localinfo.euser) { pw = getpwentry(1, localinfo.euser); if (!pw) return -1; euid_pw_uid = pw->pw_uid; euid_pw_name = strdup(pw->pw_name); if (!euid_pw_name) return Error(0, 0, "%t\n\tfailed to malloc space for euid_pw_name=<%s>\n", pw->pw_name); } if (*localinfo.u_g) { pw = getpwentry(1, localinfo.u_g); if (!pw) return -1; u_g_pw_gid = pw->pw_gid; } pw = NULL; if (*localinfo.group && *localinfo.u_g) { return Error(0, 0, "%t\n\tCan't mix options gid=xxx and u+g=yyy in one entry."); } /* * OK, now we have all the uid/gid info. Select uid's and gid's, * and select the appropriate set of functions to do the assignments. */ /* UID defaults: */ userinfo.new_uid = userinfo.caller.pw_uid; use_setreuid = 0; /* don't have to use setreuid() */ if (*localinfo.euser) { /* euid=xxx was used */ userinfo.new_euid = euid_pw_uid; if (strcmp(euid_pw_name, localinfo.euser) != 0) { /* localinfo.euser must be numeric; convert it to string */ strcpy(localinfo.euser, euid_pw_name); } use_setreuid = 1; /* have to use setreuid() */ } if (*localinfo.user) { /* uid=xxx or u+g=xxx was used */ userinfo.new_uid = uid_pw_uid; if (strcmp(uid_pw_name, localinfo.user) != 0) { /* localinfo.user must be numeric; convert it to string */ strcpy(localinfo.user, uid_pw_name); } } /* GID defaults: */ userinfo.new_gid = userinfo.caller.pw_gid; use_setregid = 0; /* don't have to use setreuid() */ if (*localinfo.egroup) { /* egid=xxx was used */ userinfo.new_egid = found_egid; use_setregid = 1; /* have to use setreuid() */ } if (*localinfo.group) { /* gid=xxx was used */ userinfo.new_gid = found_gid; } else if (*localinfo.u_g) { userinfo.new_gid = u_g_pw_gid; } /* Set supplementary groups */ if (set_suppl_groups() == -1) return -1; /* Now set uid & gid */ if (use_setregid) { #ifdef HAVE_SETREGID if ((i=setregid(userinfo.new_gid, userinfo.new_egid)) == -1) { return Error(1, 0, "setregid(gid=%d, egid=%d) failed: ", userinfo.new_gid, userinfo.new_egid); } else if ((j=getgid()) != userinfo.new_gid || (k=getegid()) != userinfo.new_egid) { return Error(0, 0, "setregid(gid=%d,egid=%d) returned 0, but getgid()=%d,getegid()=%d!", userinfo.new_gid, userinfo.new_egid, j, k); } #else return Error(0, 0, "Can't use egid=xxx option, because this host doesn't offer the setregid() function"); #endif } else if (*localinfo.group || *localinfo.u_g) { if ((i=setgid(userinfo.new_gid)) == -1) { return Error(1, 0, "setgid(gid=%d) failed: ", userinfo.new_gid); } else if ((j=getgid()) != userinfo.new_gid) { return Error(0, 0, "setgid(gid=%d) returned %d, but getgid() returned %d!", userinfo.new_gid, i, j); } } if (use_setreuid) { #ifdef HAVE_SETREUID if ((i=setreuid(userinfo.new_uid, userinfo.new_euid)) == -1) { return Error(1, 0, "setreuid(uid=%d, euid=%d) failed: ", userinfo.new_uid, userinfo.new_euid); } else if ((j=getuid()) != userinfo.new_uid || (k=geteuid()) != userinfo.new_euid) { return Error(1, 0, "setreuid(uid=%d,euid=%d) returned 0, but getuid()=%d,geteuid()=%d!", userinfo.new_uid, userinfo.new_euid, j, k); } #else return Error(1, 0, "Can't use euid=xxx option, because this host doesn't offer the setreuid() function"); #endif } else if (*localinfo.user || *localinfo.u_g) { if ((i=setuid(userinfo.new_uid)) == -1) { return Error(1, 0, "setuid(uid=%d) failed: ", userinfo.new_uid); } else if ((j=getuid()) != userinfo.new_uid) { return Error(1, 0, "setuid(uid=%d) returned %d, but getuid() returned %d!", userinfo.new_uid, i, j); } } if (uid_pw_name) free(uid_pw_name); if (euid_pw_name) free(euid_pw_name); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Puts the encrypted password in userinfo.encr, and the salt in userinfo.salt. * Returns 0 on success, -1 on failure to obtain the password. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifdef SUNOS5 #define HAVE_G_E_PW int get_encrypted_pw() { /* Shadow passwords are always used on Sunos 5.x */ struct spwd *caller_pw; if (!(caller_pw = getspnam(userinfo.caller.pw_name))) { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain shadow password entry for user %s", userinfo.caller.pw_name); return -1; } strcpy(userinfo.encr, caller_pw->sp_pwdp); return get_setting(); } #endif #ifdef _HPUX_SOURCE #define HAVE_G_E_PW int get_encrypted_pw() { if(iscomsec()) { struct pr_passwd *caller_pw; if (!(caller_pw = getprpwnam(userinfo.caller.pw_name))) { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain Trusted Computing Base entry for user %s", userinfo.caller.pw_name); return -1; } strcpy(userinfo.encr, caller_pw->ufld.fd_encrypt); } else { struct passwd *caller_pw; /* See if we can do shadow password lookup for HPUX 9.x. * The rule is that if /.secure/etc/passwd exists, we have to use it; * otherwise, fall through to regular password file lookup. */ static struct stat st; if (stat("/.secure/etc/passwd", &st) == 0) { /* Shadow password file exists; use it */ struct s_passwd *caller_pw; if (!(caller_pw = getspwnam(userinfo.caller.pw_name))) { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain shadow password entry for user %s", userinfo.caller.pw_name); return -1; } strcpy(userinfo.encr, caller_pw->pw_passwd); } else { /* Fall through to regular password file lookup. */ strcpy(userinfo.encr, userinfo.caller.pw_passwd); } } return get_setting(); } #endif #ifdef SCO #define HAVE_G_E_PW int get_encrypted_pw() { struct passwd *caller_pw; struct spwd *caller_ps; if (!(caller_pw = getpwnam(userinfo.caller.pw_name))) { sprintf(authInitMsg1, "No password entry for user %s.\n", userinfo.caller.pw_name); return -1; } /* SCO 3.2v4 has "x" in password field to indicate shadow password * file has to be consulted. */ if (strcmp(caller_pw->pw_passwd, "x") == 0) { /* Shadow password in use... */ if (!(caller_ps = getspnam(userinfo.caller.pw_name))) { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain shadow password entry for user %s", userinfo.caller.pw_name); return -1; } strcpy(userinfo.encr, caller_ps->sp_pwdp); } else { /* Fall through to regular password file lookup. */ strcpy(userinfo.encr, caller_pw->pw_passwd); } return get_setting(); } #endif #ifdef Digital_UNIX #define HAVE_G_E_PW int get_encrypted_pw() { struct passwd *caller_pw; struct pr_passwd *caller_prpass; if (!(caller_pw = getpwnam(userinfo.caller.pw_name))) { sprintf(authInitMsg1, "No password entry for user %s.\n", userinfo.caller.pw_name); return -1; } /* Digital Unix has "x" in password field to indicate shadow password * file has to be consulted. */ if (strcmp(caller_pw->pw_passwd, "x") == 0) { /* Protected (shadow) password in use... */ if (!(caller_prpass = getprpwnam(userinfo.caller.pw_name))) { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain shadow password entry for user %s", userinfo.caller.pw_name); return -1; } strcpy(userinfo.encr, caller_prpass->ufld.fd_encrypt); } else { /* Fall through to regular password file lookup. */ strcpy(userinfo.encr, caller_pw->pw_passwd); } return get_setting(); } #endif #ifdef __linux__ #define HAVE_G_E_PW int get_encrypted_pw() { /* Use /etc/shadow if it exists; else fall back on std */ static struct stat st; if (stat("/etc/shadow", &st) == 0) { struct spwd *spwd = 0L; if (!(spwd = getspnam(userinfo.caller.pw_name))) { /* Gordon Lack notes: Linux doesn't use the shadow file for NIS * passwords, so if you get ENOENT or no error, then try the * local password file. */ if (errno == ENOENT || errno == 0) { strcpy(userinfo.encr, userinfo.caller.pw_passwd); } else { authInitErrno = errno; sprintf(authInitMsg1, "Failed to obtain shadow password entry for user %s", userinfo.caller.pw_name); return -1; } } else { /* got shadow entry */ strcpy(userinfo.encr, spwd->sp_pwdp); } } else { /* Fall through to regular password file lookup. */ strcpy(userinfo.encr, userinfo.caller.pw_passwd); } return get_setting(); } #endif #ifdef __FreeBSD__ #define HAVE_G_E_PW int get_encrypted_pw() { /* getpwnam() and getpwuid() will have read the shadow passwd * if our effective uid == root; no need to use getspnam() or the like. * But if the encrypted pw is "*", then we didn't get the real pw. */ strcpy(userinfo.encr, userinfo.caller.pw_passwd); if (strcmp(userinfo.encr, "*") == 0) { sprintf(authInitMsg1, "Can't get encrypted password, \ or there is no password, for user %s", userinfo.caller.pw_name); return -1; } return get_setting(); } #endif #ifdef __OpenBSD__ #define HAVE_G_E_PW int get_encrypted_pw() { /* getpwnam() and getpwuid() will have read the shadow passwd * if our effective uid == root; no need to use getspnam() or the like. * But if the encrypted pw is "*", then we didn't get the real pw. */ strcpy(userinfo.encr, userinfo.caller.pw_passwd); if (strcmp(userinfo.encr, "*") == 0) { sprintf(authInitMsg1, "Can't get encrypted password, \ or there is no password, for user %s", userinfo.caller.pw_name); return -1; } return get_setting(); } #endif #ifndef HAVE_G_E_PW int get_encrypted_pw() { /* Vanilla password file lookup */ strcpy(userinfo.encr, userinfo.caller.pw_passwd); strncpy(userinfo.salt, userinfo.caller.pw_passwd, 2); return get_setting(); } #endif /* * Read the userinfo.encr (encrypted passwd field) and pull out the data * needed for the "salt" or "setting" argument to crypt(). * This version implements the following rule: * o if encr begins with "$", the entire encr field should be used * (crypt() will be responsible for extracting the data it needs); * o otherwise, if encr begins with "_", use the first 9 chars * (crypt() will discard the leading "_" and use the next 8 characters); * o otherwise, the salt is the first two chars. * * Returns: * -1 (plus Error()) on failure * 0 on success. */ int get_setting() { if (sizeof(userinfo.salt) <= strlen(userinfo.encr)) { return Error(0, 0, "Compilation error: the userinfo.salt field is too short (%d chars) to hold a copy of the userinfo.encr field (%d chars) for user %s", sizeof(userinfo.salt), strlen(userinfo.encr), userinfo.caller.pw_name); } if (userinfo.encr[0] == '$') { strcpy(userinfo.salt, userinfo.encr); } else if (userinfo.encr[0] == '_') { /* crypt() _might_ parse the encr field to pull off the necessary * salt, but we don't make that assumption. */ strncpy(userinfo.salt, userinfo.encr, 9); userinfo.salt[9] = '\0'; } else { /* Salt is first two chars. */ strncpy(userinfo.salt, userinfo.encr, 2); userinfo.salt[2] = '\0'; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns ptr to string with name of desired authentication method. */ char * auth_name() { if (!localinfo.authinfo.required) { return "None"; } else if (localinfo.authinfo.method == SUPER_AUTH_PASSWORD) { return "Password"; } else if (localinfo.authinfo.method == SUPER_AUTH_PAM) { return "PAM"; } else { Error(0, 1, "auth_name: don't recognize auth method %d!\n", localinfo.authinfo.method); } /* NOTREACHED */ return "Unknown!"; /* to make gcc -Wall happy... */ } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Checks if authentication is needed, and does so if needed. * Expects that the encrypted password is already in userinfo.{encr,salt}, * so that this can be run after switching to unpriviledged uid. * Returns 0 on success, -1 on error. * The timestamp directory faces the same problem as the logfile: if the * administrator wants to share an NFS-mounted directory across hosts * on which root is translated to nobody for NFS access, we have to be * able to create the timestamp file under a special uid. This is done * just as in open_writer(): we fork, setuid(), and do the file * manipulation in the child. This allows us to implement a special uid * for the timestamp file, without needing the operating system to * offer saved uid's or interprocess file-descriptor passing, etc. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_auth(cmd) char *cmd; { char file[MAXPATHLEN]; struct stat st; int l, istat, file_exists, got_auth, err, timestamp_creatok; int timed_out = 0; int status; pid_t pid, child; char mkdirMsg[1000]; char *authuser; if (!localinfo.authinfo.required) return 0; /* don't need authentication */ if (*authInitMsg1 || *authInitMsg2) { /* A message was generated during authentication initialization, * way back before the super.tab file was read. It was only * relevant if the command required authorization... well, this * command requires user authentication, so print the message now. */ if (*authInitMsg1) { if (authInitErrno) { errno = authInitErrno; Error(1, 0, "%s: ", authInitMsg1); } else { Error(0, 0, "%s", authInitMsg1); } } if (*authInitMsg2) { Error(0, 0, "%s", authInitMsg2); } } /* Create or update the timestamp file even if the lifetime is 0 * (always ask for password). We do this because the user may * execute _another_ command which has a password expiry > 0, * and which will be happy to use the password that was already * entered with the 0-lifetime command. */ child = fork(); if (child == -1) { Error(1, 0, "Failed to create child for timestamp processing: "); return -1; } else if (child > 0) { /* In parent -- wait to see if the child succeeded */ while ((pid = wait(&status)) > 0 && pid != child) { if (pid == globalinfo.log.pid) { Error(0, 0, "Warning: logging process died -- logging to file has stopped."); globalinfo.log.pid = -1; } else { Error(0, 0, "Wait() surprised! check_pass() received pid %d;\n\t\ expected child pid = %d; waiting for correct pid...\n", pid, child); } } if (pid == -1) { /* wait() failed */ Error(1, 0, "Waiting for timestamp creation process: "); return -1; } else if (status == 0) { /* child succeeded */ return 0; } else if (status != 0) { /* child failed to authenticate user */ Error(0, 0, "Authentication failed\n"); return -1; } /* NOTREACHED */ } /* * If here, must be in child. * Unless this command specifies a timeout > 0, don't generate * error messages if we fail to store timestamp info. * We'll use exit code 1 for failure to authenticate; * otherwise we'll exit 0 (success). */ if (child != 0) { Error(0, 1, "Internal error: child=%d; should be 0!\n", child); } /* * setuid, then make and/or test the directory */ if (*localinfo.authinfo.ts_user != '\0') { stringcopy(localinfo.user, localinfo.authinfo.ts_user, sizeof(localinfo.user)); *localinfo.group = '\0'; *localinfo.u_g = '\0'; if (set_u_g() == -1) { if (localinfo.authinfo.timeout > 0) { Error(1, 0, "failed to setuid to user=%s before setting timestamp file: ", localinfo.user); } exit(2); } } /* Make the timestamp directory name */ timestamp_creatok = 1; mkdirMsg[0] = '\0'; if (!makedirname(TIMESTAMP_DIR, globalinfo.authinfo.perhost ? userinfo.hostname : "", file, &err, mkdirMsg)) { timestamp_creatok = 0; if (localinfo.authinfo.timeout > 0 && mkdirMsg[0]) { if (err) { errno = err; Error(1, 0, "Warning: can't record timestamp: %s: ", mkdirMsg); } else { Error(0, 0, "Warning: can't record timestamp: %s", mkdirMsg); } } } /* Make the timestamp directory */ if (timestamp_creatok) { mkdirMsg[0] = '\0'; if (makedir(file, &err, mkdirMsg) == -1) { timestamp_creatok = 0; if (localinfo.authinfo.timeout > 0 && mkdirMsg[0]) { if (err) { errno = err; Error(1, 0, "Warning: can't record timestamp: %s: ", mkdirMsg); } else { Error(0, 0, "Warning: can't record timestamp: %s", mkdirMsg); } } } } /* Make the file in the timestamp directory */ if (timestamp_creatok) { l = strlen(file) + 1 + strlen(userinfo.caller.pw_name); if (l >= MAXPATHLEN) { if (localinfo.authinfo.timeout > 0) { Error(1, 0, "Can't create timestamp file: would exceed MAXPATHLEN = %d\n", MAXPATHLEN); } timestamp_creatok = 0; } } if (timestamp_creatok) { strcat(file, "/"); strcat(file, userinfo.caller.pw_name); istat = stat(file, &st); if (istat != 0 && errno != ENOENT) { if (localinfo.authinfo.timeout > 0) { Error(1, 0, "Failed to stat timestamp file `%s': ", file); } timestamp_creatok = 0; } } if (timestamp_creatok) { file_exists = (istat == 0); if (file_exists) { timed_out = (localinfo.authinfo.timeout < 1) || ((time(NULL)-st.st_mtime) > localinfo.authinfo.timeout*60); } } got_auth=0; if (localinfo.authinfo.user[0]) { authuser = localinfo.authinfo.user; /* authuser=xxx local opt */ } else if (globalinfo.authinfo.user[0]) { authuser = globalinfo.authinfo.user; /* authuser=xxx global opt */ } else { authuser = userinfo.caller.pw_name; /* default: caller's pw */ } if (!timestamp_creatok || !file_exists || timed_out) { switch (localinfo.authinfo.method) { case SUPER_AUTH_PASSWORD: got_auth = (get_password(cmd, userinfo.caller.pw_name, authuser, userinfo.salt, userinfo.encr) == 1); break; case SUPER_AUTH_PAM: #if WITH_PAM got_auth = (get_pam(cmd, userinfo.caller.pw_name, authuser) == 1); #else Error(0, 1, "Auth method is PAM, but this copy of super \ was compiled without PAM support!"); #endif break; default: Error(0, 1, "Internal error in check_auth: \ unknown auth method %d!\n", localinfo.authinfo.method); } if (!got_auth) return -1; } /* NOTE: A race condition is possible between two super's, with the * worst-case effect of an error message and failure to run the * requested command. */ /* If file exists, and we haven't (a) gotten the password again, or * (b) supposed to automatically refresh the timestamp, do nothing to * the file except ensure that we own it. * Otherwise create the file (unlink it first if it exists). */ if (!timestamp_creatok) { /* do nothing: we failed in setting up the timestamp file, * so don't try to update it. */ } else if (file_exists && !(got_auth || localinfo.authinfo.renewtime)) { if (st.st_uid != geteuid()) return Error(0, 0, "Timestamp file `%s' is owned by uid=%d, but expected owner=%d.\n\ \tN.B. If you recently changed the value of timestampuid=xxx, all existing\n\ \tfiles in the timestamp directory _may_ have the wrong owner; delete them.\n\ \t(No security hole appears when you delete a timestamp file.)\n", file, st.st_uid, geteuid()); } else { if (file_exists) { if (unlink(file) != 0) return Error(1, 0, "Failed to unlink() timestamp file `%s': ", file); } if (open(file, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0200) == -1) return Error(1, 0, "Failed to open() timestamp file `%s': ", file); } exit(0); /* UNREACHABLE */ Error(0, 1, "Unreachable code!\n"); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Encrypt a password. Returns value from crypt() or similar. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * docrypt(prompt, salt) char *prompt; char *salt; { char *crypt(); char *getpass(); char buf[300]; int n; n = s_getpass(prompt, use_stdin, buf, sizeof(buf)); if (n < 0) { Error(0, 1, "Failed to get password.\n"); } else if (n >= sizeof(buf)) { Error(0, 1, "Buffer too small (%d chars) to hold input password!\n", sizeof(buf)-1); } #ifdef _HPUX_SOURCE if (iscomsec()) { #if (HPUX_MAJOR == 10) return bigcrypt(buf, salt); #endif #if (HPUX_MAJOR == 11) return bigcrypt(buf, salt); #endif return crypt(buf, salt); } else { return crypt(buf, salt); } #else return crypt(buf, salt); #endif } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Gets a user's encrypted password. Returns -1 on failure, +1 on success */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int get_password(cmd, caller, user, salt, encr) char *cmd; char *caller; /* the person who invoked super */ char *user; /* the person whose authentication is required */ char *salt; char *encr; { /* No such file or password timed out -- get password */ int ntry, match; char msg[500]; char *encrypted = NULL; if (strcmp(encr, "") == 0) { return Error(0, 0, "Command requires a password, but user `%s' has no password\n", user); } for (ntry=0, match=0; ntry < MAXTRY && !match; ntry++) { if (ntry == 0) { if (localinfo.authinfo.prompt && localinfo.authinfo.prompt[0]) { stringcopy(msg, do_variables(localinfo.authinfo.prompt), sizeof(msg)); } else if (strcmp(caller, user) == 0) { (void) sprintf(msg, "Your password is required for super command `%.400s'...\nPassword: ", cmd); } else { (void) sprintf(msg, "%c%s's password is required for super command `%.400s'...\nPassword: ", toupper(*user), user+1, cmd); } } else { strcpy(msg, "Password incorrect\nPassword: "); } encrypted = docrypt(msg, salt); if (encr && encrypted) { match = (strcmp(encr, encrypted) == 0); } else { match = 0; } } if (!match) return Error(0, 0, "Password incorrect\n"); return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Looks up a group name or number (as a text string), returns gid. * Accepts special names (e.g. or ). * Returns -1 if no such group. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int findgid(allowbrackets, grouplabel) int allowbrackets; /* accept names like */ char *grouplabel; /* name or numeric form */ { struct group *gp; SETGRENT_T setgrent(); void endgrent(); int numeric_gid; int found_gid, is_numeric=0; int l=strlen(grouplabel); char c; if (allowbrackets && grouplabel[0] == '<' && grouplabel[l-1] == '>') { /* Translate special name */ struct passwd *pw = getpwentry(1, grouplabel); if (!pw) return -1; else return pw->pw_gid; } is_numeric = (sscanf(grouplabel, "%d%c", &numeric_gid, &c) == 1); if (is_numeric) return numeric_gid; /* Grouplabel didn't look like a number (according to sscanf), * so look up its name. */ setgrent(); for (found_gid = -1, gp = getgrent(); gp; gp = getgrent()) { if (strcmp(grouplabel, gp->gr_name) == 0) { /* Found the gid in the group file */ found_gid = gp->gr_gid; break; } } endgrent(); return found_gid; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Adds condition to condition list. * returns -1 on syntax error, malloc error, etc; * returns 0 otherwise. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int InsertCondition(condition, s, isglobal) char *condition; /* condition to insert: xxx~yyy */ char *s; /* pts to yyy in condition */ int isglobal; /* Is this a per-command or global condition? */ { char **globlist; TimeList *tl; int i; int invert = (*condition == '!'); if ( invert ) condition++; /* All conditions accept {a,b,c} or a,b,c as lists. * Form the globlist and pass along... */ /* Do brace globbing */ if ((i=globbraces(s, 1, &globlist)) != 0) { /* Local Condition */ return Error(0, 0, "%tMissing `%c'.\n", i); } if (balancedbraces(s) != 0) { return Error(0, 0, "%tUnbalanced braces in %s.\n", s); } if (STRMATCH3("time", condition, s-1)) { tl = isglobal ? &globalinfo.timeafter : &localinfo.time; if (InsertTimeList(s, globlist, tl, isglobal ? "global" : "local", invert) == -1) return -1; } else if (STRMATCH3("user", condition, s-1)) { if (InsertUserList(s, globlist, &localinfo.userpats, &localinfo.origtext, invert) == -1) return -1; } else { return Error(0, 0, "%t\n\tInternal error: unrecognized condition <%s>.\n", condition); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Add a user/group/host pattern to a list. * returns -1 on syntax error, malloc error, etc; * returns 0 otherwise. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int InsertUserList(wd, wdlist, sl, otl, invert) char *wd; /* Pattern to match; must NOT have leading '!'; braces ok; * disallow '<', '>'. */ char **wdlist; /* brace-expanded u/g/h list */ Simple2List *sl;/* Insert user list elements (i.e. argument wdlist) * at sl->next. */ SimpleList *otl;/* Insert original text (i.e. argument wd) * at otl->next. */ int invert; /* Inverts the test */ { int iwd; char *tok, *s; SimpleList *new; Simple2List *new2; /* Check for illegal characters */ if ((s=strchr(wd, '>')) || (s=strchr(wd, '<'))) { if (s-wd == 4 && strncmp(wd, "time", 4) == 0) { return Error(0, 0, "%t\n\tPermittedUser patterns may not use '>' or '<';\n\ \tyou used '%s'; perhaps you meant to write 'time~%s'\n", wd, s); } else { return Error(0, 0, "%t\n\tPermittedUser patterns may not use '>' or '<';\n\ \tyou used '%s'.\n", wd); } } new = (SimpleList *) malloc(sizeof(SimpleList)); if (!new) return Error(0, 0, "%t\n\tFailed to malloc space for PermittedUser\n"); new->next = otl->next; new->pat = (char *) malloc(strlen(wd) + 1); if (!new->pat) return Error(0, 0, "%t\n\tFailed to malloc space for PermittedUser pat\n"); strcpy(new->pat, wd); otl->next = new; for (iwd=0; (tok=wdlist[iwd]); iwd++) { new2 = (Simple2List *) malloc(sizeof(Simple2List)); if (!new2) return Error(0, 0, "%t\n\tFailed to malloc space for PermittedUser\n"); new2->next = sl->next; new2->other = otl->next; new2->pat = (char *) malloc(strlen(tok) + (invert ? 2 : 1)); if (!new2->pat) return Error(0, 0, "%t\n\tFailed to malloc space for PermittedUser pat\n"); if (invert) { *new2->pat = '!'; strcpy(new2->pat+1, tok); } else { strcpy(new2->pat, tok); } sl->next = new2; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Match a list of user/group/host pattern against the present user. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void match_ugh_user(sl, isglobal) Simple2List *sl;/* A list of user pats to match against, starting at sl->next */ int isglobal; /* !0 means its from a global def */ { /* Checks if user is matched against each elt in sl. * Sets matches.match_user if user matches; sets it to 1 if the last * match is non-inverting, 0 otherwise. * BUT! the list created by the InsertUserList function * is in reverse order, so we only need to find the first * entry in the list that is a match (+ or -) and stop there! */ int invert, match; int check_ugh P__((char *, char *)); for (match=0, sl=sl->next; sl && !match; sl=sl->next) { invert = *sl->pat == '!'; if (check_ugh(sl->other->pat, invert ? sl->pat+1 : sl->pat) == 0) { match = 1; matches.user = invert ? 0 : 1; if (debug || it_came_from_cmdline) (void) fprintf(stderr, "\tPermission %s: %s pattern %suser~%s\n", invert ? "denied" : "allowed", isglobal ? "global" : "per-cmd", invert ? "!" : "", sl->other->pat); } else if (debug || it_came_from_cmdline) { (void) fprintf(stderr, "\tNot applicable: %s pattern %suser~%s\n", isglobal ? "global" : "per-cmd", invert ? "!" : "", sl->other->pat); } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check pattern against a hostname. If the hostname is fully-qualified, * then try stripping off each of the domains to find a match. * Return -1 on failure to match; 0 on success. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_host(pat, host) char *pat, *host; { int is_netgroup = 0; int match; char *p, *dotp; if (*pat == '+') { is_netgroup = 1; ++pat; } match = (is_netgroup ? netgrp_h_compare(pat, host) : (*pat_compare)(host)); dotp = strrchr (host, '.'); while (dotp && !match) { *dotp = 0; match = (is_netgroup ? netgrp_h_compare(pat, host) : (*pat_compare)(host)); p = strrchr (host, '.'); *dotp = '.'; dotp = p; } return (match ? 0 : -1); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Try to match a string to a pattern. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int match_pattern(match, do_glob, str, pattern) int match; /* Return input value of match on failure; 1 on success */ int do_glob; /* 0: no brace globbing; * 1: brace glob; * >1: wrap in braces, then brace-glob. */ char *str; char *pattern; { int i, ipat, wrap; char *tok, tokbuf[1000]; char **patlist, *pat1list[2]; char chkbuf[1024]; if (do_glob != 0) { /* Do brace globbing on the pattern */ wrap = (do_glob > 1) ? 1 : 0; if ((i=globbraces(pattern, wrap, &patlist)) != 0) { Error(0, 0, "%tMissing `%c'.\n", i); return match; } } else { pat1list[0] = pattern; pat1list[1] = NULL; patlist = pat1list; } if (balancedbraces(pattern) != 0) { Error(0, 0, "%tUnbalanced braces in %s.\n", pattern); return match; } for (ipat=0; (tok=patlist[ipat]); ipat++) { strcpy(tokbuf, tok); anchor(tok, chkbuf); /* Anchor all matches */ if ((*pat_compile)(chkbuf) != NULL) { Error(0, 0, "%t\n\tBad command pattern: `%s'.\n", pattern); return match; } else if ((*pat_compare)(str) == 1) { if (debug) (void) fprintf(stderr, "\tMatched user's command=%s to CmdPattern=%s\n", str, pattern); return 1; } else if (debug) { (void) fprintf(stderr, "\tNo match user's command=%s to CmdPattern=%s\n", str, pattern); } } return match; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check a single user/group/host string * Return -1 on failure to match; 0 on success. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int check_ugh(origtext, token) char *origtext; /* original text -- for error messages */ char *token; /* user/group/host pattern */ { char chkbuf[1024]; char *userpat, *grouppat, *hostpat; char *colon; int match, i; if (strlen(token) > sizeof(chkbuf)-4) { return Error(0, 1, "%tCan't handle patterns larger than %d chars.\n", sizeof(chkbuf)-4); } /* Split into user:group@host; check host part first (if it exists) */ if ((hostpat = strchr(token, '@'))) { if (hostpat[1] == 0) { return Error(0, 0, "%tMissing hostname in pattern `%s'.\n", origtext); } *hostpat++ = 0; match = -1; if (hostpat[0] == '+') { #ifdef HAVE_INNETGR if (hostpat[1] == 0) { return Error(0, 0, "%tMissing netgroupname in pattern `%s'.\n", origtext); } match = check_host(hostpat, userinfo.hostname); #else return Error(0, 0, "%thostnames may not begin with `+' since this super() was compiled\n\ without -DHAVE_INNETGR.\n"); #endif } else { strtolower(hostpat); anchor(hostpat, chkbuf); /* Force all matches to be anchored */ if ((*pat_compile)(chkbuf) != NULL) { return Error(0, 0, "%tbad host pattern: `%s'.\n", origtext); } } if (match == -1) match = check_host(hostpat, userinfo.lc_hostname); if (debug > 1) fprintf(stderr, "\thost pattern <%s> %s user's host <%s>\n", hostpat, (match == -1) ? "did not match" : "matched", userinfo.lc_hostname); if (match == -1) return -1; } colon = grouppat = strchr(token, ':'); userpat = token; if (*token == '\0' && !hostpat) { /* Nothing in pattern?! */ return Error(0, 0, "%t\n\tUnacceptable pattern `%s'.\n", origtext); } else if (*token == '\0') { userpat = grouppat = "^.*$"; /* only hostname given */ } else if (grouppat && *(grouppat+1)) { /* pat is "uuu:ggg or ":ggg" */ if (token == grouppat) userpat = "^.*$"; /* pat is ":ggg" */ *grouppat++ = '\0'; } else { /* pat is "uuu" or "uuu:" */ if (grouppat) *grouppat = '\0'; /* pat is "uuu:" */ grouppat = "^.*$"; } if (strchr(grouppat, ':')) { return Error(0, 0, "%t\n\tGroup pattern `%s' contains a colon!\n", grouppat); } if (globalinfo.group_slash == 0 && strchr(grouppat, '/')) { return Error(0, 0, "%t\n\tFormat error in super.tab file: \ group pattern `%s' contains a slash.\n\ \tPerhaps you meant to use Cmd::Filename, but forgot one colon,\n\ \tso it looks like User:Group? If you really need to allow\n\ \tslashes in group patterns, use global option group_slash=y.\n", grouppat); } #ifdef HAVE_INNETGR if (userpat[0] == '+') { if (userpat[1] == 0) { return Error(0, 0, "%tMissing netgroupname in pattern `%s'.\n", origtext); } match = netgrp_u_compare(&userpat[1], userinfo.caller.pw_name); } else #endif { anchor(userpat, chkbuf); /* Anchor all matches */ if ((*pat_compile)(chkbuf) != NULL) { return Error(0, 0, "%t\n\tbad user pattern: `%s'.\n", origtext); } match = (*pat_compare)(userinfo.caller.pw_name); #ifdef MATCH_DECIMAL_UID if (match != 1) { /* Enabling MATCH_DECIMAL_UID allows the userpat to be * numeric, as an alternative to being interpreted as a * user name: after checking the username, we check if the * user's uid, as a decimal text value, matches the user * pattern userpat. */ char buf[20]; (void) sprintf(buf, "%d", userinfo.caller.pw_uid); match = (*pat_compare)(buf); } #endif } if (debug > 1) fprintf(stderr, "\tuser pattern <%s> %s username <%s>\n", userpat, (match != 1) ? "did not match" : "matched", userinfo.caller.pw_name); if (match != 1) return -1; anchor(grouppat, chkbuf); i = ingroup(userinfo.caller.pw_name, userinfo.caller.pw_gid, chkbuf); if (i == -1) return Error(0, 0, "%t\n\tbad group pattern\n", origtext); if (debug > 1) fprintf(stderr, "\tuser <%s> is %sa member of group <%s>\n", userinfo.caller.pw_name, (i != 1) ? "not " : "", grouppat); if (i != 1) return -1; return 0; /* Success! */ } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Determines if user's group matches a group pattern. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int created_group_table = 0; int ingroup(user, gid, gp_pat) char *user; gid_t gid; char *gp_pat; /* pattern to match */ { /* Use: * ingroup(user, gid, gp_pat) * Returns: * 1 if the user is in a group matching the regex pattern gp_pat. * 0 if the user isn't in a group matching the pattern. * -1 if pattern failed to compile. * SIDE-EFFECT: uses pat_compile/pat_compare! * -- messes up caller's use of same! * Examples: * ingroup("joe", joes_gid, "xyz") * returns !0 if user joe is in group "xyz". * ingroup("joe", joes_gid, "xy.*") * returns !0 if user joe is in any group matching "xy.*". */ struct group *gp; char **mem; char buf[20]; SETGRENT_T setgrent(); void endgrent(); ENTRY item, *found_item; int passed, klen; if ((*pat_compile)(gp_pat) != (char *)0 ) return -1; if (!created_group_table) { if (!s_hcreate(HS_GROUP, 1000)) { return Error(0, 0, "%tCouldn't allocate hash table for group processing\n"); } created_group_table = 1; } /* Catenate user, gid and gp_pat for the key such that * "abc" + 10 + "de" is not the same as "ab" + 1 + "0cde". * Use "\n", as that will have been stripped from input before we get here. */ if (snprintf(keybuf, MAX_KEYLEN, "%s\n%d\n%s", user, gid, gp_pat) >= MAX_KEYLEN) { return Error(0, 0, "%tuser/gid/gp_pat too large for user ng processing\n"); } item.key = keybuf; if (found_item = s_hsearch(HS_GROUP, item, FIND)) { return found_item->data == YES? 1: 0; } passed = 0; /* Assume the worst */ /* Search group file for groups user is in. For each group of which * the user is a member, test a match to the pattern. */ setgrent(); for (gp = getgrent(); gp; gp = getgrent()) { /* The gr_mem list only shows usernames added in the /etc/group file, * and not any users assigned to the group in the passwd file. * Thus discover group membership by first checking the user's * group from the password file (gp->gr_gid) against this group's * gid, then check to see if this user is in the gp->gr_mem list. */ if (gid != gp->gr_gid) { for (mem = gp->gr_mem; *mem ; mem++) if (strcmp(*mem, user) == 0) break; if (!*mem) continue; /* not in group */ } /* if here, the user is in group gp; now check if group * name gp->gr_name matches group pattern gp_pat. */ if ((*pat_compare)(gp->gr_name) == 1) { /* successful match -- user is in a group that matches gp_pat */ endgrent(); /* return 1; */ passed = 1; goto found_it; } #ifdef MATCH_DECIMAL_GID else { /* Enabling MATCH_DECIMAL_GID allows the gp_pat to be * numeric, as an alternative to being interpreted as a * group name: we check if the group id gp->gr_gid, as a * decimal text value, matches the group pattern gp_pat. */ (void) sprintf(buf, "%d", gp->gr_gid); if ((*pat_compare)(buf) == 1){ /* successful match -- user is in a group that matches gp_pat */ endgrent(); /* return 1; */ passed = 1; goto found_it; } } #endif } #ifdef MATCH_DECIMAL_GID /* We haven't found any group from /etc/group to which we belong that * matches the pattern. It is possible that the user's group id from the * password file isn't in the /etc/group file at all, in which case the * user's group won't have matched the pattern since we've only checked * /etc/group entries so far. Now check the numeric id from the * /etc/passwd file against the pattern. */ (void) sprintf(buf, "%d", gid); if ((*pat_compare)(buf) == 1){ endgrent(); /* return 1; */ passed = 1; goto found_it; } #endif endgrent(); /* return 0; */ found_it: /* Have to make this key a permanent copy for the hash */ klen = strlen(keybuf); item.key = malloc(klen + 1); if (!item.key) { return Error(0, 0, "%tout of memory for group processing\n"); } strcpy(item.key, keybuf); item.data = passed? YES: NO; if (!s_hsearch(HS_GROUP, item, ENTER)) { return Error(0, 0, "%thash set failure for group processing\n"); } return passed; } super-3.30.0/time.c0000444000104100002640000003355410732537455012372 0ustar willspgstatic const char rcsid[] = "$Id: time.c,v 1.28 2004/04/30 17:00:58 will Exp $"; #include "super.h" #define ANYDAY 7 /* Maximum length of a time field in super.tab. */ #define MAX_T_FIELDLEN 80 struct weekDay { char name[20]; char abbr[20]; }; #ifdef HAVE_LOCALE_H /* We will pick up weekday names dynamically; make the first name a * null string so we know that initialization has yet to be done. */ static struct weekDay weekday[7] = { { "", ""}, }; #else static struct weekDay weekday[7] = { { "sunday", "sun", }, { "monday", "mon", }, { "tuesday", "tue", }, { "wednesday", "wed", }, { "thursday", "thu", }, { "friday", "fri", }, { "saturday", "sat" } }; #endif char * dayname(n) int n; /* day number: 0..6 = sun..sat; 7 = any */ { /* Returns ptr to day of week */ static char *anyday="*"; #ifdef HAVE_LOCALE_H if (*(weekday[0].name) == '\0') readtime_init(); #endif if (n < 0 || n > 6) return anyday; else return weekday[n].name; } int daynum(t) int t; /* A Unix time */ { /* Returns day of week, with 0 = sunday. This routine takes the input * time as given -- it doesn't assume GMT or any such thing -- and * returns the day number: you should use localtime() or gmtime() if * you have them available. */ int jd = (int) (2440587.5 + ((double) t) / 86400.); int i = (jd+1) / 7; return jd - 7 * i + 1; } int InsertTimeList(str, wdlist, tl, timetype, invert) char *str; /* Contains one of the time types accepted by readtimerange(), * and extended to allow brace-expansion */ char **wdlist; /* list-expanded form of str */ TimeList *tl; /* Insert time list elements at tl->next */ char *timetype; /* "per-cmd" or "global": a string to use in info msgs */ int invert; /* Inverts the test */ { /* Checks if time is in the range specified by the time string str. * Returns * -1 on syntax error, malloc error, or similar; * 0 otherwise. * Side effect: sets the matches.time field. */ int match; int iwd; char *tok; TimeList *new; for (iwd=0, match=0; (tok=wdlist[iwd]); iwd++) { new = (TimeList *) malloc(sizeof(TimeList)); if (!new) return Error(0, 0, "%t\n\tFailed to malloc space for time entry\n"); new->next = tl->next; new->te.invert = invert; /* interpret pat */ if (readtimerange(tok, &new->te.begin, &new->te.end, &new->te.day) == -1) return -1; if (debug) (void) fprintf(stderr, "\tInsert %s time pattern: %stime~%s (min=%d-%d day=%d [dayname=%s])\n", timetype, invert ? "!" : "", tok, new->te.begin, new->te.end, new->te.day, dayname(new->te.day)); tl->next = new; } return 0; } void matchtime(our, tl) OurTime *our; /* A time entry to match. Only the "min" and "day" fields * will be used, so it's ok if the "start" field doesn't * match them. */ TimeList *tl; /* A list of times to match against; 1st used is tl->next */ { /* The time list created by the InsertTimeList function * is in reverse order, so we only need to find the first * entry in the list that is a match (+ or -) and stop there. * But if there are no matches, we scan all entries. * Side effects: * If an entry is matched, matches.time is set to 0 or 1, * according as the entry is/is not inverted. Otherwise unmodified. * If an entry is non-inverted, matches.alltime_invert is set to 0, * otherwise unmodified. Note that this will include all entries * only if there was no match, because scanning stops with a match. */ /* The caller should interpret the returned matches as * follows. * Case 1: Our time 12:30 * time~8-17 !time~12-13 time~23-24 * a. time~8-17 matches, user allowed. * b. time~12-13 matches, ! means user disallowed. * c. time~23-24 doesn't match, doesn't change allow/disallow. * Therefore user disallowed. * Case 2: Our time 12:30 * time~8-17 !time~12-13 !time~23-24 * a. time~8-17 matches, user allowed. * b. time~12-13 matches, ! means user disallowed. * c. time~23-24 doesn't match, doesn't change allow/disallow. * Therefore user disallowed. * Case 3: Our time 12:30 * !time~23-24 * a. time~23-24 doesn't match, doesn't change allow/disallow. * b. Thus fall back on default. Default is * i) allow if _all_ statements are inverted; * ii) else disallow. * Therefore user is allowed. * Case 4: Our time 17:30 * time~8-17 !time~12-13 !time~23-24 * a. time~8-17 doesn't match, doesn't change allow/disallow. * b. time~12-13 doesn't match, doesn't change allow/disallow. * c. time~23-24 doesn't match, doesn't change allow/disallow. * d. Thus fall back on default. Default is * i) allow if _all_ statements are inverted; * ii) else disallow. * Therefore user is disallowed. */ int match; for (tl=tl->next, match=0; tl && !match; tl=tl->next) { if (!tl->te.invert) matches.allinverted = 0; if (our->min >= tl->te.begin && our->min <= tl->te.end && (tl->te.day == ANYDAY || our->day == tl->te.day)) { /* matches */ match = 1; matches.time = tl->te.invert ? 0 : 1; if (debug || it_came_from_cmdline) { (void) fprintf(stderr, "\t%s: %stime~%d:%.2d-%d:%.2d/%s\n", tl->te.invert ? "Permission denied" : "Permission allowed", tl->te.invert ? "!" : "", tl->te.begin/60, tl->te.begin%60, tl->te.end/60, tl->te.end%60, dayname(tl->te.day)); } } else { /* Our time is not in the range of this time entry. */ if (debug || it_came_from_cmdline) { (void) fprintf(stderr, "\tNot applicable: %stime~%d:%.2d-%d:%.2d/%s\n", tl->te.invert ? "!" : "", tl->te.begin/60, tl->te.begin%60, tl->te.end/60, tl->te.end%60, dayname(tl->te.day)); } } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Frees all elements in a TimeList, except the one it's given. * The "next" field of that element is set NULL. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void free_TimeList(tl) TimeList *tl; { TimeList *tlp; if (!tl || !tl->next) return; tlp = tl->next; tl->next = NULL; for (tl=tl->next ; tl; tl = tlp) { tlp = tl->next; free(tl); } } #ifdef HAVE_LOCALE_H /* The following function should be invoked each time the locale * is changed (via lang=xxx). */ void readtime_init() { struct tm ti; int i; /* We know the following to be a Sunday */ ti.tm_sec = 0; ti.tm_min = 0; ti.tm_hour = 12; ti.tm_mday = 4; ti.tm_wday = 0; ti.tm_mon = 0; ti.tm_year = 70; /* Figure out the days of the week in the current locale */ if (debug) fprintf(stderr, "\tInitializing days of week. Full names and official abbr's:\n\t"); for (i = 0; i < 7; i++) { strftime(weekday[i].name, sizeof(weekday[0].name)-1, "%A", &ti); strtolower(weekday[i].name); strftime(weekday[i].abbr, sizeof(weekday[0].abbr)-1, "%a", &ti); strtolower(weekday[i].abbr); if (debug) { fprintf(stderr, "%s (%s) ", weekday[i].name, weekday[i].abbr); if (i == 3) fputs("\n\t", stderr); } ti.tm_mday++; ti.tm_wday++; } if (debug) fputs("\n", stderr); } #endif int readtimerange(str, t1, t2, d) char *str; short *t1; /* Returned with 1st time, units=minutes, range = 0..1439 */ short *t2; /* Returned with 2nd time, units=minutes, range = 0..1439 */ char *d; /* Returned with day number (0=Sunday) or ANYDAY */ { /* str is a string containing one of the following patterns: * * "" (implies all days, all hours) * [/]dayname (implies all hours) * hh[:mm]-hh[:mm]/dayname * hh[:mm]-hh[:mm] (implies all days) * xhh[:mm]/dayname (x is one of <, >, <=, >= ) * xhh[:mm] (implies all days; x is as above) * * The valid daynames are (case-insensitive) either an official abbreviated * day name in the current locale; a 3-or-more character abbreviation * of the full weekday; or "*", meaning any day. * For convenience, the upper time can be 24:00, but it is converted * to 11:59. * Returns: -1 on invalid time pattern; 0 otherwise. */ char *s, *p; int hh1, mm1; int hh2, mm2; int i, l; int has_relop; #ifdef HAVE_ENUM enum { LT, LE, GT, GE } relop; #else /* No enums! */ #define LT 0 #define LE 1 #define GT 2 #define GE 3 int relop; #endif if (strlen(str) > MAX_T_FIELDLEN) { return Error(0, 0, "%t\n\tInvalid time range; first %d chars are: <%*.*s>\n", MAX_T_FIELDLEN, MAX_T_FIELDLEN, str); } #ifdef HAVE_LOCALE_H if (*(weekday[0].name) == '\0') readtime_init(); #endif s = str; has_relop = 0; if (*s == '<' || *s == '>') { /* Must be xhh[:mm][/dayname] */ has_relop = 1; switch (*s++) { case '<': relop = (*s == '=') ? (s++, LE) : LT; break; case '>': relop = (*s == '=') ? (s++, GE) : GT; break; default: return Error(0, 0, "%t\n\tInvalid time range <%s>\n", str); } if (!isdigit(*s)) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid hour part)\n", str); hh1 = strtol(s, &p, 10); if (p == s || hh1 > 24 || hh1 < 0) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid hour part)\n", str); s = p; if (*s != ':') { /* minutes not given */ mm1 = 0; } else { mm1 = strtol(++s, &p, 10); if (p == s || mm1 > 59 || mm1 < 0 || (mm1 > 0 && hh1 == 24)) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid minute part)\n", str); } s = p; switch (relop) { case LT: *t1 = 0; *t2 = hh1*60 + mm1 - 1; break; case LE: *t1 = 0; *t2 = hh1*60 + mm1; break; case GT: *t1 = hh1*60 + mm1 + 1; *t2 = 24*60 - 1; break; case GE: *t1 = hh1*60 + mm1; *t2 = 24*60 - 1; break; default: return Error(0, 0, "%t\n\tInternal time range error -- relop is %d\n", relop); } } else if (isdigit(*str)) { /* It must begin hh:mm-hh:mm */ s = str; hh1 = strtol(s, &p, 10); if (p == s || hh1 > 24 || hh1 < 0) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid first hr)\n", str); s = p; if (*s != ':') { mm1 = 0; } else { mm1 = strtol(++s, &p, 10); if (p == s || mm1 > 59 || mm1 < 0 || (mm1 > 0 && hh1 == 24)) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid first min)\n", str); } *t1 = hh1*60 + mm1; s = p; if (*s++ != '-') return Error(0, 0, "%t\n\tInvalid time range <%s> (expected '-' in hh:mm-hh:mm)\n", str); hh2 = strtol(s, &p, 10); if (p == s || hh2 > 24 || hh2 < 0) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid second hr)\n", str); s = p; if (*s != ':') { mm2 = 0; } else { mm2 = strtol(++s, &p, 10); if (p == s || mm2 > 59 || mm2 < 0 || (mm2 > 0 && hh2 == 24)) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid second min)\n", str); } s = p; if (*s != '\0' && *s != '/') return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid char after time range)\n", str); *t2 = hh2*60 + mm2; } else { /* We've seen no time part; must be dayname only; time is all hrs */ s = str; *t1 = 0; *t2 = 24 * 60; } if (*s == '/') /* Skip field separator, if present */ s++; if (*s == '\0' || strcmp(s, "*") == 0) { *d = ANYDAY; /* all days */ } else { /* It must be a weekday, expressed in the current locale. * Allow just dayname or /dayname. */ char buf[MAX_T_FIELDLEN+1]; strcpy(buf, s); strtolower(buf); for (i=0; i<7; i++) { #if 0 fprintf(stderr, "HERE: s=<%s> buf=<%s> day=<%s> abbr=<%s>\n", s, buf, weekday[i].name, weekday[i].abbr); #endif if (strlen(buf) < 3) { ; /* not accepted -- must be at least three chars */ } else if (strncmp(weekday[i].name, buf, (l=strlen(buf))) == 0) { *d = i; break; } else if (strcmp(weekday[i].abbr, buf) == 0) { *d = i; break; } } if (i >= 7) return Error(0, 0, "%t\n\tInvalid time range <%s> (invalid day field)\n", str); } /* Convert 24:00 to 23:59 */ if (*t1 == 24*60) (*t1)--; if (*t2 == 24*60) (*t2)--; if (*t1 < 0 || *t2 < 0 || *t1 > 24*60-1 || *t2 > 24*60-1) return Error(0, 0, "%t\n\tInvalid time range <%s>\n", str); return 0; } int readtime(str, t, d) char *str; short *t; /* Returned with time, units=minutes, range = 0..1439 */ char *d; /* Returned with day number (0=Sunday) */ { /* str must be like: * * hh[:mm]/dayname * * The valid daynames are (case-insensitive) either an official abbreviated * day name in the current locale; a 3-or-more character abbreviation * of the full weekday; or "*", meaning any day. * Returns: -1 on invalid time pattern; 0 otherwise. */ char buf[MAX_T_FIELDLEN+1]; int hh, mm; int i, l; #ifdef HAVE_LOCALE_H if (*(weekday[0].name) == '\0') readtime_init(); #endif if (strlen(str) > sizeof(buf)-1) return Error(0, 0, "%t\n\tInvalid time <%s>\n", str); if (sscanf(str, "%d:%d/%s", &hh, &mm, buf) != 3) { mm = 0; if ( (sscanf(str, "%d:/%s", &hh, buf) != 2) && (sscanf(str, "%d/%s", &hh, buf) != 2) ) { return Error(0, 0, "%t\n\tInvalid time <%s>; format must be hh[:mm]/dayname\n", str); } } if (hh > 23 || hh < 0) return Error(0, 0, "%t\n\tInvalid time <%s> (invalid hr)\n", str); if (mm > 59 || mm < 0) return Error(0, 0, "%t\n\tInvalid time <%s> (invalid min)\n", str); *t = hh*60 + mm; /* The dayname must be a weekday, expressed in the current locale. */ strtolower(buf); for (i=0; i<7; i++) { if (strlen(buf) < 3) { ; /* not accepted -- must be at least three chars */ } else if (strncmp(weekday[i].name, buf, (l=strlen(buf))) == 0) { *d = i; break; } else if (strcmp(weekday[i].abbr, buf) == 0) { *d = i; break; } } if (i >= 7) return Error(0, 0, "%t\n\tInvalid time <%s> (invalid dayname)\n", str); return 0; } super-3.30.0/super.spec.in0000444000104100002640000000200610732537455013673 0ustar willspgSummary: safely execute scripts or other commands setuid-root Name: super Version: @version@ Release: 1 Copyright: GPL or "Artistic" Group: System/Base Source: ftp://www.ucolick.org/pub/users/will/super-@version@-tar.gz ### BuildRoot: /var/tmp/%{name}-buildroot %description Super(1) is a setuid-root program that offers restricted setuid-root access to executables, adjustable on a per-program and per-user basis. It provides a relatively secure environment for scripts, so that well-written scripts can be run as root (or some other uid/gid), without unduly compromising security. %prep %setup -q %build ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var/super make %install make DESTDIR=$RPM_BUILD_ROOT install %files %defattr(-,root,root) %doc README README.Y2K Artistic Copying WhatsNew %doc sample.cdmount sample.cdumount sample.tab %config /etc/super.tab /usr/bin/super /usr/bin/setuid /usr/man/man1/super.1* /usr/man/man5/super.5* %changelog * Tue Feb 12 2002 Will Deich Release 1 super-3.30.0/README0000444000104100002640000004752310732537455012151 0ustar willspgSuper(1) is a setuid-root program that offers o restricted setuid-root access to executables, adjustable on a per-program and per-user basis; o a relatively secure environment for scripts, so that well-written scripts can be run as root (or some other uid/gid), without unduly compromising security. Sample uses: - to call a script that allows users to use mount(8) on cdrom's or floppy disks, but not other devices. - to restrict which users, on which hosts, may execute a setuid-root program. - to call a script that allows users to send STOP/CONT signals to certain jobs, but not others. - to allow groups of trusted users (e.g. an "operator" group) complete root access to sets of selected commands such as, say, line-printer control commands, without giving away access to other commands, and with full logging of all commands used. -------------------- Copyright (c) 1993, 1994 by California Institute of Technology. Written by William Deich. Not derived from licensed software. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" (from Larry Wall). This program 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 either the GNU General Public License or the Artistic License for more details. You should have received a copy of the Artistic License with this Kit, in the file named "Artistic". If not, I'll be glad to provide one. You should also have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -------------------- Super and sudo I have received some enquiries regarding the difference between super and sudo, another program designed to give restricted access to certain commands. Sudo -- Sudo allows a permitted user to execute a command as the superuser. I think its central design philosophy is that each user can be trusted when executing certain commands. This is implemented by allowing each user to execute the restricted commands for which s/he is trusted, without giving access to other restricted commands. Super -- The design philosophy behind super is two-fold: (a) some users can be trusted when executing certain commands; (b) there are some commands, such as a script to mount CDROM's, which you'd like to be safely executable even by users who are NOT trusted. Although setuid-root scripts are insecure, a good setuid-root wrapper around a sensible non-setuid script can be hard to break, and super provides that wrapper so that even a non-trusted user can use the scripts. In my view, the main differences to the administrator and user are: (1) super provides a safe wrapper for scripts, so that a well-written script can be run safely by ordinary users without having to actually trust them. (2) super provides a simple symlink method for invoking "super"-ed commands without needing to explicitly type "super cmd..." (3) the files that specify valid user/command combinations have a different look and feel. (4) of course there are dozens of differences in details and in feature sets. Read the man pages of both and choose that which suits you better! ------------------- A low-volume mailing list for users of super has been set up by Martin Schulze (joey@infodrom.org): super@lists.infodrom.org To subscribe to this list, do one of the following: . send a mail to super-request@lists.infodrom.org with the word "subscribe" as subject or . send a mail to majordomo@lists.infodrom.org with the body of "subscribe super". The list will be archived publically at http://www.infodrom.org/Mail-Archive/ ------------------- A "super.tab" file names each command that super is willing to execute, and says who can use it. It contains lines like: CmdPattern fullpathname valid-user/group/host ed-type patterns e.g. # Example 1 cdmount /usr/local/bin/cdmount {harry,sally}@kaa tom@surya cdumount /usr/local/bin/cdumount {harry,sally}@kaa tom@surya # Example 2 cdmount::/usr/local/bin/cdmount cdumount::/usr/local/bin/cdumount \ {harry,sally}@kaa tom@surya # Example 3 {lp,lpstat,disable,enable,cancel} /usr/bin/* :operators # Example 4 /* * ReallyReallyTrustedUsers To execute a super command, type % super command [args...] If no command is given, super prints the commands that you are allowed to execute, but nothing is executed. The first example, above, shows a typical use for giving root access to scripts that mount/unmount a CD. It restricts access to users harry and sally on host kaa, and user tom on host surya. The second example shows an alternative form for Command/filename entry, allowing you to combine several command/filename pairs on a single control line. Generally, the notation Cmd1::File1 Cmd2::File2 [...] can be used instead of a line containing a single whitespace-separated filename entry. The third example illustrates the special meaning of an asterisk in the FullPathName: it is replaced with the user-entered command name. A valid user can type ``super disable some_printer''; super will replace the asterisk in "/usr/bin/*" with "disable" to form the command ``/usr/bin/disable some_printer''. The fourth example shows how the CmdPattern is treated as a pattern by super: the user's command is matched against the CmdPattern, and if it matches, the FullPath is executed. Here, the CmdPattern can be matched by any absolute pathname (note the leading slash to force only absolute paths to match); the FullPath is just an asterisk, and is therefore replaced by the user's typed absolute path. If you _completely_ trust some users, but want logging of all root actions, you could actually use this entry: a trusted user can now execute any command as root, by giving its full path to super. Each entry in the super.tab file can contain a variety of options, which include such things as setting the real uid and/or gid to something other than root, requiring the user's password before executing the command, and so on. If you were really going to give everything away as shown in the fourth example, above, you'd probably want to exclude any public-area workstations, require the trusted users to periodically give their passwords, and set the real uid=root (instead of just the effective uid), so the entry might be modified to read: /* * TrustedUsers !{PatternsOfPublicWorstations} \ auth=password timeout=5 uid=0 If a user is allowed to execute a given , the is exec'd, with as argv[0]. If the contains an asterisk, the asterisk is replaced by the typed before exec'ing. The superuser is always allowed to execute any super command. By default, the effective uid is set to 0 (root) before executing the command. Super logs every failed or successful attempt to execute commands. For security, the environment variables are discarded, save for TERM, LINES, and COLUMNS. If TERM contains any characters other than [a-z][A-Z][0-9]_+.:/-, it is discarded. If LINES or COLUMNS contains any characters other than [0-9], they are discarded. To these are added reasonable values for IFS, PATH, USER and HOME (USER and HOME are set to the username and login directory, respectively, of the real uid under which the command is executed by super). LOGNAME is set to the same as USER. SUPERCMD is set to the . ORIG_USER, ORIG_LOGNAME, and ORIG_HOME are set to the USER, LOGNAME, and HOME of the user who invoked super. All descriptors excepting 0,1,2 are closed. Signals are all reset to have default handling. -------------------- Acknowledgements This program uses the following extremely useful code from others: o Ozan Yigit's regex routines o Rich $alz's sh-style pattern-matching routines. o The BSD brace-expansion code. o Arnold Robbins (arnold@skeeve.atl.ga.us) PD implementation of hsearch.c. o Andrew Morgan (morgan@linux.kernel.org) misc_conv.c used for Solaris PAM. The following people contributed ideas, code, and/or fixes to various super versions (my apologies to anybody I've inadvertently left out): Olof Backing (obg@nada.kth.se) - reported bugs in super 3.5.1: logging lines without newlines, and the unexpected (and unwanted!) appearance of a path as argv[1]. - reported more bugs in super 3.7.2: comparing character to NULL instead of '\0'. Pedro Antonio Acebes Bayon (pacebes@cozuelos.tid.es) - noted failure to match some TERM patterns, logging error, portability problems. Boleslav Bobcik (xbobcik@informatics.muni.cz) - pointed out missing comment marks, duplicate .o entry, &c. David O'Brien (obrien@NUXI.com) - FreeBSD patches and other fixes. Max Buchheit (buchheit@ccrs.emr.ca) - provided Makefile entry + header #ifdef's for SGI v5.3. Steve Carney (carney@gvc.dec.com) - provided Makefile entries and patches for Digital UNIX V3.2. Valter V. Cavecchia (valter@itnsg1.cineca.it) - modifications for logging usage; suggested -h should show commands only valid for that user; inspired options for setting uid, gid, env, fd, extended SAFE_PATH. Dave Curry (davy@ecn.purdue.edu) - Changed super's logging to include the arguments passed to the command. Suggested testing shorter parts of FQDN when the hostname didn't match host pattern. Richard Czech (Richard.Czech@gmd.de) - discovered problems with multiple :global_options lines. Hadmut Danisch (hadmut@danisch.de) - discovered problem with argv0 vs argNNN option handling. Karen L Dickerson (kld@mudshark.sunquest.com). - supplied bugfix for incorrect denial of execution when pattern is `uuu:ggg' or `uuu:'. Gary Duncan (gduncan@penguin.pts.philips.oz.au) - beta-test sufferer in extremis. (ees1in@ee.surrey.ac.uk) - fix for checking TERM. Terje Eggestad (Terje.Eggestad@novit.no) - fixed bug failing to parse user:command properly when using per-user commands. - Noted declaration problem for AIX 4.x. Dmitry A. Fedorov (D.A.Fedorov@inp.nsk.su) - fixes for Makefile install rules and typo's in man pages. Christoph Geelen (geelen@rzulx1.mpie-duesseldorf.mpg.de) - provided Makefile entry for Ultrix 4.3. Oyvind Gjerstad (ogj@it.tollpost.no) - patches for running under TI's SysV 3.3. - pointed out errors in super.tab comment processing. H.C.den Harink (Harry@electron.ms.philips.nl) - group id fixes, Makefile fixes. Adam P. Harris (apharris@mcs.com) - reported bug when USE_NETGROUP is not defined and a hostname is used in the super.tab file. - pointed out that the copyright information should be improved. - sent notes about unused variables, etc (from gcc -pendantic). - added modifications to make gcc -Wall quieter. - provided a Linux Makefile entry. - maintains the super mailing list, provides a mirror ftp site, etc. Pete Holsberg (pjh@tecoma.mccc.edu) - provided Makefile entry for UnixWare 2.0. ISS-Xforce (iss-xforce@iss.net) - A group of people at ISS found a local root exploit in 3.11.6. Gordon Lack (gml4410@ggr.co.uk) - provided bugfix for IRIX 5, and general improvement: using close-on-exec rather than close() in buttonup(). - has pointed out various bugs in handling environment variables. - fixed problem with getpass()' input processing (ICANON setting). - fixed problem with Linux' handling of passwords. Geoffrey A. Lowney (Geoffrey.A.Lowney@Boeing.com) - provided bugfixes for debug initialization & help listing. - suggested the symlink hack (a la rsh). - suggested the -H / -h (long help / short help) option. - found an error with an appended dot to hostnames. - suggested the per-user $HOME/.supertab solution to user-offered cmds. Mark Meierjohann (mark_meierjohann@non.hp.com) - provided patch for HP-UX 11.0 with tcb. Keith Menard (menard@gateway.wtc.com) - ported to SCO 3.2v4. Clement Moulin (freebsd@simplerezo.com) - pointed out bug with new arg=xxx handling. - suggested making super quiet when an auth warning wasn't required. Pat Myrto (rwing!pat@rutgers.edu) - portability modifications. Edgar Nielsen - contributed a patch to fix part of the problem with Linux shadow password handling. Gabor Z. Papp (gzp@papp.hu) - reported problem with reference to get_pam() when building w/o pam. Steve Robbins (steve@cim.mcgill.ca) - adjusted hostname comparisons to be case-insensitive. - Substantial modifications to hostname matching to improve handling of netgroups. Morten Rolland ((Morten.Rolland@si.sintef.no) - pointed out security hole with lack of supplementary groups handling, and provided patch for same. - suggested the cd=dir option. - motivated the discussions that led to per-user super.tab files. Martin Schulze (joey@infodrom.north.de) - provided a Linux entry. - modified man page to be more consistent with Linux conventions. - provided a variety of patches. Michael Steffens (michael.steffens@hp.com) - fixed some missing returns; - discovered same ICANON problem as by Gordon Lack the month before. Sekure SDI (specifically, root@sekure.org) - reported a buffer overrun and supplied a patch. Gerry Singleton (Gerry.Singleton@canada.sun.com) - ported to Solaris 5.3. - key help in identifying the DNS vs NIS problem when appending dots in effort to get FQDN's. - a variety of other problems. Benoit Speckel (Benoit.Speckel@IReS.in2p3.fr) - supplied fix for error in checking -U option. Robert Luberda (robert@debian.org) - supplied patch for dumb syslog() calling bug. Jean-luc Szpyrka (jls@sophia.inria.fr) - inspired the addition of global user/group/host patterns and pattern negation (e.g. !user@xyz). - Changed super's logging to provide networked syslog messages: all super's syslog messages can be directed to a single host. - provided bugfix with -V option. Rein Tollevik (Rein.Tollevik@si.sintef.no) - provided patches for errors in processing options and symlinks under 3.9. - provided a variety of patches for 3.12.2, related to password reading, writing timestamp file, help printing, etc. Minh Tran (mtran@tnl.com.au) - provided code to handle HP-UX 10.20 when running with a Trusted Computing Base. Jukka A. Ukkonen (jau@iki.fi) - pointed out typo in syslog level conversion from string to number. Amar Vadlamudi (nath@src.umd.edu) - pointed out problems with network-wide logging, and workaround. Klaus Wacker (wacker@Physik.Uni-Dortmund.DE) - reported error with AIX configure script. Olle Wikstrom (olle@ericsson.se) - pointed out that I screwed up TERM checking yet again! Henrik Strom in your super.tab file, then typing % super ECHO arg1 arg2 arg3 2. You can use the -d option (debug), which will show you what super will do, but never actually execute a command: % super -d ECHO arg1 arg2 arg3 3. You can use the more verbose -D instead of -d. 4. You can use -F superfile, to cause super to read a different superfile and tell you what would happen. It won't actually execute any command, so this is a handy way of testing new super.tab files before you install them: % super -F newsuper.tab mynewcommand or % super -d -F newsuper.tab mynewcommand or % super -D -F newsuper.tab mynewcommand 5. Similar to the -F option, you can use -T hh:mm/dayname, to tell super to act as if the execution time is hh:mm/dayname (see super.5 for daynames), and thus let you check if a time restriction is working properly. You can use this with or without the -F option: % super [-d] [-D] [-F newsuper.tab] -T 13:30/tues mynewcommand -------------------- Notes on super scripts: 1. Scripts run via super(1) must start "#!/bin/sh" (or whatever interpreter is being used). 2. It's nice to be able to type something like % cdmount instead of % super cdmount You can make your script automatically invoke super on itself by starting a script in the following manner: #!/bin/sh prog=`basename $0` test "X$SUPERCMD" = "X$prog" || exec /usr/local/bin/super $prog ${1+"$@"} 3. Some variants of csh will not run setuid scripts unless the -b flag (force a "break" from option processing) is set. Generally, csh scripts should _always_ contain the -f flag on the exec line to prevent the .cshrc file from being sourced: #!/bin/csh -fb 4. Better still, avoid csh scripts entirely -- they are harder to write safely than Bourne-shell scripts. 5. Some programs need certain directories in the path. Your super scripts may have to add directories like /etc or /usr/etc to make commands work. (One common problem for SunOS 4.x users is that /usr/etc has to be in the path in order to mount HSFS-format cd-rom's.) 6. By default, super only changes the effective uid. Some programs (e.g. exportfs under SunOS 4.1.x) require the real uid to be root. In that case, either your super script will have to change the real uid to root before executing the command, or the super.tab file should set "uid=root". 7. A brief security comment: You must be exceedingly careful when writing scripts for super. A surprising variety of seemingly-ordinary commands can, when run setuid-root, be exploited to nasty purpose. Always make your scripts do as little as possible, and give the user as few options as possible. Think twice about side-effects and alternative uses of these scripts. For instance, you might write a script to allow users to mount cd-rom's by executing mount(8). But if you don't write it carefully, a user could mount a floppy disk containing, say, a setuid-root shell. Be leery of using "env=var,..." to increase the list of preserved environment variables -- some programs can be tricked into executing commands embedded in certain environment variables. -------------------- William Deich UCO / Lick Observatory | Internet: will@ucolick.org University of California | Phone: (831) 459-3913 Santa Cruz, CA 95064 | Fax: (831) 459-2298 super-3.30.0/INSTALL.notes0000444000104100002640000000360410732537455013441 0ustar willspg############################################################################# ## Older versions of super 3.x have been built using the setups shown ## ## below. They may be useful guides to you in adapting super to your ## ## system: first run ./configure; then make; then, if super doesn't build ## ## properly, see if you need some of the flags below. ## ############################################################################# # AIX: # CONFIG_FLAGS= -DSYSLOG_PRIORITY='((17<<3)+4)' # CC=cc # CFLAGS= -O $(CONFIG_FLAGS) # Clix 3.1 r.7.1.3 (Intergraph) # CC=cc # CFLAGS= -O # Digital UNIX # (known as DEC OSF/1 prior to Digital UNIX V3.2) # # If you are running V2.0 to V3.2, and you have the DEC C # compiler installed, you should add -migrate to CFLAGS. # CC=cc # CFLAGS= -std -migrate # or # CFLAGS= -std # HP-UX 9.01: # CONFIG_FLAGS= -DSYSLOG_PRIORITY='((17<<3)+4)' # Note: unpatched HP-UX 9.01 c89 has a bug, so that compiling with -O # doesn't work. Patched version is OK. # CC=c89 # CFLAGS= -g -Aa $(CONFIG_FLAGS) # IRIX v4.0.5: # CC=cc # CFLAGS= -O $(CONFIG_FLAGS) # Linux v1.2: # CONFIG_FLAGS= \ # -DSAFE_PATH=\"/bin:/usr/bin\" \ # -DSYSLOG_FACILITY=LOG_AUTH \ # -DSYSLOG_PRIORITY=LOG_INFO \ # CC=gcc # CFLAGS= -O2 # SCO 3.2v4 # CC=cc # CFLAGS= -O $(CONFIG_FLAGS) # # Solaris 2.2, 2.3; SunOS 5.2, 5.3, gcc: # CC=gcc # CFLAGS= -O $(CONFIG_FLAGS) # Solaris 2.4; SunOS 5.4, gcc 2.7.1: # CC=gcc # CFLAGS= -O $(CONFIG_FLAGS) # Solaris 2.4; SunOS 5.4; Sun 3.0.1 C compiler: # CC=??? (sorry, don't know its name) # CFLAGS= -O -Xc -DSUNOS5_4 -D_POSIX_C_SOURCE -D__EXTENSIONS__ $(CONFIG_FLAGS) # SunOS 4.1.3: # CC=gcc # CFLAGS= -O $(CONFIG_FLAGS) # TI SYS V 3.3: # CC=gcc # CFLAGS=-O $(CONFIG_FLAGS) -traditional # Ultrix V4.3A # CC=cc # CFLAGS= -g3 -O $(CONFIG_FLAGS) # UnixWare 2.0: # CC=cc # CFLAGS= -O # LDFLAGS= -L/usr/ucblib # LDLIBS= -lgen -lcrypt -lucb super-3.30.0/utils.c0000444000104100002640000015223310732537455012570 0ustar willspgstatic const char rcsid[] = "$Id: utils.c,v 1.157 2007/03/07 14:48:15 will Exp $"; #include "super.h" /* Variables table flag -- !0 means has been created */ static int created_variables_table = 0; /* an expandable input buffer */ struct Ebuf { char *buf; int l; int nalloc; }; /* checksize of Ebuf; grow an Ebuf */ static char *checksize P__((struct Ebuf *cb, int N)); static char *grow P__((struct Ebuf *cb, int N)); /* The input, cleaned input, and variable expansion buffers */ static struct Ebuf ebuf = { NULL, 0, 0 }; static struct Ebuf ebuf_clean = { NULL, 0, 0 }; static struct Ebuf variablebuf = { NULL, 0, 0 }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get environment variable */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * Getenv(s) char *s; { /* Like getenv(), but returns ptr to the in "name=xxxx", * not just the xxxx. */ char **envp; int l; extern char **environ; if (!s) return (char *) NULL; l = strlen(s); for (envp=environ; *envp ; envp++) if (strncmp(*envp, s, l) == 0 && *(*envp+l) == '=') return *envp; return (char *) NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get login directory of a user */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int getlogdir(user, buf) char *user; char *buf; { /* Gets the login directory of the named user, and puts it into buf. * The "user" argument can either be a username or a uid in text form. * If user==NULL || *user == '\0', the current user is obtained. * Best if buf is MAXPATHLEN long. * 0 is returned on success; -1 on error. */ struct passwd *pass; buf[0] = '\0'; if (user != NULL && *user != '\0') { /* Name or uid given; use getpwentry */ pass = getpwentry(1, user); } else { /* No user given; use current uid */ pass = getpwuid(userinfo.orig_uid); } if (pass == (struct passwd *) NULL) return -1; (void) strcpy(buf, pass->pw_dir); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Convert string to syslog priority code */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int read_syslogcode(s, code) char *s; int *code; { /* * Takes a string like "LOG_WARNING | LOG_AUTH", and returns the * corresponding syslog numeric value in *code. * The leading "LOG_" is optional, as is the case, and the separator * can be any combination of space, dot, and |. Thus the following * are equivalent: * LOG_WARNING | LOG_AUTH * warning.auth * Returns: * 0 on success; * -1 on error, with error message to Error(). * * In s, the valid code separators are: whitespace, '.' and/or "|". * */ char *word, *xword; char *sep = " \t|."; char *p, *new_s; if (!(new_s = strdup(s))) { return Error(0, 0, "Failed to malloc space for copy of s=<%s>\n", s); } for (p = new_s; *p; p++) { if (islower(*p)) { *p = toupper(*p); } } *code = 0; for (word = strtok(new_s, sep); word; word = strtok(NULL, sep)) { if (!word) { continue; /* ignore empty field */ } if (strncmp(word, "LOG_", 4) == 0) { xword = word + 4; /* ignore leading LOG_ */ } else { xword = word; /* there is no leading LOG_ */ } if (0) { /* placeholder */ /* * ********** * Facilities * ********** */ #ifdef LOG_AUTH } else if (strcmp(xword, "AUTH") == 0) { *code |= LOG_AUTH; #endif #ifdef LOG_AUTHPRIV } else if (strcmp(xword, "AUTHPRIV") == 0) { *code |= LOG_AUTHPRIV; #endif #ifdef LOG_CRON } else if (strcmp(xword, "CRON") == 0) { *code |= LOG_CRON; #endif #ifdef LOG_DAEMON } else if (strcmp(xword, "DAEMON") == 0) { *code |= LOG_DAEMON; #endif #ifdef LOG_KERN } else if (strcmp(xword, "KERN") == 0) { *code |= LOG_KERN; #endif #ifdef LOG_LOCAL0 } else if (strcmp(xword, "LOCAL0") == 0) { *code |= LOG_LOCAL0; #endif #ifdef LOG_LOCAL1 } else if (strcmp(xword, "LOCAL1") == 0) { *code |= LOG_LOCAL1; #endif #ifdef LOG_LOCAL2 } else if (strcmp(xword, "LOCAL2") == 0) { *code |= LOG_LOCAL2; #endif #ifdef LOG_LOCAL3 } else if (strcmp(xword, "LOCAL3") == 0) { *code |= LOG_LOCAL3; #endif #ifdef LOG_LOCAL4 } else if (strcmp(xword, "LOCAL4") == 0) { *code |= LOG_LOCAL4; #endif #ifdef LOG_LOCAL5 } else if (strcmp(xword, "LOCAL5") == 0) { *code |= LOG_LOCAL5; #endif #ifdef LOG_LOCAL6 } else if (strcmp(xword, "LOCAL6") == 0) { *code |= LOG_LOCAL6; #endif #ifdef LOG_LOCAL7 } else if (strcmp(xword, "LOCAL7") == 0) { *code |= LOG_LOCAL7; #endif #ifdef LOG_LPR } else if (strcmp(xword, "LPR") == 0) { *code |= LOG_LPR; #endif #ifdef LOG_MAIL } else if (strcmp(xword, "MAIL") == 0) { *code |= LOG_MAIL; #endif #ifdef LOG_NEWS } else if (strcmp(xword, "NEWS") == 0) { *code |= LOG_NEWS; #endif #ifdef LOG_RFS } else if (strcmp(xword, "RFS") == 0) { *code |= LOG_RFS; #endif #ifdef LOG_USER } else if (strcmp(xword, "USER") == 0) { *code |= LOG_USER; #endif #ifdef LOG_UUCP } else if (strcmp(xword, "UUCP") == 0) { *code |= LOG_UUCP; #endif /* * ****** * Levels * ****** */ #ifdef LOG_ALERT } else if (strcmp(xword, "ALERT") == 0) { *code |= LOG_ALERT; #endif #ifdef LOG_CRIT } else if (strcmp(xword, "CRIT") == 0) { *code |= LOG_CRIT; #endif #ifdef LOG_DEBUG } else if (strcmp(xword, "DEBUG") == 0) { *code |= LOG_DEBUG; #endif #ifdef LOG_EMERG } else if (strcmp(xword, "EMERG") == 0) { *code |= LOG_EMERG; #endif #ifdef LOG_ERR } else if (strcmp(xword, "ERR") == 0) { *code |= LOG_ERR; #endif #ifdef LOG_INFO } else if (strcmp(xword, "INFO") == 0) { *code |= LOG_INFO; #endif #ifdef LOG_NOTICE } else if (strcmp(xword, "NOTICE") == 0) { *code |= LOG_NOTICE; #endif #ifdef LOG_WARNING } else if (strcmp(xword, "WARNING") == 0) { *code |= LOG_WARNING; #endif } else { free(new_s); return Error(0, 0, "%t\n\tUnknown syslog code <%s>\n", word); } } free(new_s); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copies in to out, prefixing with "^" and suffixing with "$" * if these are missing. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void anchor(in, out) char *in; char *out; { void re_anchor P__((char *, char *)); if (need_re_anchor) re_anchor(in, out); else (void) strcpy(out, in); } void re_anchor(in, out) char *in; char *out; { int i; i = (*in != '^'); if (i) out[0] = '^'; (void) strcpy(out+i, in); i = strlen(out); if (out[i-1] != '$') out[i++] = '$'; out[i] = '\0'; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Grow an expandable buffer */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static char * grow(cb, nb) struct Ebuf *cb; int nb; /* amount to grow, bytes */ { if (cb->buf) cb->buf = realloc(cb->buf, cb->nalloc += nb); else cb->buf = malloc(cb->nalloc += nb); return cb->buf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Grow buffer if less than N bytes free */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static char * checksize(cb, N) struct Ebuf *cb; int N; { if (cb->nalloc - cb->l < N) return grow(cb, 2*N); else return cb->buf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Check if string s1 ends with string s2 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char *ends(s1, s2) char *s1, *s2; /* If s1 ends with string s2, a pointer to the ending of s1 is returned; * else null */ { int l1, l2; l1 = strlen(s1); l2 = strlen(s2); if (l1 < l2) return NULL; else if (strcmp(s1+l1-l2, s2) == 0) return s1+l1-l2; else return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copy the input buffer to outbuf (default clean_buf), * cleaning out comments and the backslash-newline-whitespace parts; the * latter become plain whitespace if the backslash is preceded by letter, * digit, or underscore; otherwise, they are deleted. * Comments are also deleted. * Return a ptr to the string in the cleaned buffer. * Returns null pointer on malloc error. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * clean_buf(buf, outbuf) char *buf; /* input buffer */ char *outbuf; /* output buffer; NULL means to use the * ebuf_clean buffer. If non-null, you must make * sure it's >= buf in size. */ { register char *s, *t; char inquote = '\0'; if (outbuf) { t = outbuf; } else { if (!(t = outbuf = checksize(&ebuf_clean, ebuf.nalloc))) { Error(1, 0, "%t\n\tFailed to malloc space for clean copy of input text\n"); return NULL; } } /* Copy s (input buffer) to t (clean input buffer); * delete comments, delete backslash-newline-whitespace * or replace w/ ' ' */ for (s = buf; *s; ) { /* Assert not in comment */ if (*s == '\\' && *(s+1) == '\n') { /* At continued line; skip over backslash-newline-whitespace; * make it a blank if following digit,letter,_ . */ if ( (s > buf) && (isalnum(*(s-1)) || *(s-1) == '_') ) *t++ = ' '; s += 2; while (isspace(*s)) s++; /* s has been left positioned at next character to process */ } else if (inquote) { /* In a quote */ if (*s == inquote) { /* end of quote */ inquote = '\0'; } *t++ = *s++; } else if (my_qm[*(unsigned char *)s]) { /* Begin quote */ inquote = *t++ = *s++; } else if (my_cc[*(unsigned char *)s]) { /* Begin comment; skip over until EOL */ char last_noncmt = (s > buf) ? *(s-1) : '\0'; while (*s && *s != '\n') s++; if (*s && *(s-1) == '\\') { /* At continued line. Ignore comment part, and * look at last non-comment char before * backslash-newline-whitespace; then process as above. */ if ( (s > buf) && (isalnum(last_noncmt) || last_noncmt == '_') ) *t++ = ' '; s++; while (isspace(*s)) s++; } /* s has been left positioned at next character to process */ } else { /* Ordinary character */ *t++ = *s++; /* s has been left positioned at next character to process */ } } *t = '\0'; return outbuf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Do fgets to get one logical line: join lines that are terminated * with backslash-newline. Don't discard backslash or newline (so that * we can print the exact text, if desired). * The result is stored in "ebuf" and a pointer to the string * is returned. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * fillbuffer(fp, all_indented, nl) FILE *fp; int *all_indented; /* Returned !0 if continued lines are all indented */ int *nl; /* Returned with number of lines read in */ { char c, *s; ebuf.l = 0; /* clear the extensible buffer */ /* Collect lines until we have a non-zero buffer (which happens with * the first line, of course) and it isn't terminated "\\\n". */ if (nl) *nl = 0; *all_indented = 1; UNTIL(ebuf.l && !(s=ends(ebuf.buf, "\\\n"))) { if (!checksize(&ebuf, 1024)) { /* Needed to, but couldn't increase the allocated space */ return NULL; } if (!fgets(ebuf.buf+ebuf.l, ebuf.nalloc - ebuf.l, fp)) return NULL; c = *(ebuf.buf + ebuf.l) ; if (nl) (*nl)++; if (ebuf.l != 0 && !(isspace(c) || c == '#')) { /* Continued line not indented. */ *all_indented = 0; } ebuf.l += strlen(ebuf.buf+ebuf.l); } return ebuf.buf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Open a file; chain it to the previous opened list. * Returns NULL pointer on malloc error, stat error, fopen error, * ownership error, etc. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ FileList * file_open(parent, name, allow_missing, req_uid, req_gid) FileList *parent; /* null if this is head file */ char *name; /* file to open */ int allow_missing; /* silently ignore missing files if parent != null. */ uid_t *req_uid; /* NULL if default, else ptr to required uid */ gid_t *req_gid; /* NULL if default, else ptr to required gid; * this group is also allowed write permission. */ { char *s; FileList *fl; struct stat st; struct passwd *pass; int orig_uid, euid; fl = (FileList *) malloc(sizeof(FileList)); if (!fl) { Error(0, 0, "%tFailed to malloc list member space for include file <%s>\n", name); return NULL; } if (!(fl->givenname = malloc(strlen(name)+1)) ) { Error(0, 0, "%tFailed to malloc space for filename <%s>\n", name); return NULL; } strcpy(fl->givenname, name); if (*name != '/' && parent != NULL) { /* it must be relative to the superfile directory */ int l1, l2; s = strrchr(superfile, '/'); if (s) { l1 = s + 1 - superfile; l2 = strlen(name); if (!(fl->fullname = malloc(l1+l2+1)) ) { Error(0, 0, "%tFailed to malloc space for expanded filename of <%s>\n", name); return NULL; } sprintf(fl->fullname, "%.*s%s", l1, superfile, (strncmp("./", name, 2) == 0) ? name+2 : name); } else { fl->fullname = fl->givenname; } } else { /* accept the name as is */ fl->fullname = fl->givenname; } if (debug) { if (parent == NULL) { fprintf(stderr, "\tOpening file %s\n", fl->fullname); } else { fprintf(stderr, "\tLine %d: opening include file %s\n", parent->line, fl->fullname); } } /* * Handle missing-file case. */ if (stat(fl->fullname, &st) == -1) { if (errno == ENOENT && allow_missing) { if (debug) fprintf(stderr, "\tIgnoring missing file %s\n", fl->fullname); } else { Error(1, 0, "Couldn't stat super.tab %sfile `%s': ", parent == NULL ? "" : "include ", fl->fullname); } if (fl->fullname != fl->givenname) free(fl->fullname); free(fl->givenname); free(fl); if (errno == ENOENT && allow_missing) { return parent; } else { return NULL; } } /* * Check file write permissions. */ if (st.st_mode & S_IWOTH) { /* * World-writable is never ok. */ Error(0, 0, "super.tab %sfile `%s' is world-writable. Bailing out.\n", parent == NULL ? "" : "include ", fl->fullname); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would have quit here.\n"); } else { return NULL; } } else if (!req_gid && (st.st_mode & S_IWGRP)) { /* * No group was specified, but it's group-writable! */ Error(0, 0, "super.tab %sfile `%s' is group-writable. Bailing out.\n", parent == NULL ? "" : "include ", fl->fullname); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would have quit here.\n"); } else { return NULL; } } if (!parent) { /* This is the master file. Extract its owner's name for use * in the SUPER_OWNER variable. */ pass = getpwuid(st.st_uid); if (!pass) { Error(0, 0, "%t\n\tSuper.tab file `%s' owner uid is %d, \ which has not passwd entry!\n", fl->fullname, st.st_uid); return NULL; } if (add_variable("SUPER_OWNER", pass->pw_name) == -1) return NULL; if (add_variable("SUPER_HOME", pass->pw_dir) == -1) return NULL; } /* * Check file ownership. */ euid = geteuid(); orig_uid = userinfo.orig_uid; if (req_uid && req_gid) { /* * File's uid/gid must match the required uid/gid. */ if (st.st_uid != *req_uid || st.st_gid != *req_gid) { Error(0, 0, "super.tab %sfile `%s' needs to have (uid=%d, \ gid=%d), but is uid=%d, gid=%d\n", parent == NULL ? "" : "include ", fl->fullname, *req_uid, *req_gid, st.st_uid, st.st_gid); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would quit here.\n"); } else { return NULL; } } } else if (req_uid) { /* * File's uid must match the required uid. */ if (st.st_uid != *req_uid) { Error(0, 0, "super.tab %sfile `%s' needs to have uid=%d, but has uid=%d\n", parent == NULL ? "" : "include ", fl->fullname, *req_uid, st.st_uid); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would quit here.\n"); } else { return NULL; } } } else if (req_gid) { /* * File's gid must match the required gid. */ if (st.st_gid != *req_gid) { Error(0, 0, "super.tab %sfile `%s' needs to have gid=%d, but has gid=%d\n", parent == NULL ? "" : "include ", fl->fullname, *req_gid, st.st_gid); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would quit here.\n"); } else { return NULL; } } } else if (euid == 0 || orig_uid == 0) { /* Being run by root, using default rules: the super.tab file * must be owned by root. */ if (st.st_uid != 0) { Error(0, 0, "super.tab %sfile `%s' isn't owned by root, \n\ \tbut we are being run as or by root. Bailing out.\n", parent == NULL ? "" : "include ", fl->fullname); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would have quit here.\n"); } else { return NULL; } } } else if (orig_uid != userinfo.caller.pw_uid) { /* * Real uid has changed -- this happens when the command is * like "user:somecommand", in which case the file's owner * had better be "user". * */ if (st.st_uid != orig_uid) { Error(0, 0, "super.tab %sfile `%s' isn't owned by uid %d.\n", parent == NULL ? "" : "include ", fl->fullname, orig_uid); if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, super would quit here.\n"); } else { return NULL; } } } if ((fl->fp = fopen(fl->fullname, "r")) == NULL) { Error(1, 0, "%t\n\tCouldn't open super.tab %sfile `%s': ", parent == NULL ? "" : "include ", fl->fullname); return NULL; } fl->line = 1; fl->nl = 0; fl->prev = parent; return fl; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Close a file; return previous in list, or NULL when all done */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ FileList * file_close(curr) FileList *curr; { FileList *parent; if (!curr) return (FileList *) NULL; parent = curr->prev; if (debug) { fprintf(stderr, "\tClosing %sfile %s.\n", parent == NULL ? "" : "include ", curr->fullname); if (parent) fprintf(stderr, "\tReturning to %s file %s, line %d\n", parent->prev == NULL ? "top-level" : "include ", parent->fullname, parent->line); } fclose(curr->fp); if (curr->fullname != curr->givenname) free(curr->fullname); free(curr->givenname); free(curr); return parent; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Initialize an StrArray */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void StrInit(a) StrArray *a; { a->n = 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get address of string element of StrArray */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * StrEltGetPtr(a, ielt) StrArray *a; /* StrArray with element of interest */ int ielt; /* Element to return */ /* Returns NULL if no such element (or if unused) */ { if (ielt >= 0 && ielt < a->n && a->str[ielt].used) return a->str[ielt].s; else return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Put string into element of StrArray. * Returns -1 on malloc/realloc failure, 0 otherwise. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int StrEltCpy(a, ielt, str) StrArray *a; /* StrArray with element to fill */ int ielt; /* Element to be filled */ char *str; /* what to put into ielt'th place; if NULL, elt is "unused". */ { int l; l = (str) ? strlen(str) : 0; if (StrNalloc(a, ielt) == -1) return -1; a->str[ielt].used = 1; if (a->str[ielt].n == 0) { a->str[ielt].s = malloc(l+1); } else if (a->str[ielt].n < l+1) { a->str[ielt].s = realloc(a->str[ielt].s, l+1); a->str[ielt].n = l+1; } if (!a->str[ielt].s) { a->str[ielt].n = 0; return -1; } if (str) { strcpy(a->str[ielt].s, str ? str : ""); } else { a->str[ielt].used = 0; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns number of elements of StrArray */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int StrNElts(a) StrArray *a; { return a->n; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Return last index of in-use elements of StrArray */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int StrLastInUse(a) StrArray *a; { int i; int last; for (i=0, last = -1; i < a->n; i++) { if (a->str[i].n && a->str[i].used) last = i; } return last; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Marks all elements of StrArray as unused */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void StrEltsUnused(a) StrArray *a; { int i; for (i=0; i < a->n; i++) a->str[i].used = 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Makes StrArray large enough to have an ielt'th element. * Returns -1 on malloc/realloc failure, 0 otherwise. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int StrNalloc(a, ielt) StrArray *a; /* StrArray that must have an ielt'th element */ int ielt; { int i; if (ielt >= a->n) { /* Have to increase the new space */ unsigned int new_n; if (a->n == 0) { new_n = (ielt < 4) ? 4 : 2*ielt ; a->str = (CountedString *) malloc(sizeof(CountedString) * new_n); } else { new_n = 2*ielt; a->str = (CountedString *) realloc((void *) a->str, sizeof(CountedString) * new_n); } if (!a->str) return -1; for (i=a->n; i < new_n; i++) a->str[i].n = 0; a->n = new_n; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copy StrArray src to StrArray dst, starting at element src_ielt * in the src array, and at element dst_ielt in the dst array; * copy nelt elements. * If there are fewer than (src_ielt + nelt) elements, silently stop * copying at the end of the src array. * Returns -1 on malloc/realloc failure, 0 otherwise. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int StrBulkCpy(dst, dst_ielt, src, src_ielt, nelt) StrArray *dst; /* dstination array */ int dst_ielt; /* starting element to fill */ StrArray *src; /* sourced array */ int src_ielt; /* starting element to copy from */ int nelt; /* number of elements to copy */ { int i; char *s; if ((nelt + src_ielt) > StrNElts(src)) { /* not that many src elements */ nelt = StrNElts(src) - src_ielt; } /* make sure dst has enough space */ if (StrNalloc(dst, (dst_ielt + nelt)) != 0) { return -1; /* can't make dst sufficiently large! */ } for (i = 0; i < nelt; i++) { s = StrEltGetPtr(src, i + src_ielt); if (StrEltCpy(dst, i + dst_ielt, s) != 0) { return -1; /* copy failed */ } } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Free everything in an ArgRangePat list. * Don't free the pointer to the head. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void ARfree( ArgRangePat *head) { ArgRangePat *arp, *next; if (!head) { return; } for (arp = head->next ; arp; arp = next) { next = arp->next; if (arp->pat) { free(arp->pat); } free(arp); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Insert a new string at the head of an arglist. * Return 0 on success, -1 on malloc failure. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int ARinsert( ArgRangePat *head, int arg1, int arg2, char *pat) { ArgRangePat *arp; arp = malloc(sizeof(ArgRangePat)); if (!arp) { return -1; } arp->pat = malloc(strlen(pat)+1); if (!arp->pat) { return -1; } strcpy(arp->pat, pat); arp->arg1 = arg1; arp->arg2 = arg2; arp->next = head->next; head->next = arp; return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Walk an ArgRangePat list, finding the next pattern that applies * to the iarg'th argument. If the start'th argument applies, * return it. Stop if we reach an empty pattern. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ArgRangePat * ARnext( ArgRangePat *start, int iarg) { ArgRangePat *arp; for (arp=start; arp; arp = arp->next) { if (!arp->pat || !arp->pat[0]) { /* Stop if pattern is empty */ return NULL; } else if (arp->arg1 <= iarg && iarg <= arp->arg2) { return arp; } } /* input was null ptr, or ran out of list */ return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copy up to n-1 characters into "to"; then null-terminate. * Return 1 if all characters fitted into "to", else return 0. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int stringcopy(to, from, n) char *to; /* buffer to copy into */ char *from; /* string to copy */ int n; /* size of to buffer */ { int l = strlen(from); if (l >= n) { strncpy(to, from, n-1); to[n-1] = '\0'; return 0; } else { strcpy(to, from); return 1; } /* NOTREACHED */ } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Opens the logfile. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void opensuperlog() { extern FILE *error_logfile; /* to tell Error() where the log is */ close_writer(); /* in case there is already one running */ if (debug || it_came_from_cmdline) { Error(0, 0, "If this weren't debug mode, \ super would try to open as log file \"%.500s\"\n", globalinfo.log.filename); return; } if (*globalinfo.log.filename == '\0') { Error(0, 0, "opensuperlog(): logfile name is (nil)\n"); return; } globalinfo.log.fp = open_writer(globalinfo.log.user, globalinfo.log.filename, &globalinfo.log.pid); error_logfile = globalinfo.log.fp; /* ...so Error() writes here too */ return; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* In order to implement the loguser=xxx option, we (1) create a pipe, * (2) fork, in the child setuid to loguid; (3) child opens logfile; * (4) child copies from pipe to logfile. Meanwhile, we return a pointer * to a stream to the pipe as the log stream seen by the parent program. * This allows us to implement a special uid for the logfile writer, * without needing the operating system to offer saved uid's or * interprocess file-descriptor passing, etc. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ FILE * open_writer(user, filename, pid_p) char *user; char *filename; pid_t *pid_p; /* filled with pid of created logger */ { FILE *fp = NULL; int fildes[2]; pid_t child; if (pipe(fildes) == -1) { (void) Error(1, 0, "Failed to created pipe for logfile; no logging: "); return NULL; } child = fork(); if (child == -1) { (void) Error(1, 0, "Failed to create child for logfile; no logging: "); return NULL; } else if (child > 0) { /* In parent -- close read side, and aim logstream at write side */ if (pid_p) *pid_p = child; (void) close(fildes[0]); if (!(fp = fdopen(fildes[1], "w"))) { (void) Error(1, 0, "failed to fdopen logfile pipe writer; no logging: "); (void) close(fildes[1]); return NULL; } } else if (child == 0) { /* In child. Open log file and copy from pipe to log. */ FILE *input; char text[2000]; (void) close(fildes[1]); if (!(input = fdopen(fildes[0], "r"))) { (void) Error(1, 0, "failed to fdopen logfile pipe reader; no logging: "); (void) close(fildes[1]); exit(1); } if (user && *user != '\0') { stringcopy(localinfo.user, user, sizeof(localinfo.user)); *localinfo.euser = '\0'; *localinfo.egroup = '\0'; *localinfo.group = '\0'; *localinfo.u_g = '\0'; if (set_u_g() == -1) { (void) Error(1, 0, "failed to setuid %s before opening logfile; no logging: ", globalinfo.log.user); exit(1); } } if (!(fp = fopen(globalinfo.log.filename, "a"))) { if (user && *user != '\0') (void) Error(1, 0, "failed to open logfile `%s' using uid `%s': ", globalinfo.log.filename, localinfo.user); else (void) Error(1, 0, "failed to open logfile `%s': ", globalinfo.log.filename); exit(1); } while (fgets(text, sizeof(text), input)) { if (fputs(text, fp) == EOF) (void) Error(1, 0, "fputs to logfile failed: "); } (void) fclose(fp); exit(0); } return fp; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Closes the logfile stream, then calls wait(). */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void close_writer() { pid_t pid; if (!globalinfo.log.fp && globalinfo.log.pid == -1) return; if (globalinfo.log.fp) { if (fclose(globalinfo.log.fp) == EOF) Error(1, 0, "failed to close globalinfo.log.fp: "); globalinfo.log.fp = NULL; } if (globalinfo.log.pid != -1) { while ((pid = wait((int *) NULL)) > 0 && pid != globalinfo.log.pid) { Error(0, 0, "wait() surprised! close_writer() received pid %d;\n\t\ expected logger pid = %d; waiting for correct pid...\n", pid, globalinfo.log.pid); } if (pid == -1) Error(1, 0, "while waiting for logger process to exit"); globalinfo.log.pid = -1; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Construct a host-unique directory name: * xyz.home.caltech.edu -> prefix/xyz.home.caltech.edu/user * If hostname is empty string, file is prefix/user. * WARNING: the hostname used is that from gethostname(). * Note that this is not necessarily unique across * internet domains, since it is frequently not a * fully-qualified domain name. Therefore you should NOT * share the timestamp directory outside the local domain. * * *err is returned with an errno value, if there was an error * for which there's a relevant errno. Otherwise it's set to 0. * * If msgbuf is non-null pointer, then it's *assumed* long enough * for error message (1000 chars is enough), and error messages * are printed into it; otherwise, error messages are Error()'d. * */ /* returns NULL on error, constructed path otherwise */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * makedirname(prefix, hostname, file, err, msgbuf) char *prefix, *hostname, *file; int *err; char *msgbuf; { int l; char *s, str[MAXPATHLEN]; *err = 0; l = strlen(prefix) + 1 + strlen(hostname) + 1; if (l >= MAXPATHLEN) { if (msgbuf) { sprintf(msgbuf, "Can't create directory <%.500s...>: it would exceed MAXPATHLEN = %d\n", prefix, MAXPATHLEN); } else { Error(0, 0, "Can't create directory <%.500s...>: it would exceed MAXPATHLEN = %d\n", prefix, MAXPATHLEN); } return NULL; } strcpy(file, prefix); if (!*hostname) return file; #ifndef HAVE_LONG_FILE_NAMES strncpy(str, hostname, 14); str[14] = '\0'; /* in case exactly 14 chars were copied */ #else strcpy(str, hostname); #endif for (s = strrchr(str, '.'); s; *s = '\0', s = strrchr(str, '.')) { strcat(file, "/"); strcat(file, s+1); } strcat(file, "/"); strcat(file, str); return file; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Creates a directory, including any needed directories leading * to it. Returns -1 on stat/mkdir failure; 0 otherwise. * WARNING: doesn't check if final component is a directory. * * *err is returned with an errno value, if there was an error * for which there's a relevant errno. Otherwise it's set to 0. * * If msgbuf is non-null pointer, then it's *assumed* long enough * for error message (1000 chars is enough), and error messages * are printed into it (without the following perror() value, which * should be added later; otherwise, error messages are Error()'d. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int makedir(dir, err, msgbuf) char *dir; /* path with directories only. */ int *err; char *msgbuf; { static struct stat st; char *q; char path[MAXPATHLEN]; *err = errno; /* First create directories along way, if necessary */ strcpy(path, dir); for (q=path; q && *q; ) { /* skip leading slashes */ while (*q == '/') q++; /* check directory before next slash */ q = strchr(q, '/'); if (q) *q = '\0'; /* Stat directory; if missing, create it */ if (stat(path, &st) != 0) { if (errno != ENOENT) { *err = errno; if (msgbuf) { sprintf(msgbuf, "Failed to stat directory <%.500s>: ", path); } else { Error(1, 0, "Failed to stat directory <%.500s>: ", path); } return -1; } else if (mkdir(path, 0700) != 0) { *err = errno; if (msgbuf) { sprintf(msgbuf, "Failed to create directory <%.500s>: ", path); } else { Error(1, 0, "Failed to create directory <%.500s>: ", path); } return -1; } } /* Restore slash */ if (q) *q = '/'; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Adds a variable definition. * Returns 0 on success, -1 on error. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int add_variable(varname, vardefn) char *varname; char *vardefn; { /* * Allocate space for varname, vardefn, and insert into * vars table. */ ENTRY item, *found_item; char *keyspace, *dataspace; int ln = strlen(varname); int lb = strlen(vardefn); if (!created_variables_table) { if (!s_hcreate(HS_VARS, 1000)) return Error(0, 0, "%tCouldn't allocate hash table for variable processing\n"); created_variables_table = 1; } if (debug > 1) fprintf(stderr, "entering add_variable(\"%s\",\"%s\")\n", varname, vardefn); keyspace = malloc(ln+1); dataspace = malloc(lb+1); if (!keyspace || !dataspace) { return Error(0, 0, "%tFailed to allocate space for definition of variable `%s'\n", varname); } item.key = keyspace; item.data = dataspace; strcpy(item.key, varname); strcpy(item.data, vardefn); if (debug > 1) fprintf(stderr, "Adding variable `%s' = `%s'\n", item.key, item.data); /* Delete the existing value, if any */ if ((found_item = s_hsearch(HS_VARS, item, FIND))) { /* Assume all data allocated via malloc() */ free(found_item->data); found_item->data = NULL; } if (!s_hsearch(HS_VARS, item, ENTER)) return Error(0, 0, "%tFailed to allocate space for hash-table entry for variable `%s'\n", varname); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Add sysinfo(2) items as variables. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int add_sysinfo_variables() { char buf[500]; /* silly gimmick: define a variable using empty buf[] instead of "", * so that gcc -Wall doesn't complain if buf isn't used in at least * one of the ifdef'd regions, below. */ buf[0] = '\0'; add_variable("SI_ARCHITECTURE", buf); #ifdef HAVE_SYSINFO #ifdef SI_ARCHITECTURE if (sysinfo(SI_ARCHITECTURE, buf, sizeof(buf)) != -1) { if (add_variable("SI_ARCHITECTURE", buf) == -1) return -1; } #endif #endif if (add_variable("SI_HOSTNAME", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_HOSTNAME if (sysinfo(SI_HOSTNAME, buf, sizeof(buf)) != -1) { if (add_variable("SI_HOSTNAME", buf) == -1) return -1; } #endif #endif if (add_variable("SI_HW_PROVIDER", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_HW_PROVIDER if (sysinfo(SI_HW_PROVIDER, buf, sizeof(buf)) != -1) { if (add_variable("SI_HW_PROVIDER", buf) == -1) return -1; } #endif #endif if (add_variable("SI_HW_SERIAL", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_HW_SERIAL if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) != -1) { if (add_variable("SI_HW_SERIAL", buf) == -1) return -1; } #endif #endif if (add_variable("SI_MACHINE", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_MACHINE if (sysinfo(SI_MACHINE, buf, sizeof(buf)) != -1) { if (add_variable("SI_MACHINE", buf) == -1) return -1; } #endif #endif if (add_variable("SI_RELEASE", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_RELEASE if (sysinfo(SI_RELEASE, buf, sizeof(buf)) != -1) { if (add_variable("SI_RELEASE", buf) == -1) return -1; } #endif #endif if (add_variable("SI_VERSION", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_VERSION if (sysinfo(SI_VERSION, buf, sizeof(buf)) != -1) { if (add_variable("SI_VERSION", buf) == -1) return -1; } #endif #endif if (add_variable("SI_SRPC_DOMAIN", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_SRPC_DOMAIN if (sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf)) != -1) { if (add_variable("SI_SRPC_DOMAIN", buf) == -1) return -1; } #endif #endif if (add_variable("SI_SYSNAME", "") == -1) return -1; #ifdef HAVE_SYSINFO #ifdef SI_SYSNAME if (sysinfo(SI_SYSNAME, buf, sizeof(buf)) != -1) { if (add_variable("SI_SYSNAME", buf) == -1) return -1; } #endif #endif return 0; } #ifdef HAVE_UNAME /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Add uname(2) items as variables. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int add_uname_variables() { struct utsname uts; if (uname(&uts) != -1) { if (add_variable("UNAME_SYSNAME", uts.sysname) || add_variable("UNAME_NODENAME", uts.nodename) || add_variable("UNAME_RELEASE", uts.release) || add_variable("UNAME_VERSION", uts.version) || add_variable("UNAME_MACHINE", uts.machine)) return -1; } else { if (add_variable("UNAME_SYSNAME", "") || add_variable("UNAME_NODENAME", "") || add_variable("UNAME_RELEASE", "") || add_variable("UNAME_VERSION", "") || add_variable("UNAME_MACHINE", "")) return -1; } return 0; } #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Does variable substitution on a string. The result is stored in * an internal, reused buffer, and a pointer to that buffer is returned. * The caller must copy the returned string to a safe place before calling * any routine that might reuse the buffer. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * do_variables(string) char *string; { char c, *dollar, *varname; char *tail=NULL; char savechar; char key[2]; int l; ENTRY wanted_item, *found_item; dollar = strchr(string, '$'); /* Special early return for no vars */ if (!dollar) return string; if (debug > 1) fprintf(stderr, "Applying variable expansion to: `%s'\n", string); if (!created_variables_table) { Error(0, 0, "%tNo variables have been defined, but super.tab file is using some anyway!\n"); return NULL; } variablebuf.l = 0; /* Clear the buffer */ /* Initialize the buffer to be at least the same size as the input buffer */ if (!checksize(&variablebuf, ebuf.l)) { Error(1, 0, "%tCouldn't increase space for variable processing\n"); return NULL; } while (string && *string) { /* First, copy up to variable character */ dollar = strchr(string, '$'); if (!dollar) l = strlen(string); else l = dollar - string; strncpy(variablebuf.buf + variablebuf.l, string, l); variablebuf.l += l; variablebuf.buf[variablebuf.l] = '\0'; string += l; /* Reached end of string? */ if (!*string) break; /* Not at string end; expand variable */ if ( (c = *(dollar+1)) == '$') { /* $$ is a special macro name */ key[0] = c; key[1] = '\0'; varname = key; string += 2; savechar = '\0'; } else if (isalnum(c) || c == '_') { /* Replace $name -> variable defn */ for (tail=dollar+2; isalnum(*tail) || *tail == '_'; tail++) ; varname = dollar+1; /* tail points to one past last char in variable name. * Save this character, then overwrite with null char. */ savechar = *tail; *tail = '\0'; string = tail; } else if (c == '(') { /* Replace $(name) -> variable defn */ for (tail=dollar+2; isalnum(*tail) || *tail == '_'; tail++) ; /* must have reached right paren, and must make sure first * character was alphabetic */ if (tail == dollar+2) { Error(0, 0, "%tEmpty variable name is illegal: `$()'\n"); return NULL; } else if (*tail != ')' || !isalpha(*(dollar+2))) { Error(0, 0, "%tNot a valid variable name: `%.*s'\n", tail+1-dollar, dollar); return NULL; } savechar = '\0'; *tail = '\0'; varname = dollar+2; string = tail+1; } else { /* All other $X is error */ Error(0, 0, "%tIllegal variable name `$%c'. \n\ (Use `$$' to get a plain `$' passed on to the rest of file parsing.)\n", c); return NULL; } if (debug > 1) { fprintf(stderr, "Variable name is `%s'\n", varname); } if (varname) { /* Have a variable requiring expansion */ wanted_item.key = varname; found_item = s_hsearch(HS_VARS, wanted_item, FIND); if (!found_item) { Error(0, 0, "%t\n\tNo such variable as `$%s'\n", wanted_item.key); return NULL; } l = strlen(found_item->data); if (!checksize(&variablebuf, ROUNDUP(l+1, 1024))) { Error(1, 0, "%tCouldn't increase space for variable processing\n"); return NULL; } strcpy(variablebuf.buf+variablebuf.l, found_item->data); variablebuf.l += l; variablebuf.buf[variablebuf.l] = '\0'; /* Restore the saved character */ if (savechar && tail) *tail = savechar; } } if (debug > 1) fprintf(stderr, "variable-expanded string is `%s'\n", variablebuf.buf); return variablebuf.buf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Returns a variable's value. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * get_variable(varname) char *varname; { ENTRY wanted_item, *found_item; /* Have a variable requiring expansion */ wanted_item.key = varname; found_item = s_hsearch(HS_VARS, wanted_item, FIND); if (!found_item) { return NULL; } return found_item->data; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* A function for printing one variable's name and value. * See hprint() for calling sequence. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void print_variable(indx, key, data) int indx; char *key; char *data; { /* Ignore the variable "$", which is just a cute way of getting * "$$" to translate to plain "$". */ if (strcmp(key, "$") != 0) printf("\t%s:\t%s\n", key, data); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Input is string like "lhsrhs" * If there is no , null ptr is returned. * If lhs == left, then ptr to rhs is returned; else null pointer. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * str_val(left, sep, str) char *left; int sep; char *str; { char *s = strchr(str, sep); if (!s /* equal sign? */ || strlen(left) != (s - str) /* not same size as `left'? */ || strncmp(left, str, s-str) != 0) /* lhs != left */ return NULL; return s+1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* re_comp()-style interface to wildmat. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static char *shell_pattern = NULL; char * shell_compile(s) char *s; { shell_pattern = s; return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* re_exec()-style interface to wildmat. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int shell_compare(str) char *str; { extern int wildmat P__((char *str, char *pat)); int l, Reverse; char *sp; /* If the pattern is [[...]] (that is, bounded by doubled * square brackets), then we have a special case: * every character in s must match the glob pattern [...]. * For consistency with our normal shell patterns, we allow * ^[[...]] to invert the overall sense of match, but note * that the effect is the same as [[^...]]. */ Reverse = 0; sp = shell_pattern; if (*sp == '^') { Reverse = 1; sp++; } l = strlen(sp); if (sp[0] == '[' && sp[1] == '[' && sp[l-1] == ']' && sp[l-2] == ']') { /* * it's the special case... */ int last, matched, reverse; char *p; for ( ; *str; str++) { p = sp+1; /* skip leading "[" of "[[" */ if (p[1] == '^') { reverse = !Reverse; /* Inverted character class. */ p++; } else { reverse = Reverse; } matched = 0; if (p[1] == ']' || p[1] == '-') { if (*++p == *str) { matched = 1; } } for (last = *p; *++p && *p != ']'; last = *p) { if (*p == '-' && p[1] != ']' ? *str <= *++p && *str >= last : *str == *p) { matched = 1; } } if (matched == reverse) { return 0; /* fail */ } } return 1; } else { return wildmat(str, shell_pattern); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void init_strqtokS() { unsigned char *p; memset(my_qm, '\0', sizeof(my_qm)); for (p=(unsigned char *) QM; *p; ) my_qm[*p++] = 1; memset(my_cc, '\0', sizeof(my_cc)); for (p=(unsigned char *) CM; *p; ) my_cc[*p++] = 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Finds the hostname, like gethostname(), then uses canonicalize_hostname * to change it to a canonical form. * Returns 0 on success, and -1 on error, like gethostname(). */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int get_canonical_hostname(buf, len) char *buf; int len; { if (gethostname(buf, len) < 0) return Error(0, 0, "gethostname(\"%s\", %d) failed\n", buf, len); return canonicalize_hostname(buf, len); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Canonicalizes a hostname, if available. * Returns 0 on success, and -1 on error, like gethostname(). */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int canonicalize_hostname(buf, len) char *buf; int len; { #ifdef HAVE_GETHOSTBYNAME struct hostent *he, *he_nodot, *he_dot; char dot_name[1024] = "", nodot_name[1024] = ""; if (globalinfo.gethostbyname) { if ((l=strlen(buf)) > len - 2 || l > sizeof(dot_name)-1) return Error(0, 0, "hostname %s is too long for our buffer!\n", buf); /* On systems using DNS, appending a dot should force gethostbyname() * to fully expand and return fqdn. On systems using NIS, appending a * dot will cause match failure. So we try both forms, and take the * longer match. */ he_nodot = gethostbyname(buf); if (he_nodot && he_nodot->h_name) strcpy(nodot_name, he_nodot->h_name); strcat(buf, "."); he_dot = gethostbyname(buf); if (he_dot && he_dot->h_name) strcpy(dot_name, he_dot->h_name); if (strlen(dot_name) && strlen(nodot_name)) { if ((strlen(dot_name) > len - 1) || (strlen(nodot_name) > len - 1)) return Error(0, 0, "gethostbyname() returns `%s' which is too long for our buffer!\n", buf); strcpy(buf, strlen(dot_name) > strlen(nodot_name) ? dot_name : nodot_name); } else if (strlen(dot_name)) { if (strlen(dot_name) > len - 1) return Error(0, 0, "gethostbyname() returns `%s' which is too long for our buffer!\n", buf); strcpy(buf, dot_name); } else if (strlen(nodot_name)) { if (strlen(nodot_name) > len - 1) return Error(0, 0, "gethostbyname() returns `%s' which is too long for our buffer!\n", buf); strcpy(buf, nodot_name); } else { return Error(0, 0, "host `%s' not recognized by gethostbyname().\n", buf); } /* Delete trailing dot, if still present */ if ((l=strlen(buf)) > 0 && buf[l-1] == '.') buf[l-1] = '\0'; } #endif return 0; } /* * Check for balanced braces. * Return 0 if balanced, else (nleft-nright). */ int balancedbraces(s) char *s; { int n; for (n=0; *s; s++) { switch (*s) { case '{': n++; break; case '}': n--; break; } } return n; } /* * Downcase a null-terminated string. */ void strtolower(s) char *s; { for (; *s; s++) if (isupper(*s)) *s = tolower(*s); } #ifndef HAVE_STRTOL static unsigned long digit_a2d[128] = {0}; /* Initialize the character-to-digit mapping. */ static void init_digit(void) { int c; for (c=0; c < NELEM(digit_a2d); c++) digit_a2d[c] = -1; for (c = '0' ; c <= '9'; c++) digit_a2d[c] = c - '0'; digit_a2d['a']=digit_a2d['A'] = 10; digit_a2d['b']=digit_a2d['B'] = 11; digit_a2d['c']=digit_a2d['C'] = 12; digit_a2d['d']=digit_a2d['D'] = 13; digit_a2d['e']=digit_a2d['E'] = 14; digit_a2d['f']=digit_a2d['F'] = 15; digit_a2d['g']=digit_a2d['G'] = 16; digit_a2d['h']=digit_a2d['H'] = 17; digit_a2d['i']=digit_a2d['I'] = 18; digit_a2d['j']=digit_a2d['J'] = 19; digit_a2d['k']=digit_a2d['K'] = 20; digit_a2d['l']=digit_a2d['L'] = 21; digit_a2d['m']=digit_a2d['M'] = 22; digit_a2d['n']=digit_a2d['N'] = 23; digit_a2d['o']=digit_a2d['O'] = 24; digit_a2d['p']=digit_a2d['P'] = 25; digit_a2d['q']=digit_a2d['Q'] = 26; digit_a2d['r']=digit_a2d['R'] = 27; digit_a2d['s']=digit_a2d['S'] = 28; digit_a2d['t']=digit_a2d['T'] = 29; digit_a2d['u']=digit_a2d['U'] = 30; digit_a2d['v']=digit_a2d['V'] = 31; digit_a2d['w']=digit_a2d['W'] = 32; digit_a2d['x']=digit_a2d['X'] = 33; digit_a2d['y']=digit_a2d['Y'] = 34; digit_a2d['z']=digit_a2d['Z'] = 35; } long strtol(register const char *str, char **ptr, int base) { long sign=1; long value=0; long digit; if (*digit_a2d == 0) init_digit(); /* skip leading whitespace */ while (isspace(*str)) ++str; /* Check for optional sign */ switch (*str) { case '-': sign = -1; str++; break; case '+': str++; break; } /* Determine base */ if (base == 0) { if (*str != '0') { base = 10; } else if (*++str == 'x' || *str == 'X') { base = 16; ++str; } else { base = 8; } } /* Skip 0[xX], if present */ if (base == 16 && *str == '0') if (*++str == 'x' || *str == 'X') ++str; /* Convert value */ while (*str < NELEM(digit_a2d) && (digit=digit_a2d[*str]) < base && digit != -1) { value = value*base + digit; ++str; } if (ptr) *ptr = (char *) str; return sign*value; } #endif #ifndef HAVE_MEMSET void * memset(s, c, n) void *s; int c; int n; { register int i; register unsigned char *p = (unsigned char *) s; for (i=0; i sys_nerr) { sprintf(buf, "Error %d (!)", errnum); return buf; } else { #ifdef HAVE_STRERROR return strerror(errnum); #else return sys_errlist[errnum]; #endif } #endif } #ifndef HAVE_STRDUP char * strdup(s) char *s; { char *t = (char *) malloc(strlen(s)+1); if (!t) { return NULL; } strcpy(t, s); return t; } #endif #ifndef HAVE_VPRINTF /* Very system-specific. May not work for you... */ void vfprintf(stream, format, ap) FILE *stream; char *format; va_list ap; { _doprnt(format, ap, stream); } void vsprintf(str, format, ap) char *str; char *format; va_list ap; { FILE fp; fp._cnt = 077777; fp._base = fp._ptr = str; fp._bufsiz = 0; fp._flag = _IOSTRG | _IOWRT; fp._file = 0; _doprnt(format, ap, &fp); } #ifndef HAVE_DOPRNT ERROR -- YOU HAVE NEITHER v?printf() NOR _doprnt(). YOU ARE HOSED UNTIL YOU SUPPLY ONE OF THESE. #endif #endif /***********************************************************************/ /* * my_alloc, my_realloc, my_free can be handy to add debugging info to, * when allocation errors are happening. */ void * my_malloc(size_t size) { void *p = malloc(size); printf("my_malloc(%d) -> %p\n", size, p); return p; } void * my_realloc(void *ptr, size_t size) { void *p = realloc(ptr, size); printf("my_realloc(%p, %d) -> %p\n", ptr, size, p); return p; } void my_free(void *ptr) { printf("my_free(%p)\n", ptr); free(ptr); return; } super-3.30.0/p_regex.c0000444000104100002640000000314610732537455013057 0ustar willspg/* * This is an interface to the posix regular-expression matching. */ #include "localsys.h" #ifdef HAVE_POSIX_REGEX static regex_t compiled_pattern; /* for storing a compiled pattern */ static int free_pattern = 0; /* set !0 if a later call to p_compile() * should free the compiled pattern. */ static int posix_flags = 0; /* user-specified regcomp flags */ /* * Specify cflags for use in future regcomp() calls. */ void p_regcomp_flags(cflags) int cflags; { posix_flags |= cflags; } /* * Compile a pattern and store in compiled_pattern, above. * Return NULL on success, else some error string. */ char * p_compile(regex) char *regex; { int i; static char buf[1000]; if (free_pattern) { /* Free old pattern space */ regfree(&compiled_pattern); free_pattern = 0; } if ((i=regcomp(&compiled_pattern, regex, posix_flags | REG_NOSUB)) != 0) { /* compile failed */ regerror(i, &compiled_pattern, buf, sizeof(buf)); return buf; } free_pattern = 1; /* remind us to free the pattern next time. */ return NULL; } int p_compare(str) char *str; { regmatch_t pmatch[1]; return (regexec(&compiled_pattern, str, 1, pmatch, 0) == 0); } #else /* --------- POSIX regex routines not available ----------- */ static int posix_flags = 0; void p_regcomp_flags(cflags) int cflags; { return; } char * p_compile(regex) char *regex; { Error(0, 1, "p_compile(): POSIX regular expressions not available.\n"); return NULL; } int p_compare(str) char *str; { Error(0, 1, "p_compare(): POSIX regular expressions not available.\n"); return NULL; } #endif super-3.30.0/super.h0000444000104100002640000005576510732537455012607 0ustar willspg/* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1995, 1996 by William Deich. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ /* Use P__() to have prototypes in STD C code, and not use * prototypes in K&R C: declare functions as: * func_type funcname P__((arglist)); */ /* ==================================================================== */ #include "localsys.h" #include "s_hsearch.h" #include "version.h" /* ==================================================================== */ #ifndef __STDC__ extern char *malloc(); extern char *realloc(); #endif #ifndef HAVE_ALNUM #define alnum(c) (isalpha(c) || isdigit(c)) #endif #define SEP " \t\v\n" /* How to split fields on input lines */ #define QM "\"'" /* Quotemarks in fields */ #define CM "#" /* Comments in input file */ #define SAFE_IFS "IFS= \t\n" #define OPTION_SEP '=' /* option separator */ #define CONDITION_SEP '~' /* condition separator */ #define CLEAR_SETTINGS NULL /* The safe path should normally be defined/edited in config.h. This is * a just-in-case-it's-missing definition. */ #ifndef SAFE_PATH #define SAFE_PATH "/bin:/usr/bin:/usr/ucb" #endif /* The name under this program assumes it is installed. If argv[0] isn't * [/.../]ONETRUENAME, we assume we're running via symlink. */ #ifndef ONETRUENAME #define ONETRUENAME "super" #endif /* Kind of help we give */ #define HELP_BASIC 0 /* Basic help shows what you can execute */ #define HELP_FULL 1 /* Full help on each command */ #define HELP_FACTS 2 /* Just-the-facts-ma'm mode */ #define HELP_USAGE 3 /* Print usage only, no per-cmd help */ #ifndef SUPERFILE #ifdef SUPERDIR #define SUPERFILE SUPERDIR "/super.tab" #else #define SUPERFILE "/usr/local/lib/super.tab" #endif #endif #ifndef PERUSER_SUPERFILE #define PERUSER_SUPERFILE ".supertab" #endif #ifndef MAXFD int getdtablesize P__(( void )); #define MAXFD (getdtablesize()-1) #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif /* MAXSETENV is maximum number of variables that can be setenv'd on a * super control line. This isn't the maximum that can be passed; it's * only the number of environment variables definitions that can be * made on one control line. */ #define MAXSETENV 40 /* Default value for the maximum length of a user-supplied environment * variable definition. */ #define MAXENVLEN 1000 /* If defined, then user patterns are allowed to match the uid as well as * the actual username. We DISABLE this by default because users are * almost always identified by username. */ /* #define MATCH_DECIMAL_UID */ /* If defined, then group patterns are allowed to match the * gid as well as the group name, if any. We ENABLE this by default * because it's not unusual for users to be put into unnamed groups * in the password file. */ #define MATCH_DECIMAL_GID /* maximum number of tries at entering the password */ #define MAXTRY 3 /* default maxlength per arg passed to a command, maxlength all args */ #define MAXLEN1ARG 1000 #define MAXLENARGS 10000 /* define max length per option passed to super (not to the referenced * command), the max total length, and the valid option pattern. */ #define MAXOPTLEN 250 #define MAXOPTLEN_TOT 500 #define OPT_PATTERN "^[-/:+.=%@!,_a-zA-Z0-9]*$" #ifdef HAVE_INNETGR extern int innetgr(); #endif #ifndef HAVE_MEMSET void *memset P__(( void *s, int c, size_t n )); #endif /* special code to indicate we haven't specified a uid yet */ #define UID_NOTSET ((uid_t) ~0) /* special code to indicate we haven't specified a gid yet */ #define GID_NOTSET ((gid_t) ~0) /* special code to indicate we haven't specified supplementary groups */ #define GROUPS_NOTSET ((GETGROUPS_T) ~0) /* Number of elements in an array */ #define NELEM(x) (sizeof(x)/(sizeof(*x))) /* n rounded up to a multiple of m -- both should be positive */ #define ROUNDUP(n, m) ( ((n) % (m) == 0) ? (n) : ((n)/(m) + 1)*(m) ) /* STRBEG evaluates to !0 if s1 begins with substring s2 */ #define STRBEG(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0) /* STRMATCH3 expects 'end' to be a pointer into s2, and evaluates to !0 * if characters s2..(end-1) fully match s1 (that is, the next character in * s1 is null. */ #define STRMATCH3(s1, s2, end) \ (strncmp(s1, s2, end-s2) == 0 && s1[end-s2]=='\0') #define UNTIL(e) while(!(e)) /* ========================================================================= */ /* * Super's main external variables */ extern char *prog; /* this program */ extern int debug; /* debug level; 0=off */ extern int check_syntax; /* just check syntax of superfile */ extern int use_stdin; /* force stdin for passwds */ extern char *superfile; /* The actual superfile to be opened. */ extern char superfile_init[]; /* The super.init file. */ extern int it_came_from_cmdline; /* Set by -F/-T/-U/-G flags */ extern int using_user_supertab; /* !0 means using a user's .supertab */ extern int error_counter; /* incremented by Error() */ /* The following external variables control the Error() routine. * They are modified at various points by super(), to give detailed control * over the error messages that are printed. */ extern int error_stderr; /* stderr() bool */ extern int error_syslog; /* syslog() bool */ extern char *error_rlog_host; /* where rsyslog() msgs are sent */ extern int error_priority; /* syslog() "priority" */ extern int error_facility; /* openlog() "facility" */ extern char *error_command; /* our program name */ extern char *error_user; /* our caller's username */ extern int error_line; /* input line number of error */ extern int error_nl; /* number of lines this msg refers to */ extern char *error_srcfile; /* filename of input with error */ /* * For use with strqtokS -- see that routine for definitions of strqS_xxx */ extern unsigned char *strqS_qm; /* For fast access by strqtokS */ extern unsigned char my_qm[256]; extern unsigned char *strqS_cc; /* For fast access by strqtokS */ extern unsigned char my_cc[256]; /* * Extern variable and routines used to compile/match user/group/host patterns. */ extern char *(*pat_compile) P__(( char *)); extern int (*pat_compare) P__(( char *)); extern int need_re_anchor; /* ========================================================================= */ /* * Basic structures from which we construct other, bigger entities. */ struct simpleList { char *pat; struct simpleList *next; }; typedef struct simpleList SimpleList; struct simple2List { char *pat; struct simpleList *other; struct simple2List *next; }; typedef struct simple2List Simple2List; struct timeEnt { short begin; /* Start time, in minutes */ short end; /* End time, in minutes */ char day; /* day of week to match (0..6); 7 means any day */ char invert; /* match is to be inverted */ }; typedef struct timeEnt TimeEnt; struct timeList { TimeEnt te; struct timeList *next; }; typedef struct timeList TimeList; /* Linked open files */ struct fileList { char *givenname; /* filename, as given in the parent file */ char *fullname; /* filename, fully expanded */ FILE *fp; int line; /* current line */ int nl; /* number of lines in this block */ struct fileList *prev; }; typedef struct fileList FileList; struct countedString { char *s; /* malloc'd string */ int n; /* number of characters in s */ unsigned char used; /* !0 means this string is in use */ }; typedef struct countedString CountedString; struct strArray { CountedString *str; /* Pts to malloc'd array of CountedString's */ int n; /* number strings allocated */ }; typedef struct strArray StrArray; struct argRangePat { char *pat; /* pattern to be matched by ... */ int arg1; /* this arg through... */ int arg2; /* this arg. */ struct argRangePat *next; }; typedef struct argRangePat ArgRangePat; struct ourTime { time_t start; /* when program started */ short min; /* local time of day, in minutes */ char day; /* local day, with 0=sunday */ }; typedef struct ourTime OurTime; struct conditions { int user; /* !0 -> Last match to a user pattern */ int time; /* !0 -> Matched a time pattern */ int allinverted; /* !0 -> all time patterns scanned were inverted */ }; typedef struct conditions Conditions; /* The progList struct is for listing all Cmd::File pairs on a control line. */ struct progList { char *Cmd; char *File; }; typedef struct progList ProgList; /* ========================================================================= */ #ifdef HAVE_ENUM enum {SUPER_AUTH_PASSWORD, SUPER_AUTH_PAM} Method; #else /* No enums! */ #define SUPER_AUTH_PASSWORD 1 #define SUPER_AUTH_PAM 2 #endif /* Authentication information */ struct authInfo { int required; /* 0 = no auth required */ int method; /* AUTH_PASSWD, AUTH_PAM, etc */ int timeout; /* Time before re-authentication required */ int renewtime; /* update the timestamp file with each use of cmd? */ int perhost; /* create timestamp files separately for each host? */ char user[1024]; /* value of authuser=xxx, if entered */ char ts_user[1024]; /* value of timestampuid=xxx, if entered */ char *prompt; /* optional string with which to prompt for authinfo */ }; typedef struct authInfo AuthInfo; /* Information for logging use */ struct logInfo { FILE *fp; /* logfile pointer */ char filename[1024]; /* logfile name */ char user[1024]; /* value of loguid=xxx, if entered */ uid_t uid; /* UID under which we open logfile */ pid_t pid; /* PID of the logger; -1 means none running. */ unsigned char newfile; /* Bool: !0 if logfile given but not yet used */ unsigned char newuid; /* Bool: !0 if loguid given, but not yet used */ int syslog_success; /* syslog() "priority" for success msgs */ }; typedef struct logInfo LogInfo; /* progMatch is for keeping track of matches in a ProgList */ struct progMatch { ProgList *cmd_file; int match; /* index in proglist of matched command; -1 if no match */ int evermatched; /* 0 if no cmd in file matched pat */ char *commandfound; /* If match >= 0, commandfound points to actual * command matched. This can differ from * proglist.Cmd[match], because that Cmd can be * a pattern. */ int n; int nalloc; }; typedef struct progMatch ProgMatch; /* ========================================================================= */ /* * Global information from the :global lines */ struct globalInfo { char owner[32]; /* Owner of FullPath must be this person; overridden * by local owner=xxx option, if present. */ char *chdir_path; /* Change to this dir before exec'ing; null if none */ int relative_path; /* Allow filenames to be relative. This is * in general a stupid idea. Don't do it! */ int group_slash; /* Allow group names to have slashes. If you * allow this, you make it harder to catch certain * command-line typos. Don't do it! */ int maxenvlen; /* max length of envvar (all of "name=value") */ char **env; /* null-terminated list of vars from env=var[,...] */ int nice_incr; /* value of the nice=nnn increment value */ int mask; /* umask setting */ long maxlen1arg; /* max len of any single arg */ long maxlenargs; /* max len of all args, combined */ int usr_args[2]; /* number of user-entered args allowed */ ArgRangePat argpats; /* arg[MMM-]NNN=xxx arguments */ AuthInfo authinfo; /* authentication information */ Simple2List userbefore; /* list of u/g/h pats before per-cmd pats */ Simple2List userafter; /* list of u/g/h pats after per-cmd pats */ SimpleList b_a_text; /* list of original text for above */ int user_clear; /* clear userbefore list if new val seen */ TimeList timebefore; /* A list of the actual time ranges used */ TimeList timeafter; /* A list of the actual time ranges used */ int time_clear; /* clear timebefore list if new val seen */ int use_after; /* !set to !0 when we see <> */ LogInfo log; /* Information for logging to file */ char mailcmd[500]; /* Information for logging via mail */ int mail_success; /* bool: mail on success? (-1 = unknown) */ int gethostbyname; /* bool: use gethostbyname()? */ GETGROUPS_T groups[NGROUPS_MAX]; /* groups from [add]groups=xxx,... */ int ngroups; /* number of supplementary groups */ int groups_added; /* bool: groups were addgroups=, not groups= */ char *setenv[MAXSETENV+1]; /* values of setenv=var[,...] option */ }; typedef struct globalInfo GlobalInfo; /* * Information describing the caller */ struct userInfo { struct passwd caller; /* who's invoking program */ char hostname[MAXHOSTNAMELEN]; /* whence came the user */ char lc_hostname[MAXHOSTNAMELEN]; /* hostname in lower case */ int orig_mask; /* umask setting at startup */ uid_t orig_uid; /* uid at prog start, from getuid() */ gid_t orig_gid; /* gid at prog start, from getgid() */ uid_t new_uid; /* new uid, from uid=xxx or u+g=xxx */ gid_t new_gid; /* new gid, from gid=xxx or u+g=xxx */ uid_t new_euid; /* new euid, from uid=xxx or euid=xxx */ gid_t new_egid; /* new egid, from gid=xxx or egid=xxx */ OurTime ourtime; /* when we started, etc */ char encr[1000]; /* encrypted password; length is */ /* pretty large by current standards */ char salt[1000]; /* salt from password */ }; typedef struct userInfo UserInfo; /* * Per-entry (in the super.tab file) information. This gets filled in * at various points, as the program learns more. */ struct localInfo { ProgMatch progs; /* Records prog::file sets, and is updated w/ matches */ char *info; /* value of info=xxx option */ char *die; /* Gets msg from die=msg ; null if none */ char *print; /* Gets msg from print=msg ; null if none */ char *chdir_path; /* Change to this dir before exec'ing; null if none */ char *argv0; /* value of argv0=xxx option */ char user[32]; /* value of uid=xxx options */ char euser[32]; /* value of euid=xxx options */ char group[32]; /* value of group=xxx options */ char egroup[32]; /* value of egroup=xxx options */ char u_g[32]; /* value of u+g=xxx option */ char owner[32]; /* value of owner=xxx option */ uid_t file_uid; /* uid of the matched FullPath */ gid_t file_gid; /* gid of the matched FullPath */ GETGROUPS_T groups[NGROUPS_MAX]; /* groups from [add]groups=xxx,... */ int ngroups; /* number of supplementary groups */ int groups_added; /* bool: groups were addgroups=, not groups= */ int maxenvlen; /* max length of envvar (all of "name=value") */ char **env; /* null-terminated list of vars from env=var[,...] */ char *setenv[MAXSETENV+1]; /* values of setenv=var[,...] option */ char *fdlist; /* value of fd=nnn[,...] option */ int mask; /* value of umask=xxx option */ int nice_incr; /* value of the nice=nnn increment value */ Simple2List userpats; /* list of PermittedUser patterns */ SimpleList origtext; /* list of PermittedUser patterns */ TimeList time; /* A list of the actual time ranges used */ int usr_args[2]; /* number of user-entered args allowed */ long maxlen1arg; /* max len of any single arg */ long maxlenargs; /* max len of all args, combined */ ArgRangePat argpats; /* arg[MMM-]NNN=xxx arguments */ char **checkvar; /* null-term'd list of vars from checkvar=var[,...] */ char mailcmd[500]; /* Information for logging via mail */ int mail_success; /* bool: mail on successful tries? (-1 = unknown) */ int *fd; /* descriptors from fdlist string */ AuthInfo authinfo; /* authentication requirements on this command */ }; typedef struct localInfo LocalInfo; /* ========================================================================= */ extern FileList *currfile; /* list of currently-open files */ extern char authInitMsg1[]; /* msg from authentication init */ extern char authInitMsg2[]; /* suppl msg from authentication init */ extern int authInitErrno; /* errno, if relevant, to go * with authInitMsg1 */ extern GlobalInfo globalinfo; /* :global info */ extern UserInfo userinfo; /* User's info */ extern LocalInfo localinfo; /* per-cmd info */ extern Conditions matches; /* To keep track of what matched */ /* ========================================================================= */ void ARfree P__((ArgRangePat *head)); int ARinsert P__((ArgRangePat *start, int arg1, int arg2, char *pat)); ArgRangePat * ARnext P__((ArgRangePat *start, int iarg)); void add_builtin_variables P__(( void )); #ifdef HAVE_SYSINFO int add_sysinfo_variables P__(( void )); #endif #ifdef HAVE_UNAME int add_uname_variables P__(( void )); #endif int add_variable P__(( char *varname, char *vardefn )); void anchor P__(( char *in, char *out )); char* approve P__((char *usrcmd, int givehelp, int verbose)); char* auth_name P__(( void )); int balancedbraces P__(( char *s )); char ** blkdup P__((char **blk)); int blkfree P__((char **av0)); char ** Blkdup P__((char *str, char **blk)); int Blkfree P__((char *str, char **av0)); int blkprint P__((char **)); int build_cmd_file P__((char *, int , char *, char **)); char** buttonup P__((char *)); int canonicalize_hostname P__(( char *buf, int len)); int check_arglistlen P__(( char **argv )); int check_auth P__(( char *cmd )); int check_owner P__(( void )); int check_rpath P__((char *r_path, char *path)); void check_stdio P__((void)); int check_value P__(( char *value, char *pat )); int check_var_value P__(( void )); int checkarg P__(( char *str )); int checkenv P__(( char *name, char *value, char *pat )); char* clean_buf P__(( char *buf, char *outbuf )); void close_writer P__(( void )); int colon_define P__(( char *command )); int colon_die P__(( char *command )); int colon_getenv P__(( char *command )); int colon_global P__(( char *command )); int colon_include P__(( char *command, int allow_missing )); int colon_if P__(( char *command, int *colonif_succeeded )); int conditions_and_options P__(( char *cond_or_opt_wd )); struct passwd * construct_user_superfile P__(( char *user )); char* dayname P__(( int daynum )); int daynum P__(( int unixtime )); void debug_print P__((char *path, char **arglist, char **envp, int n_bltin)); void debug_hello P__((void)); int do_options P__((int argc, char **argv, int *help, int *vers, int *verbose, int *printvars, char **owned_by_file, char **required_path)); char* do_variables P__(( char *str)); char* docrypt P__((char *key, char *salt)); char* ends P__(( char *s1, char *s2 )); #ifdef HAVE_STDARG_H int Error P__(( int show_perror, int die, char * fmt, ... )); #else int Error(); #endif FileList* file_open P__(( FileList *list, char *name, int allow_missing, uid_t *req_uid, gid_t *req_gid )); FileList* file_close P__(( FileList *list )); char* fillbuffer P__(( FILE *fp, int *indentok, int *nl )); int findgid P__(( int allowbrackets, char *grouplabel )); int findgroup P__(( char *grouplabel )); int fixup_fullpath P__((int , char *, char *, char *, int )); void free_SimpleList P__(( SimpleList *)); void free_Simple2List P__(( Simple2List *)); void free_TimeList P__(( TimeList *)); int get_canonical_hostname P__((char *buf, int len)); int get_encrypted_pw P__(( void )); int get_owner P__((char *path, uid_t *uid, gid_t *gid)); int get_pam P__(( char *cmd, char *caller, char *user )); int get_password P__(( char *cmd, char *caller, char *user, char *salt, char *encr )); char* get_variable P__(( char *varname )); char* Getenv P__(( char *s )); int Getgroups P__((int, GETGROUPS_T *)); struct group * getgrentry P__(( char *name )); int getlogdir P__((char *user, char *buf)); struct passwd * getpwentry P__((int allow_brackets, char *username)); int global_arg P__((char *word)); int globbraces P__(( char *s, int wrap_in_braces, char ***globlist )); int handle_option P__((char *word, char *s, int isglobal)); int ingroup P__(( char * user, gid_t gid, char * gp_pat )); void init_nice_incr P__((int is_global)); void init_strqtokS P__(( void )); void init_umask P__((int is_global)); void init_globalinfo P__( (void) ); void init_localinfo P__( (void) ); int init_userinfo P__( (void) ); int InsertCondition P__(( char *, char *, int )); int InsertTimeList P__(( char *, char **, TimeList *, char *, int )); int InsertUserList P__((char *, char **, Simple2List *, SimpleList *, int)); void logmsg P__(( char * cmd, char ** args )); int makedir P__(( char *directories, int *err, char *msgbuf )); char* makedirname P__(( char *prefix, char *hostname, char *path, int *err, char *msgbuf )); int match_pattern P__((int match, int glob, char *str, char *pattern)); void match_ugh_user P__((Simple2List *sl, int isglobal)); void matchtime P__(( OurTime *our, TimeList *tl )); char** newargs P__((char *path_plus, char **argv, int *n_builtin)); FILE* open_writer P__(( char *user, char *filename, pid_t *pid_p )); void opensuperlog P__(( void )); int option_clear_settings P__((char *word, char *s, int isglobal)); int option_global_reset_settings P__((void)); int option_local_clear_settings P__((void)); void p_regcomp_flags P__(( int )); char* p_compile P__(( char *)); int p_compare P__(( char *)); int parseline P__((int givehelp, int checksyntax, char *buf, char *usrcmd)); void print_variable P__(( int indx, char *key, char *data )); void printhelp P__(( int verbose )); void printhelp_hello P__(( int verbose, char *usrcmd )); int process_colon_cmds P__(( char *command, int *colonif_succeeded )); int process_logfile_opt P__(( void )); int rcl_nice_incr P__((void)); int rcl_umask P__((void)); void re_anchor P__(( char *in, char *out)); int s_getpass P__((char *prompt, int use_stdin, char *buf, int buflen)); char* s_re_comp P__(( char *)); int s_re_exec P__(( char *)); void readtime_init P__(( void )); int readtimerange P__(( char *str, short *t1, short *t2, char *d )); int readtime P__(( char *str, short *t1, char *d )); int save_var_value P__((char *var_value)); int set_chdir P__((void)); int set_nice_incr P__((void)); int set_u_g P__(( void )); void set_umask P__((void)); int Setgroups P__((int, GETGROUPS_T *)); int shell_compare P__(( char *)); char* shell_compile P__(( char *)); void store_nice_incr P__((int nice_incr, int is_global)); void store_umask P__((int mask, int is_global)); char* str_val P__(( char *left, int sep, char *str )); int StrBulkCpy P__(( StrArray *dst, int dst_ielt, StrArray *src, int src_ielt, int nelt )); int StrEltCpy P__(( StrArray *a, int ielt, char *str)); char* StrEltGetPtr P__(( StrArray *a, int ielt )); void StrEltsUnused P__(( StrArray *a )); void StrInit P__(( StrArray *a )); int stringcopy P__(( char *to, char *from, int n)); int StrLastInUse P__(( StrArray *a )); int StrNalloc P__(( StrArray *a, int nelt)); int StrNelts P__(( StrArray *a )); void strtolower P__(( char *string )); char* strqtokS P__(( char *, char *, char *, char *, unsigned int )); int read_syslogcode P__(( char *str, int *code )); void user_supertab P__(( char *file_or_user, int is_file, char *cmd )); int wildmat P__(( char *text, char *p )); super-3.30.0/config.h.in0000444000104100002640000002134210732537455013303 0ustar willspg/* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1995, 1996 by William Deich. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ /* ###################################################################### */ /* The following items should be carefully checked to make sure that */ /* they properly describe your system. */ /* ###################################################################### */ /* The PATH variable for any command executed by super. Set to a path that * contains only trusted files. */ #define SAFE_PATH @SAFE_PATH@ /* TIMESTAMP_DIR is the directory in which timestamp files are * kept for commands that require passwords to be entered. */ #ifndef TIMESTAMP_DIR #define TIMESTAMP_DIR "/usr/local/lib/super/timestamps" #endif /* Define if on AIX >= 3. */ #undef _ALL_SOURCE /* Define if on Clix */ #undef __clix__ /* Define if on SCO */ #undef SCO /* Define if on HP-UX */ #undef _HPUX_SOURCE /* For HP-UX, define major and minor version numbers (computed in the * configure script). */ #undef HPUX_MAJOR #undef HPUX_MINOR /* Define if on Linux or other glibc system */ #undef _BSD_SOURCE /* For SunOS, define major and minor version numbers (computed in the * configure script); for convenience, if on SunOS 5.x, also define SUNOS5. */ #undef SUNOS_MAJOR #undef SUNOS_MINOR #ifdef SUNOS_MAJOR #if (SUNOS_MAJOR == 5) #define SUNOS5 #endif #endif /* For AIX, define major and minor version numbers (computed in the * configure script. */ #undef AIX_MAJOR #undef AIX_MINOR /* Define both of these if on Digital Unix (or Dec OSF/1 3.2 or higher) */ #ifndef Digital_UNIX #undef Digital_UNIX #endif #ifndef _OSF_SOURCE #undef _OSF_SOURCE #endif /* * Don't define _XOPEN_SOURCE for SCO: although it uses this for compliance * reasons, this define causes some problems with password file negotiation. * * Also don't define it for Solaris 2.4 (SunOS 5.4) and higher: it causes * problems for things like struct timespec, which doesn't get defined if * _XOPEN_SOURCE is set (instead struct _timespec is defined), but stat.h * uses struct timespec in its definition of itimerval. It's a mess... * For our convenience, we won't define it for any Solaris. */ #ifndef _SVR4_SOURCE #ifndef SCO #ifndef SUNOS5 #define _XOPEN_SOURCE #endif #endif #endif /* ###################################################################### */ /* The following items are set correctly for your system */ /* ###################################################################### */ #ifdef __STDC__ #define P__(x) x #else #define P__(x) () #endif /* Define these to `int' if doesn't define. */ #undef pid_t #undef uid_t #undef gid_t /* Define if your system has */ #undef HAVE_ARPA_INET_H /* Define if your system has */ #undef HAVE_ERRNO_H /* Define if you need _not_ declare errno to be extern */ #undef DONT_DECL_ERRNO /* Define if your system has */ #undef HAVE_LIMITS_H /* Define if your system has */ #undef HAVE_LOCALE_H /* Define if your system has */ #undef HAVE_MALLOC_H /* Define if your system has */ #undef HAVE_MEMORY_H /* Define if your system has */ #undef HAVE_NETDB_H /* Define if your system has */ #undef HAVE_NET_ROUTE_H /* Define if your system has */ #undef HAVE_NET_IF_H /* Define if your system has */ #undef HAVE_NETINET_IN_H /* Define if your system has */ #undef HAVE_SHADOW_H /* Define if your system has */ #undef HAVE_SYS_SECURITY_H /* Define if your system has */ #undef HAVE_HPSECURITY_H /* Define if your system has */ #undef HAVE_SECURITY_PAM_APPL_H /* Define if your system has */ #undef HAVE_SECURITY_PAM_MISC_H /* Define if your system has */ #undef HAVE_PROT_H /* Define if your system has */ #undef HAVE_AUTH_H /* Define if your system has */ #undef HAVE_SYS_LABEL_H /* Define if your system has */ #undef HAVE_SYS_AUDIT_H /* Define if your system has */ #undef HAVE_PWDADJ_H /* Define if your system has */ #undef HAVE_STANDARDS_H /* Define if your system has */ #undef HAVE_STDLIB_H /* Define if your system has */ #undef HAVE_STDARG_H /* Define if your system has */ #undef HAVE_STRING_H /* Define if your system has */ #undef HAVE_SYS_PARAM_H /* Define if your system has */ #undef HAVE_SYS_SOCKET_H /* Define if your system has */ #undef HAVE_SYS_UTSNAME_H /* Define if your system has */ #undef HAVE_SYS_SYSTEMINFO_H /* Define if your system has */ #undef HAVE_SYS_SYSINFO_H /* Define if your system has */ #undef HAVE_SYS_TIME_H /* Define if can be included with */ #undef TIME_WITH_SYS_TIME /* Define if your system has */ #undef HAVE_SYS_TYPES_H /* Define if your system has */ #undef HAVE_SYS_BSDTYPES_H /* Define if your system has */ #undef HAVE_SYS_WAIT_H /* Define if your system has */ #undef HAVE_SYSLOG_H /* Define if your system has */ #undef HAVE_SYS_RESOURCE_H /* Define if your system has */ #undef HAVE_UNISTD_H /* Define if your system has */ #undef HAVE_SYS_FILIO_H /* Define if your system has */ #undef HAVE_FCNTL_H /* Define if your system has */ #undef HAVE_TERMIOS_H /* Define if your system has */ #undef HAVE_TERMIO_H /* Define if your system has */ #undef HAVE_SGTTY_H /* Define if have getgroups() */ #undef HAVE_GETGROUPS #ifdef HAVE_GETGROUPS /* Define to the type of elements in the array set by `getgroups'. * Usually this is either `int' or `gid_t'. */ #undef GETGROUPS_T #endif /***********************************************************************/ /* Define if your system has sys_errlist[] */ #undef HAVE_SYS_ERRLIST /***********************************************************************/ /* Define if your system has sysinfo() */ #undef HAVE_SYSINFO /* Define if your system has sysconf() */ #undef HAVE_SYSCONF /* Define if your system has uname() */ #undef HAVE_UNAME /* Define if your system has setreuid() */ #undef HAVE_SETREUID /* Define if your system has setregid() */ #undef HAVE_SETREGID /* Define if your system has tcgetattr() */ #undef HAVE_TCGETATTR /* Define if your system has tcsetattr() */ #undef HAVE_TCSETATTR /* Define if your system has getdomainname() */ #undef HAVE_GETDOMAINNAME /* Define if your system has alnum(c) == (isalpha(c) || isdigit(c)) */ #undef HAVE_ALNUM /* Define if your system supports enums */ #undef HAVE_ENUM /* Define if your system supports the ioctl(fd, FIOCLEX, NULL) call */ #undef HAVE_IOCTL_FIOCLEX /* Define if your system has the getdtablesize() function */ #undef HAVE_GETDTABLESIZE /* Define if your system has innetgr() */ #undef HAVE_INNETGR /* Define if your system has iscomsec() */ #undef HAVE_ISCOMSEC /* Define if your system has localtime() */ #undef HAVE_LOCALTIME /* Define if your system has memcpy() */ #undef HAVE_MEMCPY /* Define if your system has memset() */ #undef HAVE_MEMSET /* Define if your signal() is of type void */ #undef HAVE_VOID_SIGNAL /* Define if your system has POSIX regular expression routines */ #undef HAVE_POSIX_REGEX /* Define if your system has strdup() */ #undef HAVE_STRDUP /* Define if your system has strerror() */ #undef HAVE_STRERROR /* Define if your system has strtol() */ #undef HAVE_STRTOL /* Define if your system has the pam_start() function */ #undef HAVE_PAM_START /* Define if your system has the pam_strerror() function */ #undef HAVE_PAM_STRERROR /* Define if your system has the misc_conv() function (from libpam_misc) */ #undef HAVE_MISC_CONV /* Define if your system has the fileno() function */ #undef HAVE_FILENO /* Define if your system has the gtty() function */ #undef HAVE_GTTY /* Define if your system has the syslog() function */ #undef HAVE_SYSLOG /* Define if your system has the sysconf() function */ #undef HAVE_SYSCONF /* Define if your system has the v?printf() functions */ #undef HAVE_VPRINTF /* Define if your system doesn't have vprintf, but has _doprnt() */ #undef HAVE_DOPRNT /***********************************************************************/ /* Define if your system doesn't understand "#! /path" at the start * of a script. Super will include code to do this work. */ #undef INTERPRETER_HACK /* Define if your system supports filenames more than 14 characters */ #undef HAVE_LONG_FILE_NAMES super-3.30.0/localsys.h0000444000104100002640000001270710732537455013267 0ustar willspg/* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1995, 1996 by William Deich. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ /* Use P__() to have prototypes in STD C code, and not use * prototypes in K&R C: declare functions as: * func_type funcname P__((arglist)); */ #ifndef LOCALSYS_H #define LOCALSYS_H #include "config.h" #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif /* We only include so we can do close-on-exec on ancient * systems (e.g. V7) that implement it via an ioctl instead of fcntl. * Don't include it if not needed for this purpose. */ #ifndef HAVE_FCNTL_H #ifdef HAVE_IOCTL_FIOCLEX #include #endif #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifndef DONT_DECL_ERRNO extern int errno; #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_STRING_H #include #else #include #define strchr index #define strrchr rindex #endif #ifndef HAVE_MEMCPY #define memcpy(d, s, n) bcopy((s), (d), (n)) #define memmove(d, s, n) bcopy((s), (d), (n)) #endif #ifndef HAVE_STRDUP char *strdup P__((char *)); #endif #ifdef HAVE_STANDARDS_H #include #endif #ifdef HAVE_STDARG_H #include #else #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_BSDTYPES_H #include #endif #ifdef HAVE_POSIX_REGEX #include #endif #ifdef HAVE_SYS_WAIT_H #include #else pid_t wait(int *); #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NET_ROUTE_H #include #endif #ifdef HAVE_NET_IF_H struct mbuf; /* To shut up warnings on Digital Unix, which didn't * declare all arguments as cleanly as it might. */ #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifndef NGROUPS_MAX #ifdef NGROUPS #define NGROUPS_MAX NGROUPS #else #define NGROUPS_MAX 1 #endif #endif #ifndef _POSIX_VERSION uid_t getuid(); gid_t getgid(); #endif #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_SHADOW_H #include #endif #ifdef HAVE_SYS_SECURITY_H #include #endif #ifdef HAVE_HPSECURITY_H #include #endif #ifdef HAVE_SECURITY_PAM_APPL_H #include #endif #ifdef HAVE_SECURITY_PAM_MISC_H #include #endif #ifdef HAVE_PAM_START #ifndef HAVE_MISC_CONV int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr); #endif #endif #ifdef HAVE_SYS_IOCTL_H #include #endif /* Want just one of termios.h, termio.h, sgtty.h */ #ifdef HAVE_TERMIOS_H #include #else #ifdef HAVE_TERMIO_H #include #else #ifdef HAVE_SGTTY_H #include #endif #endif #endif #ifdef HAVE_PROT_H #include #endif #ifdef HAVE_AUTH_H #include #endif #ifdef HAVE_SYS_LABEL_H #include #endif #ifdef HAVE_SYS_AUDIT_H #include #endif #ifdef HAVE_PWDADJ_H #include #endif #ifdef __clix__ #include #else #include #endif #ifdef SCO #include #endif #ifndef _SVR4_SOURCE #ifndef Digital_UNIX #if !(defined(BSD) && (BSD >= 199306)) #if !(defined(SUNOS5) && SUNOS_MINOR >= 6) #if !(defined(_AIX) && AIX_MAJOR >= 4) extern int gethostname P__((char *, size_t size)); #endif #endif #endif #endif #endif #ifdef HAVE_SYS_SYSINFO_H #include #endif #ifdef HAVE_SYS_SYSTEMINFO_H #include extern int sysinfo(); #define gethostname(buf, lbuf) (sysinfo(SI_HOSTNAME, (buf), (lbuf))) #endif #ifdef HAVE_SYS_UTSNAME_H #include #endif #ifdef _SVR4_SOURCE #undef NSIG #define NSIG _sys_nsig #else #ifdef _NSIG #ifndef NSIG #define NSIG _NSIG #endif #endif #endif #ifdef HAVE_VOID_SIGNAL #define SIGNAL_T void #else #define SIGNAL_T int #endif #include #ifndef S_IWGRP #define S_IWGRP 0000020 #endif #ifndef S_IWOTH #define S_IWOTH 0000002 #endif #ifdef HAVE_MEMORY_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_SYSLOG_H #include #endif /* I have troubles with a good value for MAXPATHLEN (if it isn't defined). * _POSIX_PATH_MAX is no good because it's only a minimum maximum. * pathconf(path, _PC_PATH_MAX) is no good because it's path-dependent. * Well, I'll just take the easy way out... */ #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif /* type returned by setgrent() */ #if defined(Digital_UNIX) || (defined(BSD) && (BSD >= 199306)) typedef int SETGRENT_T; #else typedef void SETGRENT_T; #endif #ifdef HAVE_SYSCONF #define MAXFD (sysconf(_SC_OPEN_MAX)-1) #else #ifdef HAVE_GETDTABLESIZE #define MAXFD (getdtablesize()-1) #else #define MAXFD 63 #endif #endif #endif super-3.30.0/configure.in0000444000104100002640000002224610732537455013575 0ustar willspgdnl Process this file with autoconf to produce a configure script. AC_INIT(super.h) AC_CONFIG_HEADER(config.h) AC_ARG_ENABLE(pam, [ --disable-pam don't include PAM support even if compile host has PAM]) AC_PROG_CC Uname=unknown Major=0 Minor=0 for d in /bin /usr/bin /sbin /usr/sbin ; do if test -f $d/uname ; then Uname=`$d/uname` rev=`$d/uname -r` break fi done if test "$Uname" = HP-UX ; then AC_DEFINE(_HPUX_SOURCE) case "$CC" in gcc ) CPP="${CC} -E -w" ;; * ) CPP="${CC} -E -Ae -w" CFLAGS="${CFLAGS} -Ae" ;; esac changequote(<<<,>>>)dnl Major=`expr "$rev" : '.*\.\([0-9][0-9]*\)\..*'` Minor=`expr "$rev" : '.*\.[0-9][0-9]*\.\([0-9][0-9]*\).*'` changequote([,])dnl AC_DEFINE_UNQUOTED(HPUX_MAJOR,$Major) AC_DEFINE_UNQUOTED(HPUX_MINOR,$Minor) elif test "$Uname" = Linux ; then AC_DEFINE(_BSD_SOURCE) elif test "$Uname" = OSF1 ; then AC_DEFINE(_OSF_SOURCE) AC_DEFINE(Digital_UNIX) elif test "$Uname" = SunOS ; then changequote(<<<,>>>)dnl Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` changequote([,])dnl test "$Major" = 5 && AC_DEFINE(SUNOS5) AC_DEFINE_UNQUOTED(SUNOS_MAJOR,$Major) AC_DEFINE_UNQUOTED(SUNOS_MINOR,$Minor) elif test "$Uname" = Darwin ; then changequote(<<<,>>>)dnl Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` changequote([,])dnl elif test "$Uname" = OpenBSD ; then changequote(<<<,>>>)dnl Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` changequote([,])dnl elif test "$Uname" = AIX ; then Major=`/bin/uname -v` Minor=`/bin/uname -r` # Ensure we are looking at just a numeric value, just in case # IBM decides to add some letters or dots or underscores... changequote(<<<,>>>)dnl Major=`/bin/expr "$Major" : '^[^0-9]*\([0-9][0-9]*\)'` Minor=`/bin/expr "$Minor" : '\([0-9][0-9]*\)[^0-9]*$'` changequote([,])dnl AC_DEFINE_UNQUOTED(AIX_MAJOR,$Major) AC_DEFINE_UNQUOTED(AIX_MINOR,$Minor) fi AC_PROG_INSTALL AC_HAVE_HEADERS(errno.h stdlib.h limits.h string.h standards.h \ netdb.h locale.h auth.h hpsecurity.h prot.h shadow.h \ fcntl.h regex.h sgtty.h unistd.h \ memory.h malloc.h pwdadj.h sgtty.h sys/time.h stdarg.h syslog.h \ sys/ioctl.h termio.h termios.h \ arpa/inet.h net/route.h net/if.h netinet/in.h \ sys/types.h sys/bsdtypes.h sys/label.h sys/audit.h \ sys/filio.h sys/wait.h sys/param.h sys/security.h \ sys/socket.h sys/sysinfo.h sys/systeminfo.h sys/utsname.h ) # In case the user said --without-pam instead of --disable-pam: if test "$with_pam" = "no" ; then enable_pam=no fi if test "$enable_pam" != "no" ; then AC_HAVE_HEADERS(security/pam_appl.h security/pam_misc.h) fi AC_AIX AC_MINIX AC_CHECKING(for directories to include in the safe path) SafePath=/bin:/usr/bin test -d /usr/ucb && SafePath=${SafePath}:/usr/ucb test -d /usr/bsd && SafePath=${SafePath}:/usr/bsd AC_DEFINE_UNQUOTED(SAFE_PATH, "${SafePath}") # syslog may be in one of the following. They may also be needed for # other reasons, so we just blindly check for them all. AC_CHECK_LIB(bsd, main) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(inet, main) badredhatpam=0 if test "$enable_pam" != "no" ; then # RH 7.2 has messed up libpam's installation: it supplies with # libpam.so.0, but not libpam.so. Ditto libpam_misc. test -f /etc/redhat-release -a -f /lib/libpam.so.0 \ -a ! -f /lib/libpam.so && badredhatpam=1 # -ldl may be needed by -lpam. AC_CHECK_LIB(dl, main) AC_CHECK_LIB(pam, main) AC_CHECK_LIB(pam_misc, main) fi # Pick up libcrypt if it exists and this OS needs it. # (Note that on some OS's, libcrypt does not contain the # correct crypt(); instead, libc contains the desired crypt.) if test "$Uname" = SunOS -a $Major = 5 -a $Minor -ge 9 ; then : # SunOS >= 5.9: don't link with -lcrypt elif test "$Uname" = OpenBSD ; then : # don't link with -lcrypt elif test "$Uname" = Darwin ; then : # don't link with -lcrypt else AC_CHECK_LIB(crypt, main) fi if test "$enable_pam" != "no" ; then AC_CHECK_FUNCS(pam_start) test "$ac_cv_func_pam_start" = yes && AC_REPLACE_FUNCS(misc_conv) fi AC_CHECK_FUNCS(fileno) AC_CHECK_FUNCS(gtty) AC_CHECK_FUNCS(syslog) AC_CHECK_FUNCS(strdup) AC_CHECK_FUNCS(initgroups) for lib in os ; do test "$ac_cv_func_initgroups" = yes && break AC_CHECK_LIB($lib, initgroups) done # On IRIX, -lmalloc avoids a problem with default malloc # that causes a core dump. AC_CHECK_LIB(malloc, main) # May be needed on IRIX AC_CHECK_LIB(sun, getpwnam) # Needed on SysV for shadow passwords. AC_CHECK_LIB(sec, main) # Needed on Digital Unix for shadow passwords. AC_CHECK_LIB(security, main) # Needed on Linux for shadow passwords. AC_CHECK_LIB(shadow, main) # Needed on Solaris AC_CHECK_LIB(nsl, main) # Needed on SCO-ODT-3.0 for crypt. AC_CHECK_LIB(ufc, main) # We want these before the checks, so the checks can modify their values. test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 # If the user hasn't specified CFLAGS, and we're using gcc, use -O. test -n "$auto_cflags" && test -n "$GCC" && CFLAGS="$CFLAGS -O" # If we're on AIX, not using gcc, add the ansi spec. test "$Uname" = AIX && test -z "$GCC" && CFLAGS="$CFLAGS -qlanglvl=ansi" # If system supports "const", define ConstDef to be "", but if # the system doesn't support "const", define ConstDef to be "-Dconst=". # That makes it suitable for use in the CFLAGS. AC_C_CONST ConstDef= test "$ac_cv_c_const" != yes && ConstDef="-Dconst=" AC_SYS_LONG_FILE_NAMES AC_SYS_INTERPRETER test "$ac_cv_sys_interpreter" != yes && AC_DEFINE(INTERPRETER_HACK) AC_STDC_HEADERS AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_GETGROUPS AC_TYPE_SIZE_T AC_STRUCT_TM AC_TIME_WITH_SYS_TIME void_ok=no AC_MSG_CHECKING(if func signal is compatible with declaring type void) AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl <>, changequote([,])dnl AC_DEFINE(HAVE_VOID_SIGNAL) void_ok=yes ; AC_MSG_RESULT(yes)) if test $void_ok = no ; then AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl <>, changequote([,])dnl AC_DEFINE(HAVE_VOID_SIGNAL) void_ok=yes ; AC_MSG_RESULT(yes)) fi AC_MSG_CHECKING(if sys_errlist is defined) AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl <>, changequote([,])dnl AC_DEFINE(HAVE_SYS_ERRLIST) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_MSG_CHECKING(if errno must be explicitly declared extern) AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl <>, changequote([,])dnl AC_DEFINE(DONT_DECL_ERRNO) AC_MSG_RESULT(no), AC_MSG_RESULT(yes)) AC_MSG_CHECKING(if regex library is POSIX) AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl << regex_t preg; char buf[100]; regmatch_t pmatch[1]; regcomp(&preg, "a pattern", REG_EXTENDED|REG_ICASE|REG_NOSUB|REG_NEWLINE); regexec(&preg, "a string", 1, pmatch, REG_NOTBOL|REG_NOTEOL); regerror(1, &preg, buf, sizeof(buf)); regfree(&preg); >>, changequote([,])dnl AC_DEFINE(HAVE_POSIX_REGEX) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_MSG_CHECKING(if compiler supports enum) AC_TRY_COMPILE(, [enum { red, green, blue } color;], AC_DEFINE(HAVE_ENUM) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_MSG_CHECKING(if close-on-exec can be done via ioctl()) AC_TRY_COMPILE([ #include #include ], changequote(<<,>>)dnl <>, changequote([,])dnl AC_DEFINE(HAVE_IOCTL_FIOCLEX) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_FUNC_VPRINTF if test "$enable_pam" != "no" ; then AC_CHECK_FUNCS(pam_strerror) fi AC_CHECK_FUNCS(strerror strtol memcpy memset strerror setreuid setregid \ getgroups innetgr iscomsec localtime sysconf sysinfo getdtablesize \ getdomainname sysinfo tcgetattr tcsetattr uname) # If we're enabling pam support (if PAM available), include pam.o in AC_LIBOBJ. # Note that if we don't have pam_start() on this system, pam.o will still # build correctly for a PAM-less system. In other words, include pam.o # unless the user included the configure option "--disable-pam". if test "$enable_pam" != "no" ; then AC_LIBOBJ([pam]) with_pam=1 else with_pam=0 fi AC_SUBST(libdir)dnl AC_SUBST(bindir)dnl AC_SUBST(SafePath)dnl AC_SUBST(ConstDef)dnl AC_SUBST(with_pam)dnl AC_OUTPUT(Makefile) test "$badredhatpam" = 1 && { echo "#" echo "# WARNING." echo "#" echo "# You have /lib/libpam.so.0 but not libpam.so." echo "# In Redhat 7.{1,2}, this is bugid 55651, and is fixed in rpm" echo "# pam-0.75-18.7. You should get that rpm to fix several pam bugs," echo "# but for now you should become root, and make these links by hand:" echo "# ln -s /lib/libpam.so.0 /lib/libpam.so" echo "# ln -s /lib/libpam_misc.so.0 /lib/libpam_misc.so" echo "#" echo "# Then, rm config.cache and rerun configure." echo "#" echo "#" } # The test command will give a non-zero exit code if this isn't # a bad-redhat-pam system. So use 'exit 0' to make everyone happy. exit 0 super-3.30.0/configure0000755000104100002640000062135010732537455013176 0ustar willspg#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.57. # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" # Sed expression to map a string onto a valid variable name. as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="super.h" # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP LIBOBJS SafePath ConstDef with_pam LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-pam don't include PAM support even if compile host has PAM Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be # absolute. ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.57. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core core.* *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" # Check whether --enable-pam or --disable-pam was given. if test "${enable_pam+set}" = set; then enableval="$enable_pam" fi; ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output" >&5 echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ ''\ '#include ' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu Uname=unknown Major=0 Minor=0 for d in /bin /usr/bin /sbin /usr/sbin ; do if test -f $d/uname ; then Uname=`$d/uname` rev=`$d/uname -r` break fi done if test "$Uname" = HP-UX ; then cat >>confdefs.h <<\_ACEOF #define _HPUX_SOURCE 1 _ACEOF case "$CC" in gcc ) CPP="${CC} -E -w" ;; * ) CPP="${CC} -E -Ae -w" CFLAGS="${CFLAGS} -Ae" ;; esac Major=`expr "$rev" : '.*\.\([0-9][0-9]*\)\..*'` Minor=`expr "$rev" : '.*\.[0-9][0-9]*\.\([0-9][0-9]*\).*'` cat >>confdefs.h <<_ACEOF #define HPUX_MAJOR $Major _ACEOF cat >>confdefs.h <<_ACEOF #define HPUX_MINOR $Minor _ACEOF elif test "$Uname" = Linux ; then cat >>confdefs.h <<\_ACEOF #define _BSD_SOURCE 1 _ACEOF elif test "$Uname" = OSF1 ; then cat >>confdefs.h <<\_ACEOF #define _OSF_SOURCE 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define Digital_UNIX 1 _ACEOF elif test "$Uname" = SunOS ; then Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` test "$Major" = 5 && cat >>confdefs.h <<\_ACEOF #define SUNOS5 1 _ACEOF cat >>confdefs.h <<_ACEOF #define SUNOS_MAJOR $Major _ACEOF cat >>confdefs.h <<_ACEOF #define SUNOS_MINOR $Minor _ACEOF elif test "$Uname" = Darwin ; then Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` elif test "$Uname" = OpenBSD ; then Major=`/bin/expr "$rev" : '^\([0-9][0-9]*\)\.'` Minor=`/bin/expr "$rev" : '^[0-9][0-9]*\.\([0-9][0-9]*\)'` elif test "$Uname" = AIX ; then Major=`/bin/uname -v` Minor=`/bin/uname -r` # Ensure we are looking at just a numeric value, just in case # IBM decides to add some letters or dots or underscores... Major=`/bin/expr "$Major" : '^[^0-9]*\([0-9][0-9]*\)'` Minor=`/bin/expr "$Minor" : '\([0-9][0-9]*\)[^0-9]*$'` cat >>confdefs.h <<_ACEOF #define AIX_MAJOR $Major _ACEOF cat >>confdefs.h <<_ACEOF #define AIX_MINOR $Minor _ACEOF fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in errno.h stdlib.h limits.h string.h standards.h \ netdb.h locale.h auth.h hpsecurity.h prot.h shadow.h \ fcntl.h regex.h sgtty.h unistd.h \ memory.h malloc.h pwdadj.h sgtty.h sys/time.h stdarg.h syslog.h \ sys/ioctl.h termio.h termios.h \ arpa/inet.h net/route.h net/if.h netinet/in.h \ sys/types.h sys/bsdtypes.h sys/label.h sys/audit.h \ sys/filio.h sys/wait.h sys/param.h sys/security.h \ sys/socket.h sys/sysinfo.h sys/systeminfo.h sys/utsname.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc in yes:no ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # In case the user said --without-pam instead of --disable-pam: if test "$with_pam" = "no" ; then enable_pam=no fi if test "$enable_pam" != "no" ; then for ac_header in security/pam_appl.h security/pam_misc.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc in yes:no ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done fi echo "$as_me:$LINENO: checking for AIX" >&5 echo $ECHO_N "checking for AIX... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef _AIX yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 cat >>confdefs.h <<\_ACEOF #define _ALL_SOURCE 1 _ACEOF else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest* if test "${ac_cv_header_minix_config_h+set}" = set; then echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6 if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking minix/config.h usability" >&5 echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking minix/config.h presence" >&5 echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc in yes:no ) { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; no:yes ) { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} ( cat <<\_ASBOX ## ------------------------------------ ## ## Report this to bug-autoconf@gnu.org. ## ## ------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6 if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_minix_config_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6 fi if test $ac_cv_header_minix_config_h = yes; then MINIX=yes else MINIX= fi if test "$MINIX" = yes; then cat >>confdefs.h <<\_ACEOF #define _POSIX_SOURCE 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_1_SOURCE 2 _ACEOF cat >>confdefs.h <<\_ACEOF #define _MINIX 1 _ACEOF fi { echo "$as_me:$LINENO: checking for directories to include in the safe path..." >&5 echo "$as_me: checking for directories to include in the safe path..." >&6;} SafePath=/bin:/usr/bin test -d /usr/ucb && SafePath=${SafePath}:/usr/ucb test -d /usr/bsd && SafePath=${SafePath}:/usr/bsd cat >>confdefs.h <<_ACEOF #define SAFE_PATH "${SafePath}" _ACEOF # syslog may be in one of the following. They may also be needed for # other reasons, so we just blindly check for them all. echo "$as_me:$LINENO: checking for main in -lbsd" >&5 echo $ECHO_N "checking for main in -lbsd... $ECHO_C" >&6 if test "${ac_cv_lib_bsd_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_bsd_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_bsd_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_main" >&5 echo "${ECHO_T}$ac_cv_lib_bsd_main" >&6 if test $ac_cv_lib_bsd_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBBSD 1 _ACEOF LIBS="-lbsd $LIBS" fi echo "$as_me:$LINENO: checking for main in -lsocket" >&5 echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6 if test "${ac_cv_lib_socket_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_socket_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 echo "${ECHO_T}$ac_cv_lib_socket_main" >&6 if test $ac_cv_lib_socket_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi echo "$as_me:$LINENO: checking for main in -linet" >&5 echo $ECHO_N "checking for main in -linet... $ECHO_C" >&6 if test "${ac_cv_lib_inet_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_inet_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_inet_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_inet_main" >&5 echo "${ECHO_T}$ac_cv_lib_inet_main" >&6 if test $ac_cv_lib_inet_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBINET 1 _ACEOF LIBS="-linet $LIBS" fi badredhatpam=0 if test "$enable_pam" != "no" ; then # RH 7.2 has messed up libpam's installation: it supplies with # libpam.so.0, but not libpam.so. Ditto libpam_misc. test -f /etc/redhat-release -a -f /lib/libpam.so.0 \ -a ! -f /lib/libpam.so && badredhatpam=1 # -ldl may be needed by -lpam. echo "$as_me:$LINENO: checking for main in -ldl" >&5 echo $ECHO_N "checking for main in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_main" >&5 echo "${ECHO_T}$ac_cv_lib_dl_main" >&6 if test $ac_cv_lib_dl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" fi echo "$as_me:$LINENO: checking for main in -lpam" >&5 echo $ECHO_N "checking for main in -lpam... $ECHO_C" >&6 if test "${ac_cv_lib_pam_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pam_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_pam_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_pam_main" >&5 echo "${ECHO_T}$ac_cv_lib_pam_main" >&6 if test $ac_cv_lib_pam_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBPAM 1 _ACEOF LIBS="-lpam $LIBS" fi echo "$as_me:$LINENO: checking for main in -lpam_misc" >&5 echo $ECHO_N "checking for main in -lpam_misc... $ECHO_C" >&6 if test "${ac_cv_lib_pam_misc_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam_misc $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pam_misc_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_pam_misc_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_main" >&5 echo "${ECHO_T}$ac_cv_lib_pam_misc_main" >&6 if test $ac_cv_lib_pam_misc_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBPAM_MISC 1 _ACEOF LIBS="-lpam_misc $LIBS" fi fi # Pick up libcrypt if it exists and this OS needs it. # (Note that on some OS's, libcrypt does not contain the # correct crypt(); instead, libc contains the desired crypt.) if test "$Uname" = SunOS -a $Major = 5 -a $Minor -ge 9 ; then : # SunOS >= 5.9: don't link with -lcrypt elif test "$Uname" = OpenBSD ; then : # don't link with -lcrypt elif test "$Uname" = Darwin ; then : # don't link with -lcrypt else echo "$as_me:$LINENO: checking for main in -lcrypt" >&5 echo $ECHO_N "checking for main in -lcrypt... $ECHO_C" >&6 if test "${ac_cv_lib_crypt_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_crypt_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_crypt_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_main" >&5 echo "${ECHO_T}$ac_cv_lib_crypt_main" >&6 if test $ac_cv_lib_crypt_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF LIBS="-lcrypt $LIBS" fi fi if test "$enable_pam" != "no" ; then for ac_func in pam_start do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done test "$ac_cv_func_pam_start" = yes && for ac_func in misc_conv do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else LIBOBJS="$LIBOBJS $ac_func.$ac_objext" fi done fi for ac_func in fileno do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in gtty do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in syslog do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strdup do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in initgroups do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for lib in os ; do test "$ac_cv_func_initgroups" = yes && break as_ac_Lib=`echo "ac_cv_lib_$lib''_initgroups" | $as_tr_sh` echo "$as_me:$LINENO: checking for initgroups in -l$lib" >&5 echo $ECHO_N "checking for initgroups in -l$lib... $ECHO_C" >&6 if eval "test \"\${$as_ac_Lib+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-l$lib $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char initgroups (); int main () { initgroups (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Lib=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Lib=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Lib'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Lib'}'`" >&6 if test `eval echo '${'$as_ac_Lib'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_LIB$lib" | $as_tr_cpp` 1 _ACEOF LIBS="-l$lib $LIBS" fi done # On IRIX, -lmalloc avoids a problem with default malloc # that causes a core dump. echo "$as_me:$LINENO: checking for main in -lmalloc" >&5 echo $ECHO_N "checking for main in -lmalloc... $ECHO_C" >&6 if test "${ac_cv_lib_malloc_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmalloc $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_malloc_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_malloc_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_malloc_main" >&5 echo "${ECHO_T}$ac_cv_lib_malloc_main" >&6 if test $ac_cv_lib_malloc_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBMALLOC 1 _ACEOF LIBS="-lmalloc $LIBS" fi # May be needed on IRIX echo "$as_me:$LINENO: checking for getpwnam in -lsun" >&5 echo $ECHO_N "checking for getpwnam in -lsun... $ECHO_C" >&6 if test "${ac_cv_lib_sun_getpwnam+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsun $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getpwnam (); int main () { getpwnam (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_sun_getpwnam=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_sun_getpwnam=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_sun_getpwnam" >&5 echo "${ECHO_T}$ac_cv_lib_sun_getpwnam" >&6 if test $ac_cv_lib_sun_getpwnam = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSUN 1 _ACEOF LIBS="-lsun $LIBS" fi # Needed on SysV for shadow passwords. echo "$as_me:$LINENO: checking for main in -lsec" >&5 echo $ECHO_N "checking for main in -lsec... $ECHO_C" >&6 if test "${ac_cv_lib_sec_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsec $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_sec_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_sec_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_sec_main" >&5 echo "${ECHO_T}$ac_cv_lib_sec_main" >&6 if test $ac_cv_lib_sec_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSEC 1 _ACEOF LIBS="-lsec $LIBS" fi # Needed on Digital Unix for shadow passwords. echo "$as_me:$LINENO: checking for main in -lsecurity" >&5 echo $ECHO_N "checking for main in -lsecurity... $ECHO_C" >&6 if test "${ac_cv_lib_security_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsecurity $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_security_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_security_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_security_main" >&5 echo "${ECHO_T}$ac_cv_lib_security_main" >&6 if test $ac_cv_lib_security_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSECURITY 1 _ACEOF LIBS="-lsecurity $LIBS" fi # Needed on Linux for shadow passwords. echo "$as_me:$LINENO: checking for main in -lshadow" >&5 echo $ECHO_N "checking for main in -lshadow... $ECHO_C" >&6 if test "${ac_cv_lib_shadow_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lshadow $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_shadow_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_shadow_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_shadow_main" >&5 echo "${ECHO_T}$ac_cv_lib_shadow_main" >&6 if test $ac_cv_lib_shadow_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSHADOW 1 _ACEOF LIBS="-lshadow $LIBS" fi # Needed on Solaris echo "$as_me:$LINENO: checking for main in -lnsl" >&5 echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6 if test "${ac_cv_lib_nsl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_nsl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_nsl_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6 if test $ac_cv_lib_nsl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi # Needed on SCO-ODT-3.0 for crypt. echo "$as_me:$LINENO: checking for main in -lufc" >&5 echo $ECHO_N "checking for main in -lufc... $ECHO_C" >&6 if test "${ac_cv_lib_ufc_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lufc $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_ufc_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_ufc_main=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_ufc_main" >&5 echo "${ECHO_T}$ac_cv_lib_ufc_main" >&6 if test $ac_cv_lib_ufc_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBUFC 1 _ACEOF LIBS="-lufc $LIBS" fi # We want these before the checks, so the checks can modify their values. test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 # If the user hasn't specified CFLAGS, and we're using gcc, use -O. test -n "$auto_cflags" && test -n "$GCC" && CFLAGS="$CFLAGS -O" # If we're on AIX, not using gcc, add the ansi spec. test "$Uname" = AIX && test -z "$GCC" && CFLAGS="$CFLAGS -qlanglvl=ansi" # If system supports "const", define ConstDef to be "", but if # the system doesn't support "const", define ConstDef to be "-Dconst=". # That makes it suitable for use in the CFLAGS. echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset x; /* SunOS 4.1.1 cc rejects this. */ char const *const *ccp; char **p; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; ccp = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++ccp; p = (char**) ccp; ccp = (char const *const *) p; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_const=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 echo "${ECHO_T}$ac_cv_c_const" >&6 if test $ac_cv_c_const = no; then cat >>confdefs.h <<\_ACEOF #define const _ACEOF fi ConstDef= test "$ac_cv_c_const" != yes && ConstDef="-Dconst=" echo "$as_me:$LINENO: checking for long file names" >&5 echo $ECHO_N "checking for long file names... $ECHO_C" >&6 if test "${ac_cv_sys_long_file_names+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_sys_long_file_names=yes # Test for long file names in all the places we know might matter: # . the current directory, where building will happen # $prefix/lib where we will be installing things # $exec_prefix/lib likewise # eval it to expand exec_prefix. # $TMPDIR if set, where it might want to write temporary files # if $TMPDIR is not set: # /tmp where it might want to write temporary files # /var/tmp likewise # /usr/tmp likewise if test -n "$TMPDIR" && test -d "$TMPDIR" && test -w "$TMPDIR"; then ac_tmpdirs=$TMPDIR else ac_tmpdirs='/tmp /var/tmp /usr/tmp' fi for ac_dir in . $ac_tmpdirs `eval echo $prefix/lib $exec_prefix/lib` ; do test -d $ac_dir || continue test -w $ac_dir || continue # It is less confusing to not echo anything here. ac_xdir=$ac_dir/cf$$ (umask 077 && mkdir $ac_xdir 2>/dev/null) || continue ac_tf1=$ac_xdir/conftest9012345 ac_tf2=$ac_xdir/conftest9012346 (echo 1 >$ac_tf1) 2>/dev/null (echo 2 >$ac_tf2) 2>/dev/null ac_val=`cat $ac_tf1 2>/dev/null` if test ! -f $ac_tf1 || test "$ac_val" != 1; then ac_cv_sys_long_file_names=no rm -rf $ac_xdir 2>/dev/null break fi rm -rf $ac_xdir 2>/dev/null done fi echo "$as_me:$LINENO: result: $ac_cv_sys_long_file_names" >&5 echo "${ECHO_T}$ac_cv_sys_long_file_names" >&6 if test $ac_cv_sys_long_file_names = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_LONG_FILE_NAMES 1 _ACEOF fi echo "$as_me:$LINENO: checking whether #! works in shell scripts" >&5 echo $ECHO_N "checking whether #! works in shell scripts... $ECHO_C" >&6 if test "${ac_cv_sys_interpreter+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else echo '#! /bin/cat exit 69 ' >conftest chmod u+x conftest (SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) if test $? -ne 69; then ac_cv_sys_interpreter=yes else ac_cv_sys_interpreter=no fi rm -f conftest fi echo "$as_me:$LINENO: result: $ac_cv_sys_interpreter" >&5 echo "${ECHO_T}$ac_cv_sys_interpreter" >&6 interpval=$ac_cv_sys_interpreter test "$ac_cv_sys_interpreter" != yes && cat >>confdefs.h <<\_ACEOF #define INTERPRETER_HACK 1 _ACEOF echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi echo "$as_me:$LINENO: checking for pid_t" >&5 echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 if test "${ac_cv_type_pid_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((pid_t *) 0) return 0; if (sizeof (pid_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_pid_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_pid_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 echo "${ECHO_T}$ac_cv_type_pid_t" >&6 if test $ac_cv_type_pid_t = yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6 if test "${ac_cv_type_uid_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 echo "${ECHO_T}$ac_cv_type_uid_t" >&6 if test $ac_cv_type_uid_t = no; then cat >>confdefs.h <<\_ACEOF #define uid_t int _ACEOF cat >>confdefs.h <<\_ACEOF #define gid_t int _ACEOF fi echo "$as_me:$LINENO: checking type of array argument to getgroups" >&5 echo $ECHO_N "checking type of array argument to getgroups... $ECHO_C" >&6 if test "${ac_cv_type_getgroups+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then ac_cv_type_getgroups=cross else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Thanks to Mike Rendell for this test. */ #include #define NGID 256 #undef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) int main () { gid_t gidset[NGID]; int i, n; union { gid_t gval; long lval; } val; val.lval = -1; for (i = 0; i < NGID; i++) gidset[i] = val.gval; n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, gidset); /* Exit non-zero if getgroups seems to require an array of ints. This happens when gid_t is short but getgroups modifies an array of ints. */ exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_getgroups=gid_t else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_type_getgroups=int fi rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_type_getgroups = cross; then cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then ac_cv_type_getgroups=gid_t else ac_cv_type_getgroups=int fi rm -f conftest* fi fi echo "$as_me:$LINENO: result: $ac_cv_type_getgroups" >&5 echo "${ECHO_T}$ac_cv_type_getgroups" >&6 cat >>confdefs.h <<_ACEOF #define GETGROUPS_T $ac_cv_type_getgroups _ACEOF echo "$as_me:$LINENO: checking for size_t" >&5 echo $ECHO_N "checking for size_t... $ECHO_C" >&6 if test "${ac_cv_type_size_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if ((size_t *) 0) return 0; if (sizeof (size_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_size_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_size_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 echo "${ECHO_T}$ac_cv_type_size_t" >&6 if test $ac_cv_type_size_t = yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned _ACEOF fi echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6 if test "${ac_cv_struct_tm+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct tm *tp; tp->tm_sec; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_struct_tm=time.h else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_struct_tm=sys/time.h fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 echo "${ECHO_T}$ac_cv_struct_tm" >&6 if test $ac_cv_struct_tm = sys/time.h; then cat >>confdefs.h <<\_ACEOF #define TM_IN_SYS_TIME 1 _ACEOF fi echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6 if test "${ac_cv_header_time+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_time=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_time=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 echo "${ECHO_T}$ac_cv_header_time" >&6 if test $ac_cv_header_time = yes; then cat >>confdefs.h <<\_ACEOF #define TIME_WITH_SYS_TIME 1 _ACEOF fi void_ok=no echo "$as_me:$LINENO: checking if func signal is compatible with declaring type void" >&5 echo $ECHO_N "checking if func signal is compatible with declaring type void... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { void (*signal())(); signal(1, 0); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_VOID_SIGNAL 1 _ACEOF void_ok=yes ; echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext if test $void_ok = no ; then cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { void (*signal())(); signal(1, 0); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_VOID_SIGNAL 1 _ACEOF void_ok=yes ; echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: checking if sys_errlist is defined" >&5 echo $ECHO_N "checking if sys_errlist is defined... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { extern char *sys_errlist[]; fputs(sys_errlist[0], stdout); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_SYS_ERRLIST 1 _ACEOF echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: checking if errno must be explicitly declared extern" >&5 echo $ECHO_N "checking if errno must be explicitly declared extern... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { printf("%d", errno); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define DONT_DECL_ERRNO 1 _ACEOF echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: checking if regex library is POSIX" >&5 echo $ECHO_N "checking if regex library is POSIX... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { regex_t preg; char buf[100]; regmatch_t pmatch[1]; regcomp(&preg, "a pattern", REG_EXTENDED|REG_ICASE|REG_NOSUB|REG_NEWLINE); regexec(&preg, "a string", 1, pmatch, REG_NOTBOL|REG_NOTEOL); regerror(1, &preg, buf, sizeof(buf)); regfree(&preg); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_POSIX_REGEX 1 _ACEOF echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: checking if compiler supports enum" >&5 echo $ECHO_N "checking if compiler supports enum... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { enum { red, green, blue } color; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_ENUM 1 _ACEOF echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: checking if close-on-exec can be done via ioctl()" >&5 echo $ECHO_N "checking if close-on-exec can be done via ioctl()... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { ioctl(0, FIOCLEX, NULL); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_IOCTL_FIOCLEX 1 _ACEOF echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.$ac_objext conftest.$ac_ext for ac_func in vprintf do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for _doprnt" >&5 echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 if test "${ac_cv_func__doprnt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char _doprnt (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub__doprnt) || defined (__stub____doprnt) choke me #else char (*f) () = _doprnt; #endif #ifdef __cplusplus } #endif int main () { return f != _doprnt; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func__doprnt=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func__doprnt=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 echo "${ECHO_T}$ac_cv_func__doprnt" >&6 if test $ac_cv_func__doprnt = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_DOPRNT 1 _ACEOF fi fi done if test "$enable_pam" != "no" ; then for ac_func in pam_strerror do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi for ac_func in strerror strtol memcpy memset strerror setreuid setregid \ getgroups innetgr iscomsec localtime sysconf sysinfo getdtablesize \ getdomainname sysinfo tcgetattr tcsetattr uname do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # If we're enabling pam support (if PAM available), include pam.o in AC_LIBOBJ. # Note that if we don't have pam_start() on this system, pam.o will still # build correctly for a PAM-less system. In other words, include pam.o # unless the user included the configure option "--disable-pam". if test "$enable_pam" != "no" ; then LIBOBJS="$LIBOBJS pam.$ac_objext" with_pam=1 else with_pam=0 fi ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" # Sed expression to map a string onto a valid variable name. as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.57. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.57, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@CPP@,$CPP,;t t s,@EGREP@,$EGREP,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@SafePath@,$SafePath,;t t s,@ConstDef@,$ConstDef,;t t s,@with_pam@,$with_pam,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be # absolute. ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; *) # Relative if test -f "$f"; then # Build tree echo $f elif test -f "$srcdir/$f"; then # Source tree echo $srcdir/$f else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_HEADER section. # # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='[ ].*$,\1#\2' ac_dC=' ' ac_dD=',;t' # ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='$,\1#\2define\3' ac_uC=' ' ac_uD=',;t' for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; *) # Relative if test -f "$f"; then # Build tree echo $f elif test -f "$srcdir/$f"; then # Source tree echo $srcdir/$f else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } # Remove the trailing spaces. sed 's/[ ]*$//' $ac_file_inputs >$tmp/in _ACEOF # Transform confdefs.h into two sed scripts, `conftest.defines' and # `conftest.undefs', that substitutes the proper values into # config.h.in to produce config.h. The first handles `#define' # templates, and the second `#undef' templates. # And first: Protect against being on the right side of a sed subst in # config.status. Protect against being in an unquoted here document # in config.status. rm -f conftest.defines conftest.undefs # Using a here document instead of a string reduces the quoting nightmare. # Putting comments in sed scripts is not portable. # # `end' is used to avoid that the second main sed command (meant for # 0-ary CPP macros) applies to n-ary macro definitions. # See the Autoconf documentation for `clear'. cat >confdef2sed.sed <<\_ACEOF s/[\\&,]/\\&/g s,[\\$`],\\&,g t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp t end s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp : end _ACEOF # If some macros were called several times there might be several times # the same #defines, which is useless. Nevertheless, we may not want to # sort them, since we want the *last* AC-DEFINE to be honored. uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs rm -f confdef2sed.sed # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >>conftest.undefs <<\_ACEOF s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.defines >/dev/null do # Write a limited-size here document to $tmp/defines.sed. echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#define' lines. echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/defines.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #undef templates' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.undefs >/dev/null do # Write a limited-size here document to $tmp/undefs.sed. echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#undef' echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/undefs.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail rm -f conftest.undefs mv conftest.tail conftest.undefs done rm -f conftest.undefs cat >>$CONFIG_STATUS <<\_ACEOF # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then echo "/* Generated by configure. */" >$tmp/config.h else echo "/* $ac_file. Generated by configure. */" >$tmp/config.h fi cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file fi else cat $tmp/config.h rm -f $tmp/config.h fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi test "$badredhatpam" = 1 && { echo "#" echo "# WARNING." echo "#" echo "# You have /lib/libpam.so.0 but not libpam.so." echo "# In Redhat 7.{1,2}, this is bugid 55651, and is fixed in rpm" echo "# pam-0.75-18.7. You should get that rpm to fix several pam bugs," echo "# but for now you should become root, and make these links by hand:" echo "# ln -s /lib/libpam.so.0 /lib/libpam.so" echo "# ln -s /lib/libpam_misc.so.0 /lib/libpam_misc.so" echo "#" echo "# Then, rm config.cache and rerun configure." echo "#" echo "#" } # The test command will give a non-zero exit code if this isn't # a bad-redhat-pam system. So use 'exit 0' to make everyone happy. exit 0 super-3.30.0/sample.cdumount0000644000104100002640000000112210732537455014315 0ustar willspg#!/bin/sh # This sample script assumes that there is only one cdrom drive, # and that it is on /cdrom. It unmounts the cdrom. prog=`basename $0` # If script invoked w/o super, then exec super to run this script. test "X$SUPERCMD" = "X$prog" || exec /usr/local/bin/super $prog ${1+"$@"} usage() { cat <<-END Use: $prog Purpose: Unmounts a cdrom from /cdrom. END } case $# in 0 ) ;; * ) usage ; exit 1 ;; esac PATH=$PATH:/usr/etc # SunOS 4.x needs this for mount; not sure # if needed for umount. export PATH echo /etc/umount -v /cdrom /etc/umount -v /cdrom super-3.30.0/Artistic0000400000104100002640000001207610732537455012761 0ustar willspg The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C subroutines supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End super-3.30.0/s_hsearch.c0000444000104100002640000001142110732537455013360 0ustar willspgstatic const char rcsid[] = "$Id: s_hsearch.c,v 1.16 2007/03/07 16:44:57 will Exp $"; /** * s_hsearch.c --- PD simple implementation of System V hsearch(3c) routine * It is by Arnold Robbins (arnold@skeeve.atl.ga.us) -- thanks! * * Changed names to have s_* prefix so as not to collide w/ posix names. **/ #include "localsys.h" #include "stdio.h" #include "s_hsearch.h" /* pointer to dynamically allocated tables */ static ELEMENT **hs_Table[HS_SETS] = {NULL, NULL, NULL, NULL}; /* number of elements */ static int Num_elem[HS_SETS] = {-1, -1, -1, -1}; #define Table (hs_Table[which]) static int hashit(); /* * table of primes just below 2^n, n=2..31 for use in finding the right prime * number to be the table size. this table may be generally useful... */ static unsigned int primetab[] = { /* * comment these out, so that table will always have a minimal size... 3, 7, 13, 31, 61, */ 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647 }; /* s_hcreate --- create a hash table at least how_many big */ int s_hcreate (which, how_many) register int which; register unsigned int how_many; { register int i, j; /* * find first prime number >= how_many, and use it for table size */ if (Num_elem[which] != -1) /* already a table out there */ s_hdestroy(which); /* remove it */ j = sizeof (primetab) / sizeof (primetab[0]); for (i = 0; i < j; i++) if (primetab[i] >= how_many) break; if (i >= j) /* how_many bigger than any prime we have, use it */ Num_elem[which] = how_many; else Num_elem[which] = primetab[i]; if ((Table = (ELEMENT **) \ calloc ((unsigned) Num_elem[which], sizeof (ELEMENT *))) == NULL) { return (0); } else { return (1); } } /* idestroy --- destroy a single element on a chain */ static void idestroy (elem) ELEMENT *elem; { if (elem != NULL) { idestroy (elem->next); free ((char *) elem); } } /* s_hdestroy --- nuke the existing hash table */ void s_hdestroy(which) register int which; { register unsigned int i; if (Table != NULL) { /* free all the chains */ for (i = 0; i < Num_elem[which]; i++) idestroy (Table[i]); /* now the table itself */ free ((char *) Table); Num_elem[which] = -1; Table = NULL; } } /* s_hsearch --- lookup or enter an item in the hash table */ ENTRY *s_hsearch (which, entry, action) register int which; ENTRY entry; ACTION action; { ELEMENT e; ELEMENT *ep = NULL; ELEMENT *ep2 = NULL; int hindex; if (Table == NULL) return (NULL); hindex = hashit (which, entry.key); if (Table[hindex] == NULL) /* nothing there */ { if (action == FIND) return (NULL); else { /* add it to the table */ e.item = entry; e.next = NULL; if ((Table[hindex] = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL) return (NULL); *Table[hindex] = e; return (& Table[hindex]->item); } } else { /* something in bucket, see if already on chain */ for (ep = Table[hindex]; ep != NULL; ep = ep->next) { if (strcmp (ep->item.key, entry.key) == 0) { if (action == ENTER) ep->item.data = entry.data; /* already there, just change data */ /* or action was just find it */ return (& ep->item); } else ep2 = ep; } /* at this point, item was not in table */ /* ep2 points at last element on the list */ if (action == ENTER) { if ((ep2->next = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL) return (NULL); ep2->next->item = entry; ep2->next->next = NULL; return (& ep2->next->item); } else return (NULL); } /*NOTREACHED*/ } /* hashit --- do the hashing algorithm */ /* * algorithm is sum of string elements, plus string length * mod table size. */ static int hashit (which, text) register int which; register char *text; { register long int sum = 0; register int i; for (i = 0; text[i] != '\0'; i++) sum += text[i]; sum += i; return (sum % Num_elem[which]); } /* * Prints all elements of the table, in no particular order. */ void hprint(which, f) register int which; void (*f)(); /* (*f) is a function that will be called by hprint, is passed * (hashIndex, ptrToKey, ptrToData), and should print these. */ { ELEMENT *p; int i; for (i=0; inext) (*f)(i, p->item.key, p->item.data); } } /* * A function suitable for passing to hprint, if both key and data are text * suitable for passing to printf. You can use this one or supply your * own. */ void htext(indx, key, data) int indx; char *key; char *data; { printf("(%d)\t%s :\t%s\n", indx, key, data); } super-3.30.0/sample.tab0000444000104100002640000000645510732537455013241 0ustar willspg# This file lists commands that super(1) will execute for you as root. # See the super.5 man page for information. # Global options ========================================================= # # Shell patterns are usually much more convenient to deal with in # a super.tab file. :global patterns=shell # Limits on arguments: ## # 0 or 1 argument per command ## :global nargs=0-1 # Arguments must be simple words w/o characters that may special to shells. # ==> N.B. Put this *after* you change the "patterns=xxx" option # :if $PATTERNS == shell :global arg1-99="[[-/:+.,_a-zA-Z0-9]]" :if $PATTERNS != shell :global arg1-99="^[-/:+.,_a-zA-Z0-9]*$$" # Log super actions to a file, under uid=sysmgr. (Note that loguid has to # be part of same :global_options entry as logfile.) :global logfile=/usr/adm/super.log loguid=sysmgr # Mail msgs regarding super errors to user joeblow (default is no mail): # :global mail="/usr/bin/mailx -s '*** super ***' joeblow" # Also log via syslog (just for demonstration :-). # :global syslog=y syslog_error=auth.local1 syslog_success="LOG_INFO | LOCAL2" # This says the user doesn't need to re-enter password if super cmds are # issued frequently (so that we "know" they are coming from one person). :global renewtime=y # ======================================================================= # Give access to line printer commands to some users outside office hours. # (During office hours, the regular system manager keeps these functions.) # :define OfficeHours {8:00-12:00,13:00-17:00}/{mon,tue,wed,thu,fri} # Some line printer commands that we want to give away to certain users. # (The asterisk in the FullPath is replaced by the command; thus # typing super enable executes /usr/bin/enable.) :define LP_commands {enable,disable,lpstat}::/usr/bin/* \ {lpadmin,lpsched,lpshut}::/usr/lib/* # The users who can use the line printer commands, and the hosts # from which they can use the commands: # :define LP_users jack@bucket jill@hill # During non-office hours, the following people can use the LP_commands. # (Note the use of "!time" to mean time _not_ in the $OfficeHours range.) $LP_commands $LP_users !time~$OfficeHours # ======================================================================= # The people who can use timeout/restart are: # :define TimeoutUsers :operator :wheel gv phillips srk # timeout and restart timeout /usr/local/bin/timeout $TimeoutUsers \ info="Temporarily stop any processes of any user." \ password=y echo_nopw /bin/echo $TimeoutUsers \ info="echo args" \ password=n echo_pw /bin/echo $TimeoutUsers \ info="echo args" \ password=y restart /usr/local/bin/restart $TimeoutUsers \ info="Restart a timeout'd process before the scheduled time." # ======================================================================= # Restrictions on CD-ROM mounting: # tas is the only user who may mount cd's on elgar; anybody in # group xyz may mount cd's on alpha or delta; and anybody on a # host in the netgroup "india" may mount a CD on the "india" machines. cdmount /usr/local/bin/cdmount \ info="Mounts a CD-ROM on /cdrom" \ tas@elgar \ :xyz@{alpha,delta} \ @+india :global patterns=posix/extended posix1 /bin/echo arg1="(abc.*xyz|zyx.*abc)" user~.* :global patterns=posix/extended/icase posix2 /bin/echo arg1="(abc.*xyz|zyx.*abc)" user~.* super-3.30.0/strqtokS.c0000444000104100002640000001511010732537455013252 0ustar willspgstatic const char rcsid[] = "$Id: strqtokS.c,v 1.27 2004/04/30 17:00:58 will Exp $"; #include #include #ifndef NULL #define NULL 0 #endif /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ /* strqtokS.c, v1.1 * Derived from strqtok.c v3.0. * Stripped down for simplicity and speed. */ /* The pointer into the string, indicating where to start next token search. * The purpose of making it extern is that the caller can stash away * a copy of strqS_start, process another string, then restore the pointer * and finish processing the first string. */ char *strqS_start=NULL; /* strqS_qm and strqS_cc give the current sets of quotemarks and comment * characters, used if the quotemarks or commentchars argument, respectively, * is a NULL ptr. Each of these should point an array of 256 chars; * each of those chars should be 1 (0) if the corresponding character * is (is not) in the set. * If you pass an actual string in, then the arrays strqS_qm_set and * strqS_cc_set will be initialized, and strqS_qm and strqS_cc will point * to them. But if you pass null ptrs for quotemarks and commentchars, * then strqS_qm and strqS_cc will be used as they are -- so you have to * make sure they point to something valid. For instance, you can initialize * strqS_qm_set and strqS_cc_set, and make strqS_qm & strqS_cc point to them. * Or you can initialize your own array and make strqS_qm and strqS_cc point * to your own arrays. */ unsigned char *strqS_qm=NULL, *strqS_cc=NULL; unsigned char strqS_qm_set[256], strqS_cc_set[256]; /* strqS_delim is set to the character that terminated the last token * (and was replaced with a null character). */ char strqS_delim='\0'; /* strqtokS(s, delim, quotemarks, commentchars, flags) * ...is same as strtok(s, delim), except that * o quotemarks: tokens are quoted by pairs of these characters, * allowing characters that are normally * token delimiters to be part of a token. * o commentchars: if one of these characters occurs outside a * quoted token, everything is ignored up to the next * \n or \0, inclusive. * o flags: * flags & 01: quotemarks are stripped from tokens. * Default: quotemarks are left in returned tokens. * o The following approximation of Bourne shell rules is used for * interpreting backslash-X: * A) If X is null: the backslash is discarded. * B) \newline is discarded entirely. * C) Otherwise, if outside a quote: \X is replaced by plain X, and * not treated as a delimiter, quotemark, or comment character. * D) Otherwise we are inside a quote: discard the backslash if * preceding left quote or another backslash; and in any case * the following character is plain: * \\ -> \ * \Q -> Q (Q is the char that started the quote) * \X -> \X (ie the backslash is a plain character) * If flag 0200 is enabled, the backslash must NOT be part of the * delimiter, quotemark, or comment char sets, or else the * results are undefined. * o Backslash-newline is always completely discarded, as if it had * never been typed. * * Note: strqtokS(), strqtok(), and strtok() are completely independent, * so one may safely use them in parallel. */ char * strqtokS(s, delim, quotemarks, commentchars, flags) char *s; /* String to tokenize. NULL to continue same str */ char *delim; /* Token delimiters. Can be changed w/ each call. */ char *quotemarks; /* Quote marks. Can be changed w/ each call. */ char *commentchars; /* Comment chars. Can be changed w/ ea call. */ unsigned int flags; /* flags & 01 -> strip quotes; */ { register unsigned char *p, *q; register unsigned char *qm, *cc; unsigned char leftquote = '\0'; char *token; register int inquote, bn, incomment; /* Strip quotemarks from tokens? */ int stripquote = (flags & 01); /* New string? */ if (s) strqS_start = s; /* Need new qm or cc arrays? */ if (quotemarks) { memset(strqS_qm_set, '\0', sizeof(strqS_qm_set)); for (p=(unsigned char *) quotemarks; *p; ) strqS_qm_set[*p++] = 1; qm = strqS_qm_set; } else { qm = strqS_qm; } if (commentchars) { memset(strqS_cc_set, '\0', sizeof(strqS_cc_set)); for (p=(unsigned char *) commentchars; *p; ) strqS_cc_set[*p++] = 1; cc = strqS_cc_set; } else { cc = strqS_cc; } if (!strqS_start) return (char *) NULL; /* Skip leading delimiters and comments. */ /* Use p and q to walk through the user's string: * p will follow input characters; * q will overwrite w/ outputted characters, minus possibly-stripped * quotes and including nulls after each token. */ p = (unsigned char *) strqS_start; /* Advance pointer p past delimiters and comments */ for (bn=0; p && *p && (strchr(delim, *p) || cc[*p] || (bn = (*p=='\\' && *(p+1) == '\n'))) ; ) { if (cc[*p]) { /* It's a comment */ p = (unsigned char *) strchr((char *)p, '\n'); if (p) p++; } else if (bn) { /* `\n' */ p += 2; bn = 0; } else { p++; } } if (!p || !(*p)) return (char *) NULL; /* `token' will be used to return a ptr to the token */ q = p; token = (char *) p; inquote = incomment = 0; /* Now figure out each arg */ /* NOTE: we break out of the while loop at the end of a token. */ while (*p) { if (*p == '\\') { /* at ``\X''; Advance to X character and process it */ if (! *(++p)) break; /* reached end of string */ if (*p == '\n') { p++; /* Discard backslash-newline entirely */ } else if (inquote && (*p == '\\' || *p == leftquote)) { *q++ = *p++; } else if (inquote) { *q++ = '\\'; *q++ = *p++; } else { *q++ = *p++; } } else if (!inquote) { if (strchr(delim, *p) || cc[*p]) { strqS_delim = (char) *q; /* Reached end of token */ *q = '\0'; p++; /* advance p for next token */ break; /* break out of while loop */ } else if (qm[*p]) { inquote = 1; /* Beginning a quoted segment */ leftquote = *p++; /* Save quote char for matching with */ if (!stripquote) *q++ = leftquote; } else { *q++ = *p++; } } else if (inquote && leftquote == *p) { inquote = 0; /* Ending a quoted segment */ p++; if (!stripquote) *q++ = leftquote; } else { *q++ = *p++; } } strqS_start = (char *) p; if (*q) { strqS_delim = (char) *q; *q = '\0'; } return token; } super-3.30.0/super.1.in0000444000104100002640000004370110732537455013110 0ustar willspg.TH SUPER 1 local .\" .\" Copyright (c) 1993 by California Institute of Technology. .\" Written by William Deich. Not derived from licensed software. .\" .\" You may distribute under the terms of either the GNU General Public .\" License or the Artistic License, as specified in the README file. .\" .\" .SH NAME super \- execute commands setuid root. .SH SYNOPSIS To execute a command: .br .ti +.5i .B super .RI [\ \-r\ reqpath ] .I command .RI [ " args " ] .br .ti +.5i .B super .RI [\ \-r\ reqpath ] .B \-o .I path .RI [ " args " ] .br .ti +.5i .B command .RI [ " args " ] .sp To list available commands: .br .ti +.5i .B super .RI [ \-H | \-f ] .RI [ \-S ] .sp For usage and/or version information: .br .ti +.5i .B super .RI [ \-h ] .RI [ \-V ] .sp For debugging and development: .br .ti +.5i .B super .B \-b .br .ti +.5i .B super .B \-c .RI [ " superfile " ] .br .ti +.5i .B super .RI [ \-d | \-D | \-t ] .RI [ \-S ] .RI [ MasqOptions ] .RI [ \-H | \-f | command... ] .sp .ti +0.5i MasqOptions: .RS .RS .nf .I \-F\ file .I \-T\ hh:mm/dayname .I \-G\ gid .I \-U\ uid .I \-M\ mach .fi .RE .RE .SH DESCRIPTION .B Super allows specified users to execute scripts (or other commands) as if they were root; or it can set the uid, gid, and/or supplementary groups on a per-command basis before executing the command. It is intended to be a secure alternative to making scripts setuid root. Super also allows ordinary users to supply commands for execution by others; these execute with the uid, gid, and groups of the user offering the command. .PP .B Super consults a .RI `` super.tab '' file to see if the user is allowed to execute the requested .IR command . If permission is granted, .B super will exec .IR pgm\ [\ args\ ], where .I pgm is the program that is associated with this .I command. (Root is allowed execution by default, but can still be denied if a rule excludes root. Ordinary users are disallowed execution by default.) .PP The most common sort of entry in a .I super.tab file pairs a simple .I command with a .I pgm path. But in fact, the command in the .I super.tab file is actually treated as a pattern, and .I any user-entered command that matches this pattern causes the associated .I pgm to be executed. If the listed .I pgm contains an asterisk, then the asterisk is replaced with the command entered by the user. One use of this is to let any program in a certain directory be executed by a user. For example, if the entry contains the command/pgm pairs .ta 1.75i 2i .ti +.5i .I "CommandPattern Program" .br .ti +.5i .B "scripts/* \(-> /usr/local/super/*" .br .ti +.5i .B "\ \ \ * \(-> /usr/local/somedir/*" .br then the translations made are .ti +.5i .I "User's Command Executed Program" .br .ti +.5i .B "scripts/xyz \(-> /usr/local/super/scripts/xyz" .br .ti +.5i .B "xyz \(-> /usr/local/somedir/xyz" .br .PP Some commands can only be run after the user enters his or her password. These commands can then be run multiple times until some expiration time, at which point the password needs to be re-entered. The list of password-requiring commands and the password durations are set in the same file that records the valid users for each command. .PP If \fIcommand\fR is a symbolic link (or hard link, too) to the .B super program, then typing .ti +.5i % \fIcommand args\fP .br is equivalent to typing .ti +.5i % \fBsuper\fP \fIcommand args\fP .br (The .I command must not be .BR super , or .B super will not recognize that it's being invoked via a link.) .PP .B Super without any arguments will display the list of commands that may be executed by the user. .PP For security, the following precautions are taken before exec'ing: .TP (a) all descriptors save 0,1,2 are closed; .TP (b) all of the user's environment variables are discarded, save for TERM, LINES, and COLUMNS. If TERM contains any characters other than {-/:+._a\-zA\-Z0\-9}, it is discarded. If LINES or COLUMNS contains any characters other than [0\-9], it is discarded. To these are added reasonable values for: .RS .HP USER and LOGNAME: both are set to the username associated with the real uid of the program running under .BR super ; .HP HOME: set to the login directory of the user running .BR super ; .HP ORIG_USER, ORIG_LOGNAME, ORIG_HOME: the values of USER, LOGNAME, and HOME that refer to the user who invoked .BR super . (These values are computed by .BR super , and are not the values set by the caller, so they are a reliable description of the caller. These are normally the same values as USER, LOGNAME, and HOME, but they will differ if the super command changes uid or gid before executing the program.); .HP IFS: set to blank, tab, newline; .HP PATH: set to .IR @SAFE_PATH@ . .HP SUPERCMD: set to \fIcommand\fP. .HP additional environment variables as specified in the .I super.tab file (see below). .RE .in -.5i .TP (c) all signal handling is reset to the default. .PP If .I Super is executed without arguments, it will print the commands that the user may execute, one command per line. .B "Super \-H" prints a long-winded description of each command that the user may execute. .br The .I CmdPat is the command pattern, and .I FullPath is the full path that will be executed. The super.tab file can specify initial arguments that that precede any user-supplied arguments; these arguments, if any, are printed after the .I FullPath column. .SH User-Defined Super.tab Files .PP Ordinary users can supply their own super files. This lets users give well-controlled setuid/setgid access to their programs: the user who offers the program gets the assurance of safe IFS settings, safe environment variable settings, etc; and the user who executes the program knows that it will execute under the uid and gid of the offering user. If a .I command is entered in the form .RS \fBsuper\fP \fIloginname\fB:\fIcmd\fR .RE .I super looks for .I cmd in the file .BR .supertab , in the home directory of account .IR loginname . The .I cmd will be executed using the uid, gid, and supplementary groups (if any) of user .IR loginname . .PP The usual super options (such as \fB\-H\fP) can be applied to a user's .supertab file. For example, help information about one command can be had by using: .ti +0.5i \fBsuper \-H\fP \fIloginname\fP\fB:\fP\fIcmd\fP .br Likewise, help information about all of .IR loginname 's commands can be obtained with: .ti +0.5i \fBsuper \-H\fP \fIloginname\fP\fB:\fP .br .ta 0.5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i 4.0i 4.5i 5.0i 5.5i 6.0i 6.5i 7.0i .PP Links to per-user commands can be created and used in a manner similar to making symlinks to .I super itself. If .I command is a symbolic link to a user's .supertab file, and that .supertab file is .RS .HP (a) executable, and .br .HP (b) begins with .RS .B #!\ /path/to/super \-o .RE .RE .sp then the following pair are completely equivalent: .RS .IB % \ super \ loginname : command .br .I % command .RE If the .BR #! -line would be longer than the typical Unix limit of 32 characters, you can instead start the .supertab file with: .RS .nf #! /bin/sh # Keep this backslash -> \\ exec /long/path/to/the/super/executable -o $0 ${1+"$@"} ... .fi .RE (The above takes advantage of the fact that super allows comments to be backslash-continued, but the shell doesn't.) .PP Per-user .supertab linking works as follows: if .I /path/to/xyz is a symlink to some user's .supertab file, and the .supertab file begins with \fI#! /path/to/super -o\fP, then the shell will invoke .I super with arguments something like .RS .B super -o /path/to/xyz [args] .RE Super checks that .I /path/to/xyz is a link to a real .supertab file, and then always turns the last part of the path (here .IR xyz ) into the command to execute. .PP .ce 1 .B ** Security Warning ** .br Note that if you use symlinks to a per-user .supertab file, then you must trust that the .supertab file will actually execute a super command, instead of doing something nasty. That is because .I super itself isn't invoked until the shell has opened the .supertab file and done whatever the .supertab file tells it to do. By contrast, the direct command .BI super \ loginname : cmd doesn't involve any shell processing of the .supertab file. .ta 1.75i 2i .SH REGULAR OPTIONS .TP .BR \-V Print the super version number. .TP .BR \-S When .B super prompts for a password, this forces it to prompt on stdin, even if the default .RB ( /dev/tty ) is readable and writable. .I Note: This only applies to password-type authentication \(em that is, the older type of authentication wherein .B super itself prompts for the password; PAM authentication is handled by your system's PAM modules. .TP .BR \-f This requests a list of available commands in a terse format useful for processing by scripts. (\fB\-f\fP stands for facts, as in ``just the facts, m'am''). .TP .BI \-r reqpath Tells super to generate an error if the program associated with this .I command is not .I reqpath. This helps you write scripts that ensure that super only executes what they expect it to execute. See step\ 4 of the section, ``Creating Super Scripts'', for an example of its use. .TP .B \-H Causes .B super to print a verbose listing of the commands available to the user. It prints both the .I command and its translation to a program .IR pgm . If the displayed .I pgm contains an asterisk, then the actual program executed is formed by replacing the asterisk with the .IR command entered by the user. The following examples show the kinds of lines that may be displayed with the .B \-H option: .sp .I "Example 1." .ti +0.5i .B super skill \(-> .I /usr/local/bin/skill .sp Typing .B super\ skill will execute .BR /usr/local/bin/skill . .sp .I "Example 2." .ti +0.5i .B super {lp*} \(-> .I /usr/bin/* .sp This example contains asterisks on both the left and right sides. The left side shows the valid pattern you must match to execute the command shown on the right-hand side. Usually, the right-hand side has no asterisk, just a full path to a command to execute. If there .I is an asterisk present, it is replaced by the command you entered, thereby forming the actual executed command. Thus, if you type .BI super\ lp xxx (where .I xxx is any string), .B super will execute .BI /usr/bin/lp xxx. .sp .I "Example 3." .ti +0.5i .B super {co*} \(-> .I /usr/bin/compress .sp The asterisk on the left-hand side means you can enter .BI super\ co xxx (where .I xxx is any string), but since the right-hand side doesn't contain an asterisk, .BI co xxx will always execute .BR /usr/bin/compress . .TP .BR \-t This enables ``test'' mode. It does all normal checks except for those requiring user input (passwords and variables that the user must enter), but doesn't execute any command. Instead, it exits with status code 0 if the command is ok to execute, else 1. All normal error message output is generated in the usual way, but no special debug messages are generated. Thus, it is a useful means for a script to check if a command is likely to work, and hence reasonable to exec super. Let's say that a script /usr/local/bin/foo wants to invoke itself using \fIsuper foo\fP (See the section ``Creating Super Scripts'' for how to avoid infinite loops when doing this!) the script can use the \fB\-r\fP option to ensure that \fIsuper foo\fP refers to the correct file, and it can use test mode to ensure that \fIsuper foo\fP is a valid command: .in +.5i .nf prog=\`basename $0\` /usr/local/bin/super -t -r $0 $prog case $? in 0 ) exec /usr/local/bin/super -t -r $0 $prog ;; * ) echo "Super $prog doesn't work!" ... So take appropriate action ... ;; esac .fi .in -.5i .SH DEBUG AND DEVELOPMENT OPTIONS .PP These options are useful when creating and debugging .I super.tab files. They have little or no value to the everyday user. With the exception of the .B \-b option, they can be combined with the regular options, above. .TP .BR \-b Print the names and values of built-in variables, then exit. Useful for administrators to learn the values against which builtin variables can be tested. .TP .BR \-c [\fIsuperfile\fP] Tells .I super to check the syntax of the entries in the .IR superfile , but not to execute any command. If no .I superfile is given, the regular .I super.tab is checked. The exit code is 0 if the file's syntax is ok; otherwise the exit code is 1 (and an error message is printed). After modifying a super file, you should use this option to check its integrity. .sp Note that .I "super \-c" isn't a complete check that you've correctly set up an entry, because you can create syntactically valid entries that don't do exactly what you want. Therefore, you should also use .IR "super \-d cmd" to make sure that the command you've entered will be executed with the correct arguments, uid, gid, umask, and so on. .TP .BR \-d This enables debug mode, in which case (a) debugging information is printed while checking a user for validity, and (b) the command isn't actually executed. Useful to check if a new entry in the .I super.tab file (see below) has been handled properly. .TP .BR \-D Same as .BR \-d , plus prints more information about variables defined in the .I super.tab file. .TP .BR \-F \fIsuperfile\fP This option is only used for debugging, and lets you test a superfile before installing it. No command will actually be executed. It also turns on a non-verbose debugging, showing the matched command names and reasons for accepting or rejecting the command. .TP .BR \-G \fIgid\fP This option is also used for debugging, and tells .I super to act as if the caller's groupid or groupname was .IR gid . It carries the same restrictions and debug info as the \-F option. .TP .BR \-U \fIuid\fP This option is also used for debugging, and tells .I super to act as if the caller's uid or username was .IR uid . It carries the same restrictions and debug info as the \-F option. .TP .BR \-M \fImach\fP This option is also used for debugging, and tells .I super to act as if the caller's host (machine) was .IR mach . It carries the same restrictions and debug info as the \-F option. .TP .BR \-T \fIhh\fP:\fImm\fP/\fIdayname\fP This option is also used for debugging, and tells .I super to act as if the execution time is .IR hh : mm / dayname . This lets you check if a time specification in the .I super.tab file is properly restricting execution. It carries the same restrictions and debug info as the \-F option. .SH FILES .TP .I @SUPERDIR@/super.tab contains the list of commands that .B super may execute, along with the names of the user/group combinations who may execute each command. The valid-user line can restrict use to particular users or groups on different hosts, so a single super.tab file can be used across a network. .TP .IR @TIMESTAMP_DIR@/ username is used as a timestamp for the last time that the user entered his or her password. .SH CREATING SUPER SCRIPTS You must be exceedingly careful when writing scripts for .BR super . A surprising variety of ordinary commands can, when run setuid-root, be exploited for nasty purposes. Always make your scripts do as little as possible, and give the user as few options as possible. .PP Think twice about side-effects and alternative uses of these scripts. For instance, make sure your script doesn't quietly invoke the user's .I .cshrc or similar file. Or, you might write a script to allow users to mount cd-rom's by executing .BR mount(8) . But if you don't write it carefully, a user could mount a floppy disk containing, say, a setuid-root shell. .PP Security issues aside, here are some hints on creating super scripts: .TP 1. Scripts must begin with \fB#!\ \fIinterpreter-path\fR. .TP 2. Some variants of csh will not run setuid scripts unless the \-b flag (force a "break" from option processing) is set: .ti +.5i #!/bin/csh \-fb .br Similarly, if your .I super.tab file starts a shell such as csh or tcsh, you may want to include the \-b option in the .I super.tab file, so that you don't have to remember to type it on the command line every time; use a line like the following in the .I super.tab file: .ti +.5i SHELL "/usr/bin/csh \-fb" some_priv_user .br N.B. This is by way of example only; it's not a very good idea to really let somebody become root without any password check. .TP 3. Better still, avoid csh scripts entirely -- they are harder to write safely than Bourne-shell scripts. .TP 4. It's nice to make the .B super call transparent to users, so that they can type .ti +.5i % \fBcdmount\fP \fIargs\fP .br instead of .ti +.5i % \fBsuper cdmount\fP \fIargs\fP .br You can make a script .B super itself by beginning the script in the following way: .in +.5i .nf #!/bin/sh prog=\`basename $0\` test "X$SUPERCMD" = "X$prog" || exec /usr/local/bin/super -r $0 $prog ${1+"$@"} .fi .in -.5i Here, the path that is exec'd should be replaced with the path at your site that leads to .I super. The option .IR -r $0 is a sanity-check option: it tells super that it's an error if ``super $prog'' doesn't execute ``$0'', ie this self-same program. (Also, see the \fB\-t\fP option for how a script can check that \fIsuper $prog\fP will work before doing an \fIexec super\fP.) .TP 5. Some programs need certain directories in the path. Your super scripts may have to add directories like .I /etc or .I /usr/etc to make commands work. For instance, SunOS\ 4.1 needs .I /usr/etc in the path before it can mount filesystems of type ``hsfs''. .TP 6. By default, \fBsuper\fP only changes the effective uid. Some programs (e.g. \fBexportfs\fP under SunOS\ 4.1.x) require the real uid to be root. In that case, you should put an option like ``\fIuid=root\fP'' or ``\fIu+g=root\fP'' into the .I super.tab file. .SH "SEE ALSO" .BR super (5). .SH AUTHOR Will Deich .br will@ucolick.org .SH NOTES If the .I super.tab file isn't owned by root, or if it is group- or world-writable, .B super won't run setuid-root. (If the user's real uid is root, .B super won't run at all; otherwise, the effective uid reverts to real uid.) There is a race condition when using password-requiring commands, but it doesn't affect security: if a user is running two copies of \fBsuper\fR simultaneously, and both processes try to update the user's password timestamp file at the same time, then it is possible for one of the \fBsuper\fR commands to fail. Workaround: a single user shouldn't execute two password-requiring \fBsuper\fR programs simultaneously. super-3.30.0/error.c0000444000104100002640000003760210732537455012563 0ustar willspgstatic const char rcsid[] = "$Id: error.c,v 1.79 2007/03/07 00:23:27 will Exp $"; /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ /********************************************************************/ /* * If you don't have localsys.h, supply the following: * #define HAVE_STDARG_H if you have (ie ANSI C variadic arg lists) * #define HAVE_SYSLOG_H if you have and syslog() function */ /* * If you don't like the following "priority" and "facility" values for * use with syslog(), supply the following: * #define SYSLOG_PRIORITY nnn ...priority for logging if syslog() use is * enabled; default is LOG_ERR. * #define SYSLOG_FACILITY nnn ...syslog() facility code if syslog() use is * enabled; default is LOG_USER. * We call Strerror(e) to return error messages for error code e. This * routine is expected to simply be strerror(e) + wrapper code to ensure * that e is in the valid range. */ #include "localsys.h" /********************************************************************/ /* Error -- print error message, then optionally die. * Usage: Error(show_perror, die, format, args... ); * Print error message according to format & args. * If show_perror != 0 && errno != 0, follow error message with perror(""). * (If show_perror !=0, but errno==0, follow error msg with "\n"). * If die != 0, exit with exit(die). * There are several external variables that a calling program can modify: * error_prog: program name preceding msgs to stderr. Default off. * error_log_prog: program name preceding msgs to logfile. Default off. * error_stderr: controls whether messages go to stderr. Default enabled. * error_logfile: controls whether messages go to a logfile. Default off. * error_command: controls whether msgs go to a popen'd command. Def off. * error_syslog: controls whether messages go to [r]syslog. Default: off. * error_rlog_host: host to receive rsyslog() messages. Def: ourselves. * error_user: Controls username used when printing messages. * error_tag: Controls use of error_{srcfile,line,nl}. Default off. * error_fflush: fflush(stdout) before printing error message. Default on. * error_srcfile, error_line, error_nl: error_srcfile is a file in * which an error was found, starting at line error_line * and continuing over error_nl lines. * error_counter: incremented with every call to Error(). * In detail: * If error_prog != NULL, then the message to stderr is preceded * with ": ". * If error_stderr == 0, then the message is NOT directed to stderr. * By default error_stderr == 1. * If error_logfile != NULL, then the message is also directed to * that file, preceded with * error_log_prog: user@hostname timestamp * If error_log_prog is NULL, it isn't printed. We keep separate * error_prog and error_log_prog so that the program name can be * printed on stderr (where there might otherwise be confusion to the * user about which program it is) but optionally not printed in the * logfile, which is typically unique to the program, so that the * program name is redundant. * If error_user != NULL, then the username used in messages is error_user, * instead of the default name found by looking at the user's password * entry. * If error_command != NULL and *error_command != '\0', then error_command * is popen'd and the message is piped in. If the popen fails, Error() * is silent about the problem. NOTE: the command is executed separately * for each call to this routine. * If HAVE_SYSLOG_H is defined, and the caller sets error_syslog != 0, * then the message is passed to [r]syslog(), at priority error_priority, * using facility error_facility. We compile with rsyslog, but if the * remote host argument is NULL at the time we open the log, we use the * syslog routines instead. * The fmt string and the printf output must be less * than MAXPRINT characters each. This is because syslog() accepts a * printf-style variadic argument list, but it doesn't have a va_list * version. Therefore we print into a string and pass that onto syslog(). * As a side effect, you can't use syslog-specific "%m" in the fmt. * If the error_prog string is non-null, then just before the first * call to syslog, openlog is called with an ident string = error_prog. * Note that this is done just once: you can't change error_prog * between messages. * If error_tag is !0, or if the _first_ two characters of the output * format are "%t", then the output is preceded with a message like * the following: * (a) error_srcfile == NULL: * "" # error_line <= 0 * "line %d: " # error_line > 0, error_nl <= 1 * "lines %d..%d: " # error_line > 0, error_nl > 1 * * (b) error_srcfile == "-": * "in : " # error_line <= 0 * "line %d in : " # error_line > 0, error_nl <= 1 * "lines %d..%d in : " # error_line > 0, error_nl > 1 * (c) error_srcfile == anothername: * "in file `%s': " # error_line <= 0 * "line %d in file `%s': " # error_line > 0, error_nl <= 1 * "lines %d..%d in file `%s': " # error_line > 0, error_nl > 1 * Notes: * 1. If error_prog and this line information is printed, then * the program name is _not_ suffixed with ":" -- that way, the * output looks something like: * progxyz (lines 232..255 in file `.......'): errmsg * 2. In the event that the first two characters are "%t", they enable * tagline printing but are not printed. * Return code is -1, so you can print error messages and return an error * code with return Error(...); */ FILE *error_logfile = NULL; char *error_prog = NULL; char *error_log_prog = NULL; char *error_command = NULL; char *error_user = NULL; int error_counter = 0; int error_stderr = 1; int error_syslog = 0; char *error_rlog_host = NULL; int error_line = -1; int error_nl = -1; char *error_srcfile = NULL; int error_tag = 0; int error_fflush = 1; #ifdef HAVE_SYSLOG_H /* Default error priority */ #ifndef SYSLOG_PRIORITY #define SYSLOG_PRIORITY LOG_ERR #endif /* Default error facility */ #ifndef SYSLOG_FACILITY #ifdef LOG_USER #define SYSLOG_FACILITY LOG_USER #else #define SYSLOG_FACILITY 0 #endif #endif void ropenlog P__(( char *ident, int logopt, int facility, char *host )); void rsyslog P__(( unsigned int level, char *fmt, ... )); int error_priority = SYSLOG_PRIORITY; int error_facility = SYSLOG_FACILITY; int openlog_done = 0; static int using_rsyslog = 0; void OpenLog(prog, opt, fac) char *prog; int opt; int fac; { if (error_rlog_host != NULL) { ropenlog(prog, opt, fac, error_rlog_host); using_rsyslog = 1; } else { openlog(prog, opt, fac); using_rsyslog = 0; } } void SysLog(pri, buf) int pri; char *buf; { if (using_rsyslog) { rsyslog(pri, "%s", buf); } else { syslog(pri, "%s", buf); } } #endif static int uid = -1; static char user[128] = ""; static char hostname[1024] = ""; extern char *Strerror(); #define MAXPRINT 1300 #define StrLCat(s1, s2, maxlen) strncat(s1, s2, ((maxlen) - strlen(s1) - 1)) char *taglines(); #ifdef HAVE_STDARG_H /* VARARGS3 */ int Error( int show_perror, /* If errno != 0, follow msg with perror("") */ int die, /* If !0, exit with exit(die) */ char *fmt, /* Print rest of args with fprintf(stderr, fmt, ...) */ ... ) { va_list ap; int error; FILE *error_cmd = NULL; char *tag; int pctt; if (error_fflush) fflush(stdout); error = errno; error_counter++; /* Figure out line tagging */ pctt = strncmp(fmt, "%t", 2) == 0; tag = ( pctt || error_tag ) ? taglines(3) : NULL; if (pctt) fmt += 2; /* Program name */ if (error_stderr && error_prog) (void) fprintf(stderr, "%s%s ", error_prog, (tag && *tag) ? "" : ":"); if (error_command && *error_command) error_cmd = popen(error_command, "w"); if (error_log_prog) { if (error_logfile) (void) fprintf(error_logfile, "%s%s ", error_log_prog, (tag && *tag) ? "" : ":"); if (error_cmd) (void) fprintf(error_cmd, "%s%s ", error_log_prog, (tag && *tag) ? "" : ":"); } if (error_logfile || error_syslog || error_command) { if (getuid() != uid || *user == '\0') { struct passwd *pw; int e = errno; pw = getpwuid((uid=getuid())); if (pw) (void) strcpy(user, pw->pw_name); errno = e; } } if (error_logfile || error_cmd) { /* user@hostname & timestamp */ char *s; time_t tptr; if (*hostname == '\0') (void) gethostname(hostname, sizeof(hostname)); (void) time(&tptr); s = ctime(&tptr); s[strlen(s) - 1] = '\0'; if (error_logfile) (void) fprintf(error_logfile, "%s@%s %s\t", error_user ? error_user : user, hostname, s); if (error_cmd) (void) fprintf(error_cmd, "%s@%s %s\t", error_user ? error_user : user, hostname, s); } if (error_stderr) { if (tag) (void) fputs(tag, stderr); /* User's msg */ va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); } if (error_logfile) { if (tag) (void) fputs(tag, error_logfile); /* User's msg */ va_start(ap, fmt); (void) vfprintf(error_logfile, fmt, ap); va_end(ap); } if (error_cmd) { if (tag) (void) fputs(tag, error_cmd); /* User's msg */ va_start(ap, fmt); (void) vfprintf(error_cmd, fmt, ap); va_end(ap); } if (show_perror) { if (error) { errno = error; if (error_stderr) perror(""); if (error_logfile) { (void) fprintf(error_logfile, "%s\n", Strerror(error)); } if (error_cmd) { (void) fprintf(error_cmd, "%s\n", Strerror(error)); } } else { if (error_stderr) (void) fputc('\n', stderr); if (error_logfile) (void) fputc('\n', error_logfile); if (error_cmd) (void) fputc('\n', error_cmd); } } #ifdef HAVE_SYSLOG_H if (error_syslog) { char newfmt[MAXPRINT], buf[MAXPRINT]; if (!openlog_done) { OpenLog(error_prog ? error_prog : "", 0, error_facility); openlog_done = 1; } sprintf(newfmt, "(%s) ", error_user ? error_user : user); StrLCat(newfmt, fmt, sizeof(newfmt)); if (tag) StrLCat(newfmt, tag, sizeof(newfmt)); va_start(ap, fmt); (void) vsprintf(buf, newfmt, ap); va_end(ap); SysLog(error_priority, buf); } #endif if (die) (void) exit(die); if (error_cmd) pclose(error_cmd); return -1; } #else /* VARARGS3 */ int Error( va_alist ) va_dcl { va_list ap; int die, show_perror; char *fmt, *orig_fmt; int error; char *tag; int pctt; FILE *error_cmd = NULL; if (error_fflush) fflush(stdout); error = errno; /* Figure out line tagging */ va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); fmt = va_arg(ap, char *); va_end(ap); pctt = strncmp(fmt, "%t", 2) == 0; tag = ( pctt || error_tag ) ? taglines(3) : NULL; if (pctt) fmt += 2; /* Program name */ if (error_stderr && error_prog) (void) fprintf(stderr, "%s%s ", error_prog, (tag && *tag) ? "" : ":"); if (error_command && *error_command) error_cmd = popen(error_command, "w"); if (error_log_prog) { if (error_logfile) (void) fprintf(error_logfile, "%s%s ", error_log_prog, (tag && *tag) ? "" : ":"); if (error_cmd) (void) fprintf(error_cmd, "%s%s ", error_log_prog, (tag && *tag) ? "" : ":"); } if (error_logfile || error_syslog || error_command) { if (getuid() != uid || *user == '\0') { struct passwd *pw; int e = errno; pw = getpwuid((uid=getuid())); if (pw) (void) strcpy(user, pw->pw_name); errno = e; } } if (error_logfile || error_cmd) { /* user@hostname & timestamp */ char *s; time_t tptr; if (*hostname == '\0') (void) gethostname(hostname, sizeof(hostname)); (void) time(&tptr); s = ctime(&tptr); s[strlen(s) - 1] = '\0'; if (error_logfile) (void) fprintf(error_logfile, "%s@%s %s\t", error_user ? error_user : user, hostname, s); if (error_cmd) (void) fprintf(error_cmd, "%s@%s %s\t", error_user ? error_user : user, hostname, s); } if (error_stderr) { if (tag) (void) fputs(tag, stderr); /* User's msg */ va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); orig_fmt = va_arg(ap, char *); (void) vfprintf(stderr, fmt, ap); va_end(ap); } if (error_logfile) { if (tag) (void) fputs(tag, error_logfile); /* User's msg */ va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); orig_fmt = va_arg(ap, char *); (void) vfprintf(error_logfile, fmt, ap); va_end(ap); } if (error_cmd) { if (tag) (void) fputs(tag, error_cmd); /* User's msg */ va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); orig_fmt = va_arg(ap, char *); (void) vfprintf(error_cmd, fmt, ap); va_end(ap); } /* Figure out if we do show_perror */ va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); va_end(ap); if (show_perror) { if (error) { errno = error; if (error_stderr) perror(""); if (error_logfile) (void) fprintf(error_logfile, "%s\n", Strerror(error)); if (error_cmd) (void) fprintf(error_cmd, "%s\n", Strerror(error)); } else { if (error_stderr) (void) fputc('\n', stderr); if (error_logfile) (void) fputc('\n', error_logfile); if (error_cmd) (void) fputc('\n', error_cmd); } } #ifdef HAVE_SYSLOG_H if (error_syslog) { char newfmt[MAXPRINT], buf[MAXPRINT]; va_start(ap); show_perror = va_arg(ap, int); die = va_arg(ap, int); orig_fmt = va_arg(ap, char *); if (!openlog_done) { OpenLog(error_prog ? error_prog : "", 0, error_facility); openlog_done = 1; } sprintf(newfmt, "(%s) ", error_user ? error_user : user); StrLCat(newfmt, fmt, sizeof(newfmt)); if (tag) StrLCat(newfmt, tag, sizeof(newfmt)); (void) vsprintf(buf, newfmt, ap); va_end(ap); SysLog(error_priority, buf); } #endif if (die) (void) exit(die); if (error_cmd) pclose(error_cmd); return -1; } #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* For tagging error text with a prefixing lines indicator. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * taglines(decorations) int decorations; /* 1 = enclose in parens; 2 = add a ": "; 3 = both */ { static char buf[MAXPRINT]; int putparens = decorations & 01; int putcolon = decorations & 02; if (error_srcfile == NULL) { if (error_line <= 0) return ""; else if (error_nl <= 1) (void) sprintf(buf, "%sline %d%s%s", putparens ? "(" : "", error_line, putparens ? ")" : "", putcolon ? ": " : ""); else (void) sprintf(buf, "%slines %d..%d%s%s", putparens ? "(" : "", error_line, error_line + error_nl - 1, putparens ? ")" : "", putcolon ? ": " : ""); } else if (strcmp(error_srcfile, "-") == 0) { if (error_line <= 0) (void) sprintf(buf, "%sin %s%s", putparens ? "(" : "", putparens ? ")" : "", putcolon ? ": " : ""); else if (error_nl <= 1) (void) sprintf(buf, "%sline %d in %s%s", putparens ? "(" : "", error_line, putparens ? ")" : "", putcolon ? ": " : ""); else (void) sprintf(buf, "%slines %d..%d in %s%s", putparens ? "(" : "", error_line, error_line + error_nl - 1, putparens ? ")" : "", putcolon ? ": " : ""); } else { if (error_line <= 0) (void) sprintf(buf, "%sin file `%s'%s%s", putparens ? "(" : "", error_srcfile, putparens ? ")" : "", putcolon ? ": " : ""); else if (error_nl <= 1) (void) sprintf(buf, "%sline %d in file `%s'%s%s", putparens ? "(" : "", error_line, error_srcfile, putparens ? ")" : "", putcolon ? ": " : ""); else (void) sprintf(buf, "%slines %d..%d in file `%s'%s%s", putparens ? "(" : "", error_line, error_line + error_nl - 1, error_srcfile, putparens ? ")" : "", putcolon ? ": " : ""); } return buf; } super-3.30.0/s_hsearch.h0000444000104100002640000000156410732537455013374 0ustar willspg#ifndef HSEARCH_H #define HSEARCH_H #include "config.h" typedef struct entry { char *key; char *data; } ENTRY; typedef enum { FIND, ENTER } ACTION; typedef struct element { ENTRY item; struct element *next; } ELEMENT; extern ENTRY *s_hsearch P__(( int which, ENTRY e, ACTION a )); extern void s_hdestroy P__(( int which )); extern int s_hcreate P__(( int which, unsigned int how_many )); extern void hprint P__(( int which, void (*f)() )); extern void htext P__(( int indx, char *key, char *data )); #define HS_VARS 0 /* The HS_xxx values ... */ #define HS_USER 1 /* ...must start at 0... */ #define HS_HOST 2 /* ...and increment w/o holes... */ #define HS_GROUP 3 /* ...to the largest value */ #define HS_SETS 4 /* Number of HS_xxx items, above. */ #endif super-3.30.0/rsyslog.c0000444000104100002640000001322210732537455013124 0ustar willspgstatic const char rcsid[] = "$Id: rsyslog.c,v 1.17 2004/04/30 17:00:58 will Exp $"; /************************************************************************* ** ** Network version of syslog (syslog,openlog,closelog) ** ** ************************************************************************** **/ /* * This code from Jean-luc Szpyrka's modified super. (jls@sophia.inria.fr) * Modification history: * * Will Deich (will@nfra.nl), 20 Dec 1994. * - don't use prototypes for ropenlog(), rcloselog(). * - rsyslog() changed to use stdargs if __STDC__, varargs otherwise. * - change ropenlog() to be closer to openlog() in its arguments. * - change rsyslog() to be closer to syslog() in what it prints. * Will Deich (will@nfra.nl), 20 Jan 1996. * - replaced most of the #include's with #include "localsys.h" */ #include "localsys.h" /* Just in case there is no errno.h, we provide our own useless errno * variable, so that the code below always compiles. */ #ifndef HAVE_ERRNO_H static int errno; #endif struct socketd { short f_socket; struct sockaddr_in f_addr; }; static struct socketd LogSocket; #define MAXIDENT 128 /* keep MAXIDENT << MAXLINE */ #define MAXLINE 1024 static struct { char ident[MAXIDENT]; int log_pid; int def_facility; } loginfo = { "", 0, LOG_USER }; /* * This procedure sends a message to and already opened networked syslog * It uses varargs to provide a useful interface (a la printf) * */ /*VARARGS0*/ /** ** Warning -- awful code style here. Depending on whether you are ** compiling with HAVE_STDARG_H set or not, we compile different code for ** the function declaration and first few lines of the body. **/ #ifdef HAVE_STDARG_H /** ** ** ** STD C beginning ** ** ** **/ void rsyslog(unsigned int level, char *fmt, ...) { va_list args; #else /** ** ** ** K&R C beginning ** ** ** **/ void rsyslog( va_alist ) va_dcl { va_list args; unsigned int level; char *fmt; #endif /** ** ** ** Body of function ** ** ** **/ char msg[2*MAXLINE]; /* MAXLINE is the maximum size of the message, * but <%d> ident: or <%d> (pid) ident: * is added at the beginning of it before * sending it on the net. */ int l; /* * Formats the output */ #ifdef HAVE_STDARG_H va_start(args,fmt); #else va_start(args); level = va_arg(args, unsigned long); fmt = va_arg(args, char *); #endif (void) sprintf(msg,"<%d>", level); if (loginfo.log_pid) (void) sprintf(msg,"(%d) ", getpid()); if (*loginfo.ident) (void) sprintf(msg+strlen(msg),"%s: ", loginfo.ident); (void) vsprintf(msg+strlen(msg), fmt, args); va_end(args); /* * Eventually truncate the results (I hope 2*MAXLINE is enough !!!!) */ l = strlen(msg); if (l > MAXLINE) l = MAXLINE; /* * Sends to the socket */ if (sendto(LogSocket.f_socket, msg, l, 0, (struct sockaddr *)&LogSocket.f_addr, sizeof LogSocket.f_addr) != l) { int e = errno; (void) close(LogSocket.f_socket); errno = e; perror("rsyslog: sendto"); } /* * That's it ! */ } /* * This procedure opens a UDP connection to the syslog service of the * collecting machine. * */ void ropenlog(ident, logopt, facility, host) char *ident; /* same as in ordinary openlog() */ int logopt; /* same as in openlog(), but only LOG_PID is used. * All other options are quietly ignored. */ int facility; /* same as in openlog() -- but don't rely on using #define'd * values here (e.g. LOG_USER or LOG_LOCAL1) because the * loghost may have a different set of #define's for the * facilities than the machine running ropenlog(), and thus * may interpret this differently than you think. */ char *host; /* host is the name of the collecting machine. * If a NULL pointer, gethostname() is used. */ { char nhost[500]; struct hostent *pHost; struct servent *pService; char msg[MAXLINE]; strncpy(loginfo.ident, ident, sizeof(loginfo.ident)-1); loginfo.ident[sizeof(loginfo.ident)-1] = '\0'; loginfo.log_pid = logopt & LOG_PID; loginfo.def_facility = facility; /* * if no argument is given (this test is necessary to avoid * future possible core dumps) */ if ( host==NULL ) { if (gethostname(nhost, sizeof(nhost)) == -1) { perror("ropenlog(): host not defined and gethostname() failed:"); exit(-1); } host = nhost; } /* * the hostent structure has to be used later */ pHost = gethostbyname(host); /* * also verify that the host does exists */ if (pHost == NULL) { (void) sprintf(msg, "ropenlog: unknown host %s", host); errno = 0; perror(msg); exit(-1); } /* * Network stuff */ memset((char *) &LogSocket.f_addr,0,sizeof LogSocket.f_addr); LogSocket.f_addr.sin_family = AF_INET; /* * Use the service routine to figure what the syslog/udp port is * (If it doesn't exists on a machine (you never now !), it could be useful * to force it to 514, but I never had this problem.) */ pService = getservbyname("syslog", "udp"); if (pService == NULL) { errno = 0; perror("ropenlog: syslog/udp is an unknown service"); exit(-1); } LogSocket.f_addr.sin_port = pService->s_port; /* * Opens the connection */ memcpy((char *) &LogSocket.f_addr.sin_addr, pHost->h_addr, pHost->h_length); LogSocket.f_socket = socket(AF_INET, SOCK_DGRAM, 0); if (LogSocket.f_socket < 0) { perror("ropenlog: socket"); exit(-1); } } /* * This procedure closes the opened syslog connection. */ void rcloselog() { (void) close(LogSocket.f_socket); } super-3.30.0/s_regex.c0000444000104100002640000004521310732537455013063 0ustar willspgstatic const char rcsid[] = "$Id: s_regex.c,v 1.10 2004/04/30 17:00:58 will Exp $"; /* * regex - Regular expression pattern matching * and replacement * * * By: Ozan S. Yigit (oz) * Dept. of Computer Science * York University * * * These routines are the PUBLIC DOMAIN equivalents * of regex routines as found in 4.nBSD UN*X, with minor * extensions. * * These routines are derived from various implementations * found in software tools books, and Conroy's grep. They * are NOT derived from licensed/restricted software. * For more interesting/academic/complicated implementations, * see Henry Spencer's regexp routines, or GNU Emacs pattern * matching module. * * ** NAMES CHANGED TO BE PREFIXED WITH s_, TO AVOID CONFLICTS ** * ** -Will Deich, Feb 1997 ** * * Routines: * s_re_comp: compile a regular expression into * a DFA. * * char *s_re_comp(s) * char *s; * * s_re_exec: execute the DFA to match a pattern. * * int s_re_exec(s) * char *s; * * s_re_modw change s_re_exec's understanding of what * a "word" looks like (for \< and \>) * by adding into the hidden word-character * table. * * void s_re_modw(s) * char *s; * * s_re_subs: substitute the matched portions in * a new string. * * int s_re_subs(src, dst) * char *src; * char *dst; * * s_re_fail: failure routine for s_re_exec. * * void s_re_fail(msg, op) * char *msg; * char op; * * Regular Expressions: * * [1] char matches itself, unless it is a special * character (metachar): . \ [ ] * + ^ $ * * [2] . matches any character. * * [3] \ matches the character following it, except * when followed by a left or right round bracket, * a digit 1 to 9 or a left or right angle bracket. * (see [7], [8] and [9]) * It is used as an escape character for all * other meta-characters, and itself. When used * in a set ([4]), it is treated as an ordinary * character. * * [4] [set] matches one of the characters in the set. * If the first character in the set is "^", * it matches a character NOT in the set. A * shorthand S-E is used to specify a set of * characters S upto E, inclusive. The special * characters "]" and "-" have no special * meaning if they appear as the first chars * in the set. * examples: match: * * [a-z] any lowercase alpha * * [^]-] any char except ] and - * * [^A-Z] any char except uppercase * alpha * * [a-zA-Z] any alpha * * [5] * any regular expression form [1] to [4], followed by * closure char (*) matches zero or more matches of * that form. * * [6] + same as [5], except it matches one or more. * * [7] a regular expression in the form [1] to [10], enclosed * as \(form\) matches what form matches. The enclosure * creates a set of tags, used for [8] and for * pattern substution. The tagged forms are numbered * starting from 1. * * [8] a \ followed by a digit 1 to 9 matches whatever a * previously tagged regular expression ([7]) matched. * * [9] \< a regular expression starting with a \< construct * \> and/or ending with a \> construct, restricts the * pattern matching to the beginning of a word, and/or * the end of a word. A word is defined to be a character * string beginning and/or ending with the characters * A-Z a-z 0-9 and _. It must also be preceded and/or * followed by any character outside those mentioned. * * [10] a composite regular expression xy where x and y * are in the form [1] to [10] matches the longest * match of x followed by a match for y. * * [11] ^ a regular expression starting with a ^ character * $ and/or ending with a $ character, restricts the * pattern matching to the beginning of the line, * or the end of line. [anchors] Elsewhere in the * pattern, ^ and $ are treated as ordinary characters. * * * Acknowledgements: * * HCR's Hugh Redelmeier has been most helpful in various * stages of development. He convinced me to include BOW * and EOW constructs, originally invented by Rob Pike at * the University of Toronto. * * References: * Software tools Kernighan & Plauger * Software tools in Pascal Kernighan & Plauger * Grep [rsx-11 C dist] David Conroy * ed - text editor Un*x Programmer's Manual * Advanced editing on Un*x B. W. Kernighan * RegExp routines Henry Spencer * * Notes: * * This implementation uses a bit-set representation for character * classes for speed and compactness. Each character is represented * by one bit in a 128-bit block. Thus, CCL or NCL always takes a * constant 16 bytes in the internal dfa, and s_re_exec does a single * bit comparison to locate the character in the set. * * Examples: * * pattern: foo*.* * compile: CHR f CHR o CLO CHR o END CLO ANY END END * matches: fo foo fooo foobar fobar foxx ... * * pattern: fo[ob]a[rz] * compile: CHR f CHR o CCL 2 o b CHR a CCL bitset END * matches: fobar fooar fobaz fooaz * * pattern: foo\\+ * compile: CHR f CHR o CHR o CHR \ CLO CHR \ END END * matches: foo\ foo\\ foo\\\ ... * * pattern: \(foo\)[1-3]\1 (same as foo[1-3]foo) * compile: BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END * matches: foo1foo foo2foo foo3foo * * pattern: \(fo.*\)-\1 * compile: BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END * matches: foo-foo fo-fo fob-fob foobar-foobar ... * */ #define MAXDFA 1024 #define MAXTAG 10 #define OKP 1 #define NOP 0 #define CHR 1 #define ANY 2 #define CCL 3 #define NCL 4 #define BOL 5 #define EOL 6 #define BOT 7 #define EOT 8 #define BOW 9 #define EOW 10 #define REF 11 #define CLO 12 #define END 0 /* * The following defines are not meant * to be changeable. They are for readibility * only. * */ #define MAXCHR 128 #define CHRBIT 8 #define BITBLK MAXCHR/CHRBIT #define BLKIND 0170 #define BITIND 07 #define ASCIIB 0177 typedef unsigned char CHAR; static int tagstk[MAXTAG]; /* subpat tag stack..*/ static CHAR dfa[MAXDFA]; /* automaton.. */ static int sta = NOP; /* status of lastpat */ static CHAR bittab[BITBLK]; /* bit table for CCL */ static void chset(c) register CHAR c; { bittab[((int) ((c)&BLKIND))>>3] |= 1<<((c)& (unsigned) BITIND); } #define badpat(x) return(*dfa = END, x) #define store(x) *mp++ = x char * s_re_comp(pat) char *pat; { register char *p; /* pattern pointer */ register CHAR *mp=dfa; /* dfa pointer */ register CHAR *lp; /* saved pointer.. */ register CHAR *sp=dfa; /* another one.. */ register int tagi = 0; /* tag stack index */ register int tagc = 1; /* actual tag count */ register int n; int c1, c2; if (!pat || !*pat) { if (sta) return(0); else badpat("No previous regular expression"); } sta = NOP; for (p = pat; *p; p++) { lp = mp; switch(*p) { case '.': /* match any char.. */ store(ANY); break; case '^': /* match beginning.. */ if (p == pat) store(BOL); else { store(CHR); store(*p); } break; case '$': /* match endofline.. */ if (!*(p+1)) store(EOL); else { store(CHR); store(*p); } break; case '[': /* match char class..*/ if (*++p == '^') { store(NCL); p++; } else store(CCL); if (*p == '-') /* real dash */ chset(*p++); if (*p == ']') /* real brac */ chset(*p++); while (*p && *p != ']') { if (*p == '-' && *(p+1) && *(p+1) != ']') { p++; c1 = *(p-2) + 1; c2 = *p++; while (c1 <= c2) chset(c1++); } #ifdef EXTEND else if (*p == '\\' && *(p+1)) { p++; chset(*p++); } #endif else chset(*p++); } if (!*p) badpat("Missing ]"); for (n = 0; n < BITBLK; bittab[n++] = (char) 0) store(bittab[n]); break; case '*': /* match 0 or more.. */ case '+': /* match 1 or more.. */ if (p == pat) badpat("Empty closure"); lp = sp; /* previous opcode */ if (*lp == CLO) /* equivalence.. */ break; switch(*lp) { case BOL: case BOT: case EOT: case BOW: case EOW: case REF: badpat("Illegal closure"); default: break; } if (*p == '+') for (sp = mp; lp < sp; lp++) store(*lp); store(END); store(END); sp = mp; while (--mp > lp) *mp = mp[-1]; store(CLO); mp = sp; break; case '\\': /* tags, backrefs .. */ switch(*++p) { case '(': if (tagc < MAXTAG) { tagstk[++tagi] = tagc; store(BOT); store(tagc++); } else badpat("Too many \\(\\) pairs"); break; case ')': if (*sp == BOT) badpat("Null pattern inside \\(\\)"); if (tagi > 0) { store(EOT); store(tagstk[tagi--]); } else badpat("Unmatched \\)"); break; case '<': store(BOW); break; case '>': if (*sp == BOW) badpat("Null pattern inside \\<\\>"); store(EOW); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = *p-'0'; if (tagi > 0 && tagstk[tagi] == n) badpat("Cyclical reference"); if (tagc > n) { store(REF); store(n); } else badpat("Undetermined reference"); break; #ifdef EXTEND case 'b': store(CHR); store('\b'); break; case 'n': store(CHR); store('\n'); break; case 'f': store(CHR); store('\f'); break; case 'r': store(CHR); store('\r'); break; case 't': store(CHR); store('\t'); break; #endif default: store(CHR); store(*p); } break; default : /* an ordinary char */ store(CHR); store(*p); break; } sp = lp; } if (tagi > 0) badpat("Unmatched \\("); store(END); sta = OKP; return(0); } static char *bol; static char *bopat[MAXTAG]; static char *eopat[MAXTAG]; static char *pmatch(); /* * s_re_exec: * execute dfa to find a match. * * special cases: (dfa[0]) * BOL * Match only once, starting from the * beginning. * CHR * First locate the character without * calling pmatch, and if found, call * pmatch for the remaining string. * END * s_re_comp failed, poor luser did not * check for it. Fail fast. * * If a match is found, bopat[0] and eopat[0] are set * to the beginning and the end of the matched fragment, * respectively. * */ int s_re_exec(lp) register char *lp; { register char c; register char *ep = 0; register CHAR *ap = dfa; bol = lp; bopat[0] = 0; bopat[1] = 0; bopat[2] = 0; bopat[3] = 0; bopat[4] = 0; bopat[5] = 0; bopat[6] = 0; bopat[7] = 0; bopat[8] = 0; bopat[9] = 0; switch(*ap) { case BOL: /* anchored: match from BOL only */ ep = pmatch(lp,ap); break; case CHR: /* ordinary char: locate it fast */ c = *(ap+1); while (*lp && *lp != c) lp++; if (!*lp) /* if EOS, fail, else fall thru. */ return(0); default: /* regular matching all the way. */ while (*lp) { if ((ep = pmatch(lp,ap))) break; lp++; } break; case END: /* munged automaton. fail always */ return(0); } if (!ep) return(0); bopat[0] = lp; eopat[0] = ep; return(1); } /* * pmatch: * internal routine for the hard part * * This code is mostly snarfed from an early * grep written by David Conroy. The backref and * tag stuff, and various other mods are by oZ. * * special cases: (dfa[n], dfa[n+1]) * CLO ANY * We KNOW ".*" will match ANYTHING * upto the end of line. Thus, go to * the end of line straight, without * calling pmatch recursively. As in * the other closure cases, the remaining * pattern must be matched by moving * backwards on the string recursively, * to find a match for xy (x is ".*" and * y is the remaining pattern) where * the match satisfies the LONGEST match * for x followed by a match for y. * CLO CHR * We can again scan the string forward * for the single char without recursion, * and at the point of failure, we execute * the remaining dfa recursively, as * described above. * * At the end of a successful match, bopat[n] and eopat[n] * are set to the beginning and end of subpatterns matched * by tagged expressions (n = 1 to 9). * */ extern void s_re_fail(); /* * character classification table for word boundary * operators BOW and EOW. the reason for not using * ctype macros is that we can let the user add into * our own table. see s_re_modw. This table is not in * the bitset form, since we may wish to extend it * in the future for other character classifications. * * TRUE for 0-9 A-Z a-z _ */ static char chrtyp[MAXCHR] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; #define inascii(x) (0177&(x)) #define iswordc(x) chrtyp[inascii(x)] #define isinset(x,y) ((x)[((y)&BLKIND)>>3] & (1<<((y)&BITIND))) /* * skip values for CLO XXX to skip past the closure * */ #define ANYSKIP 2 /* CLO ANY END ... */ #define CHRSKIP 3 /* CLO CHR chr END ... */ #define CCLSKIP 18 /* CLO CCL 16bytes END ... */ static char * pmatch(lp, ap) register char *lp; register CHAR *ap; { register char *e; /* extra pointer for CLO */ register char *bp; /* beginning of subpat.. */ register char *ep; /* ending of subpat.. */ register int op, c, n; char *are; /* to save the line ptr. */ while ((op = *ap++) != END) switch(op) { case CHR: if ((unsigned char) *lp++ != *ap++) return(0); break; case ANY: if (!*lp++) return(0); break; case CCL: c = *lp++; if (!isinset(ap,c)) return(0); ap += BITBLK; break; case NCL: c = *lp++; if (isinset(ap,c)) return(0); ap += BITBLK; break; case BOL: if (lp != bol) return(0); break; case EOL: if (*lp) return(0); break; case BOT: bopat[*ap++] = lp; break; case EOT: eopat[*ap++] = lp; break; case BOW: if (!(lp!=bol && iswordc(lp[-1])) && iswordc(*lp)) break; return(0); case EOW: if ((lp!=bol && iswordc(lp[-1])) && !iswordc(*lp)) break; return(0); case REF: n = *ap++; bp = bopat[n]; ep = eopat[n]; while (bp < ep) if (*bp++ != *lp++) return(0); break; case CLO: are = lp; switch(*ap) { case ANY: while (*lp) lp++; n = ANYSKIP; break; case CHR: c = *(ap+1); while (*lp && c == *lp) lp++; n = CHRSKIP; break; case CCL: case NCL: while (*lp && (e = pmatch(lp, ap))) lp = e; n = CCLSKIP; break; default: s_re_fail("closure: bad dfa.", *ap); return(0); } ap += n; while (lp >= are) { if ((e = pmatch(lp, ap))) return(e); --lp; } return(0); default: s_re_fail("s_re_exec: bad dfa.", op); return(0); } return(lp); } /* * s_re_modw: * add new characters into the word table to * change the s_re_exec's understanding of what * a word should look like. Note that we only * accept additions into the word definition. * * If the string parameter is 0 or null string, * the table is reset back to the default, which * contains A-Z a-z 0-9 _. [We use the compact * bitset representation for the default table] * */ static unsigned char deftab[16] = { 0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207, 0376, 0377, 0377, 007 }; void s_re_modw(s) register char *s; { register int i; if (!s || !*s) { for (i = 0; i < MAXCHR; i++) if (!isinset(deftab,i)) iswordc(i) = 0; } else while(*s) iswordc(*s++) = 1; } /* * s_re_subs: * substitute the matched portions of the src in * dst. * * & substitute the entire matched pattern. * * \digit substitute a subpattern, with the given * tag number. Tags are numbered from 1 to * 9. If the particular tagged subpattern * does not exist, null is substituted. * */ int s_re_subs(src, dst) register char *src; register char *dst; { register char c; register int pin; register char *bp; register char *ep; if (!*src || !bopat[0]) return(0); while ((c = *src++)) { switch(c) { case '&': pin = 0; break; case '\\': c = *src++; if (c >= '0' && c <= '9') { pin = c - '0'; break; } default: *dst++ = c; continue; } if ((bp = bopat[pin]) && (ep = eopat[pin])) { while (*bp && bp < ep) *dst++ = *bp++; if (bp < ep) return(0); } } *dst = (char) 0; return(1); } #ifdef DEBUG /* * symbolic - produce a symbolic dump of the * dfa */ symbolic(s) char *s; { printf("pattern: %s\n", s); printf("dfacode:\n"); dfadump(dfa); } static dfadump(ap) CHAR *ap; { register int n; while (*ap != END) switch(*ap++) { case CLO: printf("CLOSURE"); dfadump(ap); switch(*ap) { case CHR: n = CHRSKIP; break; case ANY: n = ANYSKIP; break; case CCL: case NCL: n = CCLSKIP; break; } ap += n; break; case CHR: printf("\tCHR %c\n",*ap++); break; case ANY: printf("\tANY .\n"); break; case BOL: printf("\tBOL -\n"); break; case EOL: printf("\tEOL -\n"); break; case BOT: printf("BOT: %d\n",*ap++); break; case EOT: printf("EOT: %d\n",*ap++); break; case BOW: printf("BOW\n"); break; case EOW: printf("EOW\n"); break; case REF: printf("REF: %d\n",*ap++); break; case CCL: printf("\tCCL ["); for (n = 0; n < MAXCHR; n++) if (isinset(ap,(CHAR)n)) printf("%c",n); printf("]\n"); ap += BITBLK; break; case NCL: printf("\tNCL ["); for (n = 0; n < MAXCHR; n++) if (isinset(ap,(CHAR)n)) printf("%c",n); printf("]\n"); ap += BITBLK; break; default: printf("bad dfa. opcode %o\n", ap[-1]); exit(1); break; } } #endif super-3.30.0/setuid.1.in0000444000104100002640000000351410732537455013245 0ustar willspg.TH SETUID 1 local .\" .\" Copyright (c) 1995 by William Deich. .\" Written by William Deich. Not derived from licensed software. .\" .\" You may distribute under the terms of either the GNU General Public .\" License or the Artistic License, as specified in the README file. .\" .\" .SH NAME setuid \- run a command with a different uid. .SH SYNOPSIS .B setuid .BR username | uid .I \ \ command [ .I args ] .SH DESCRIPTION .I Setuid changes user id, then executes the specified .IR command . Unlike some versions of .IR su (1), this program doesn't ever ask for a password when executed with effective uid=root. This program doesn't change the environment; it only changes the uid and then uses .I execvp() to find the .I command in the path, and execute it. (If the .I command is a script, .I execvp() passes the command name to .B /bin/sh for processing.) .PP For example, .RS setuid \fIsome_user\fP $SHELL .RE can be used to start a shell running as another user. .PP .I Setuid is useful inside scripts that are being run by a setuid-root user \(em such as a script invoked with .IR super , so that the script can execute some commands using the uid of the original user, instead of root. This allows unsafe commands (such as editors and pagers) to be used in a non-root mode inside a super script. For example, an operator with permission to modify a certain .I protected_file could use a super command that simply does: .RS .nf cp protected_file temp_file setuid $ORIG_USER ${EDITOR:-/bin/vi} temp_file cp temp_file protected_file .fi .RE (Note: don't use this example directly. If the \fItemp_file\fP can somehow be replaced by another user, as might be the case if it's kept in a temporary directory, there will be a race condition in the time between editing the temporary file and copying it back to the protected file.) .SH AUTHOR Will Deich super-3.30.0/WhatsNew0000444000104100002640000022665510732537455012761 0ustar willspg------------------- What's new for version 3.30.0: A. Added '-t' option, to test if a command exists, and if so if this user may execute it at this moment. ------------------- What's new for version 3.28.0: A. Added '-r requiredpath' option, to allow a program to insist that the FullPath be the same program as the requiredpath, else it's an error. ------------------- What's new for version 3.27.0: A. Modified 'super -c' to exit with non-zero exit code if there is a syntax error. Requested by Gordon Lack, gml4410@ggr.co.uk B. Performance enchancement: store various user/group/host/pattern data in a hash table, so as to avoid many repeated NIS calls when working with a large super.tab file. "The result was that I cut the number of NIS calls made when running through an entire file's tests (super with no args) from 4230 to 177. This has a *big* effect on the elapsed time too." (From Gordon Lack, gml4410@ggr.co.uk) C. Additional syntax checking: wherever super does brace-globbing, it explicitly checks for balanced braces. ------------------- What's new for version 3.26.3: A. Fix for 'super -c' when SUPERDIR has been set to other than /usr/local/lib. (From Gordon Lack, gml4410@ggr.co.uk) ------------------- What's new for version 3.26.2: A. Fix for HP-UX 11i in trusted mode, from Mike Cross . ------------------- What's new for version 3.26.1: A. Fix for super variable re-definition bug. When changing the definition of a variable, super deallocated a string that hsearch() tried to reference. Bug discovery and fix by Michael Steffens . ------------------- What's new for version 3.26.0: A. Cumulation of 3.25.x changes. ------------------- What's new for version 3.25.3: A. Fixed reference to get_pam() that shouldn't be present when building w/o pam support. Reported by Gabor Z. Papp (gzp@papp.hu) ------------------- What's new for version 3.25.2: A. Fixed bug in 3.25.1... ------------------- What's new for version 3.25.1: A. Fixed handling of argMMM-NNN options. Problem reported by cmoulin@simplerezo.com. ------------------- What's new for version 3.25.0: A. Super tries to obtain the user's authentication data early (before it yields setuid-root privileges), and it does this even before reading the super.tab file. If super is unable to obtain this info, it will no longer print error messages, unless the specific command requires user authentication. B. Super tries to record the time of the user's authentication, which allows it to trust the same user for some additional time w/o re-entering authentication data. If it's unable to record the timestamp, it doesn't generate error messages unless this particular command has the renewtime option set (typically this is done as a global option). C. Cleaned up some error messages / warnings. ------------------- What's new for version 3.24.1: A. BUGFIX for 3.24.0 / shell patterns syntax enhancement: The last version used this goofy pattern: :if $PATTERNS == shell :global arg1-99="[-/:+._a-zA-Z0-9]*" Of course, this only restricts the first character to the desired one; ordinary shell patterns can't express the desired restrictions at all! In order to let shell patterns do the desired kind of matching, I've added new syntax for shell patterns: when the pattern is [[...]] -- that is, it begins with "[[" and ends with "]]" -- then it's a special case that means each and every character in the string must match the pattern [...]. The new rule in the super.tab file can now be: :if $PATTERNS == shell :global arg1-99="[[-/:+._a-zA-Z0-9]]" :if $PATTERNS != shell :global arg1-99="^[-/:+._a-zA-Z0-9]*$$" ------------------- What's new for version 3.24.0: A. Changed option args and nargs to be global as well as local. (Suggested by Henrik Strom ) B. Added builtin variable PATTERNS to carry the value of the global patterns option. Combined with (A), your super.tab file can include these entries for limiting what can be done without local settings: # By default, allow only 0 or 1 argument :global nargs=0-1 # By default, each argument must be a simple word with no # characters that might be srecial to a shell: :if $PATTERNS == shell :global arg1-99="[-/:+._a-zA-Z0-9]*" :if $PATTERNS != shell :global arg1-99="^[-/:+._a-zA-Z0-9]*$$" ------------------- What's new for version 3.23.0: A. Fixed format string vulnerability. (Incremented version number instead of patch number to emphasize this change is important.) (From Max Vozeler , via Robert Luberda ) ------------------- What's new for version 3.22.2: A. Better syslog handling. Instead of compile-time choice of the rsyslog() vs syslog() routines, the program now makes the selection at runtime. By default, the normal openlog() and syslog() functions are used. However, if a loghost is named (using global option rlog_host=xxxx) before any syslog message is generated, the functions ropenlog() and rsyslog() are used instead. ------------------- What's new for version 3.22.1: A. Bugfix for new options euid and egid (added 3.21.0), in which one of the id's would overwrite the other. (From Robert Luberda ) B. Bugfix for missing save/restore of errno, causing an incorrect error message. (From Robert Luberda ) C. Bugfix: remove unwanted override of syslog facility and priority. (From Robert Luberda ) D. Bugfix: if your system didn't support sysinfo(SI_SYSNAME, ...), there was a missing return statement in add_sysinfo_variables(). (From Gordon Lack, gml4410@ggr.co.uk) E. Bugfix: Linux pw lookup didn't have fallback if /etc/shadow was missing. (From Gordon Lack, gml4410@ggr.co.uk) F. Long series of minor edits to remove all compiler warnings generated by gcc -Wall. (From Robert Luberda ) ------------------- What's new for version 3.22.0: A. Added flexibility to syslog facility/level setting; e.g. auth.local1 is now legal, in addition to "LOG_AUTH|LOG_LOCAL1". B. Fixed bug that disallowed whitespace in strings such as that in A. ------------------- What's new for version 3.21.5: A. Fixed a minor glitch in the configure script. ------------------- What's new for version 3.21.4: A. Fixed install of the "barebones.tab" file. ------------------- What's new for version 3.21.2: A. Generalized support for passwords: a) all encrypted password beginning "$" are now handled correctly (hence Linux, *BSD, Solaris 9, ...) b) extended DES (encrypted password begins "_") now handled correctly. B. Fixd approval checks for root. Root was being given permission to execute commands that explicitly said !root. C. Added some notes to man page. D. Minor improvement to error messages. ------------------- What's new for version 3.21.0: A. Added options euid and egid to allow setting the effective uid and gid separately from changing the real id's. A few very old versions of Unix don't provide the setre[ug]id functions, and attempting to use the e{u,g}id options will cause an error. B. Fixed reading of passwd/shadow files so that the format $n$salt$passwd is understood on Linux systems. C. Added FreeBSD passwd handling, again to recognize fmt $n$salt$passwd. ------------------- What's new for version 3.20.1: A. ICANON is no longer disabled in getpass() -- otherwise, getpass() hung for some os's. (From Gordon Lack, gml4410@ggr.co.uk) B. Fixed some missing return values. (From Michael Steffens michael.steffens@hp.com) ------------------- What's new for version 3.20.0: A. Typo in utils.c would cause super to use syslog level LOG_NEWS instead of LOG_RFS, if you tried to select the latter. ------------------- What's new for version 3.19.0: A. SECURITY FIX: Patched syslog use error. All previous versions allow local root exploit when syslog() use is enabled. Workaround for earlier versions: put "syslog=n" into :global line of the super.tab file. ------------------- What's new for version 3.18.0: A. Per user request, added option to force passwords to be read from stdin. ------------------- What's new for version 3.17.2: A. Minor man page improvements. ------------------- What's new for version 3.17.1: A. Double-checks on uid and gid, to make sure they were really changed as they should have been. ------------------- What's new for version 3.17.0: A. argNNN matching now accepts brace-enclosed list (from Boleslav Bobcik, xbobcik@informatics.muni.cz) B. If your system-supplied regex is POSIX-compatible, then posix regular expressions are now supported; use :global patterns=posix to enable them. The default is case-sensitive, basic regular expressions. To get extended regular expressions (see your POSIX regular expression man page), use :global patterns=posix/extended To add ignore-case, use :global patterns=posix/extended/icase ------------------- What's new for version 3.16.1: A. pam.o was listed twice in the Makefile. (from Boleslav Bobcik, xbobcik@informatics.muni.cz) B. Missing comment delimiters around an #ifdef comment. (from Boleslav Bobcik, xbobcik@informatics.muni.cz) ------------------- What's new for version 3.16.0: This is the stable culmination of the changes in the 3.15.x enhancements. The previous stable version was 3.14.0. The last version to have a known security problem was 3.12.0. In brief, the changes include the following (the version number tells when the capability was added; check that section for more info): A. Added PAM support. (3.15.5, 3.15.6) C. The use of password=y|n is deprecated; it's been replaced by the more general auth=y|n and authtype=xxx mechanism. (3.15.5) D. **** BEHAVIOR CHANGE FOR ROOT **** The new behavior is *usually* the same as the old behavior, but give you more control. (3.15.4) E. Added support for shadow passwords in Digital Unix 4.x. (3.15.3) F. Fixes for HP-UX 11.0 with tcb enabled. (3.15.0, 3.15.7) G. Fixed an error in printing a message when super is _not_ running setuid-root. (Hence this is not a security fix.) (3.15.2) H. Added option to let you specify the prompt for password (3.15.2) I. Improved description of some envvars. (3.15.2) J. Corrected processing of "die=message" option. (3.15.2) K. Minor readability improvements. (3.15.0) L. Trivial changes to the format of the -h and -H outputs. (3.15.6) ------------------- What's new for version 3.15.7: A. Modifications to support HP-UX 11.0 with tcb: it uses crypt() instead of bigcrypt() [the latter is used by HP-UX 10.x. ------------------- What's new for version 3.15.6: A. Trivial changes to the format of the -h and -H outputs. B. Added "--disable-pam" configure option to disable PAM support, even if compile host has PAM. Useful if the executable is going to be used on hosts that don't have the PAM shareable libraries. ------------------- What's new for version 3.15.5: A. Added Linux PAM support. To support PAM, there are new options (global or local): auth=y|n (default=n; replaces password=y|n) authtype=password|pam (default=password) authprompt="" If you want to use the same authentication method for all the commands that require user authentication, it's convenient to put authtype=xxx on a :global option line, and then you only need to add "auth=y" on the lines that require options. B. The use of password=y|n is deprecated. To maintain backwards-compatibility, the following expressions are equivalent: password=y <--> auth=y authtype=password password=n <--> auth=n ------------------- What's new for version 3.15.4: A. **** BEHAVIOR CHANGE FOR ROOT **** The rule for 'root' using super has been changed! The new behavior is *usually* the same as the old behavior, but the new rules give you more control over root. New behavior: super acts as if the very first pattern to match is "root", and then applies its ordinary pattern-matching rules. The resul is a nice simplification & clarification of the rules: root: default allow others: default deny ------------------- What's new for version 3.15.3: A. Added support for shadow passwords in Digital Unix 4.x. ------------------- What's new for version 3.15.2: A. Fixed an error in printing a message when super is _not_ running setuid-root. (Hence this is not a security fix.) B. Added option authprompt="some string", to let you specify the prompt for password. Variable substitution is done on the message before printing. C. Improved description of ORIG_USER, ORIG_LOGNAME, and ORIG_HOME, to emphasize that these values are constructed by super and hence safe to use. D. Corrected processing so that a "die=message" option doesn't stop processing when in give-help mode. E. Modified the processing of "die=message" so that the message is printed without any surrounding foo-fah-rah: just the super.tab message and nothing else. Variable substitution is done on the message before printing. ------------------- What's new for version 3.15: A. Minor readability improvements. B. Fix for HP-UX 11.0 with tcb enabled: the argument list of the (undocumented but essential) getpasswd() function has changed between 10.20 and 11.0. ------------------- What's new for version 3.14.0: *** NOTE *** Super has adopted the Linux version numbering convention. That is, the odd-numbered minor versions are development versions, and even-numbered minor versions are stable releases (super uses version numbers in the format major.minor.patchlevel). This is the stable culmination of the changes in the 3.13.x enhancements. The previous stable version was 3.12.2. The last version to have a known security problem was 3.12.0. In brief, the changes include the following (the version number tells when the capability was added; check that section for more info): A. A new file, super.init, is now processed by super! (3.13.6) B. New command-line option, `-o file', for symlinks to per-user commands. (3.13.6) C. Allow 'loginname:', in addition to 'loginname:cmd' (3.13.6) D. Added CALLER and CALL_HOME builtin variables. (3.13.10) E. Added new builtin variables: HOST, SUPER_OWNER, SUPER_HOME. (3.13.6) F. Added new variable IS_USERTAB. (3.13.7) G. New super.tab option, checkvar=xxx, to require user to enter variables. (3.13.6) H. New super.tab command, :getenv, to import environment variables. (3.13.6) I. Added owner=xxx and group=yyy options to the :include command. (3.13.6) J. Added new global command ":die" to force immediate exit. (3.13.6) K. Moved get_encrypted_passwd() before super drops privs. (3.13.6) L. Modifications to support HP-UX 10.20 running with tcb. (3.13.6) M. Patched a dumb bug -- didn't initialize -o flag to null ptr. (3.13.9) N. Patched dumb bug in the 3.13.6/3.13.7 code. (3.13.8) O. A variety of bugfixes. (3.13.6) ------------------- What's new for version 3.13.10: A. Added two built-in variables that can be helpful super.tab files: $CALLER is the login name of the of account invoking super, and $CALLER_HOME is the home directory of $CALLER. Sample use: sam /usr/sbin/sam group~operator uid=0 \ env=DISPLAY \ setenv=XAUTHORITY=$CALLER_HOME/.Xauthority Here, the "operator" group can execute 'sam' as root, and the GUI will display at the caller's display (due to env=DISPLAY). Since the XAUTHORITY envvar is set to the caller's .Xauthority file, this will give the caller access to the same displays to which s/he already has access. ------------------- What's new for version 3.13.9: A. Patched another dumb bug -- didn't initialize -o flag to null ptr. ------------------- What's new for version 3.13.8: A. Patched dumb bug in the 3.13.6/3.13.7 code -- failed to check for null pointer. ------------------- What's new for version 3.13.7: A. Added new variable IS_USERTAB. This has the value "yes" if super is processing a `user:cmd'-type command, and "no" otherwise. The allows the super.init to act differently depending on how it is being invoked. ------------------- What's new for version 3.13.6: A. A new file, super.init, is now processed by super! It is located in the same directory as super.tab, and must be owned by root and be world-readable. If it doesn't exist, the usual processing of super.tab and per-user .supertab files is done. If super.init does exist, it is processed exactly as if each super.tab and per-user .supertab file began with: :include /etc/super.init owner=root (except that "/etc" is replaced with the super.tab directory.) This allows one to have a uniform configuration file applied to every super-executed command. Note that the configuration file should _only_ contain entries that are appropriate for both root-executed super commands and per-user super commands. It is not a good idea to include commands in the super.init file; it should preferably contain only the builtin colon-commands (:global, :define, :if, :die, etc). B. New command-line option, `-o file', for symlinks to per-user commands. The `-o file' makes it possible to create symlinks to per-user commands, analogous to the manner in which super interprets symlinks to itself. For instance, if "xyz" is a symlink to the super command, then invoking "xyz" is a shorthand for "super xyz". Similarly, the `-o file' option can be used to make the following completely equivalent: super joe:xyz [args] (1) xyz [args] (2) For this method to work, "xyz" must be a symlink to the desired .supertab file (here, ~joe/.supertab), and the .supertab file must be made executable and begin with the line #! /usr/bin/super -o (Of course you should replace /usr/bin/super with the actual path to super.) If the "#!" line would be longer than the typical Unix limit of 32 characters, you can instead start the .supertab file with: #! /bin/sh # Keep this backslash -> \ exec /long/path/to/the/super/executable -o $0 ${1+"$@"} ... (This takes advantage of the fact that super allows comments to be backslash-continued, but the shell doesn't.) This works as follows: if /path/to/xyz is a symlink to some user's .supertab file, and the .supertab file begins with "#! /path/to/super -o", then the shell will invoke super with arguments something like super -o /path/to/xyz [args] Super checks that /path/to/xyz is a link to a real .supertab file, and then always turns the last part of the path (here "xyz") into the command to execute. ** Security Warning ** Note that the caller is trusting that the .supertab file will actually begin `#! /path/to/super', and not be changed to contain something like `rm *"! Of course, this doesn't apply to the non-symlink form, `super joe:xyz'. C. Allow 'loginname:', in addition to 'loginname:cmd' A modification to the syntax for invoking per-user commands allows you to invoke help listings for the per-user files. The original syntax was restricted to something like this: super joe:xyz which executes command xyz from joe's .supertab file. The new rule is that if the "xyz" part can be missing: super joe: or super -H joe: gets command listings for joe's .supertab just as plain "super" or "super -H" gets command listings for the normal super.tab file. D. New super.tab option, checkvar=xxx, to require user to enter variables. The checkvar=xxx option tells super to prompt the user to enter the value of one or more variables (here, the variable xxx). For example, you might have a command `super shutdown' which halts the computer. If you execute this on the wrong host there may be some very annoyed users! The super.tab option checkvar=HOST may be helpful here; it causes super to prompt Super needs you to enter the HOST variable before proceeding. Enter HOST ( for reminder): If you press or the wrong value, super re-prompts with: Enter HOST (expecting `myhost'): This allows you to ensure that the caller really knows the host on which the command is executing -- a useful thing if the command will shutdown the system! Any super.tab variable can be used in this kind of check. Note that the value isn't anything like a secret; it's simply intended to help avoid gross embarrassment (or worse) by discouraging errors. E. New super.tab command, :getenv, to import environment variables. The :getenv command allows a super.tab file to import environment variables into super.tab variable definitions. The environment variables are not allowed unless the definition is restricted to super's normal set of "safe" characters. This provides two advantages: (a) it's a safe alternative to allowing users' environment variables to be passed unchecked to programs, because you can do: :getenv VAR1 VAR2 Cmd FullPath user~xyz setenv=VAR1=$VAR1,VAR2=$VAR2 ...and the program will receive VAR1 and VAR2 only if they have "safe" values, of reasonable length. (b) It allows interesting new constructs in super.tab files. F. Added owner=xxx and group=yyy options to the :include command. The use is :include FileName [owner=xxx] [group=yyy] This allows your per-user .supertab file to include files that are owned by some user xxx (owner=xxx) and/or are writable by group yyy (group=yyy). This can be useful for a collection of accounts that are operated together as a single "project" -- a variety of accounts can share .supertab files from the trusted user xxx or group yyy. Note: (1) The regular root-owned super.tab file can also use this construct, but it's not a good idea. Don't do it. (2) Beware of the transitive nature of this trust: the file owned by xxx can in turn include a file owned by yet another user. G. Added new builtin variables. The new variables are: i) HOST, the unqualified form of HOSTNAME. (Note that HOST and HOSTNAME will be the same if the system doesn't use qualified names for HOSTNAME.) ii) SUPER_OWNER, the owner of the top-level super.tab file. This is root for the default super.tab file, or the owner of the .supertab file in a per-user command. iii) SUPER_HOME, the home directory of $SUPER_OWNER. H. Added new global command ":die" to force immediate exit. The use is :die message The purpose is to allow a super.tab file to force an exit without resorting to syntactically clumsy methods. For example, you can use a line like this: :if $HOST != myhost :die "For use on myhost only; this is $HOST!" Without the :die command, one would have to write :global patterns=shell :if $HOST != myhost * /dev/null user~* die="For use on myhost only!" ...which is unnecessarily hard to read and write. I. A variety of bugfixes. These include: change to read password before super.tab uid=xxx causes uid to change to non-root; propagate -1 error return after canonicalize hostname failures; fixed generating of timestamp directory; fixed segfault occurring when printing wildcard commands w/o any "info". Patches from Rein Tollevik (Rein.Tollevik@si.sintef.no). J. Moved get_encrypted_passwd() to happen before super drops privs. This allows per-super .supertab files to use password-checking (from Geoffrey A. Lowney, Geoffrey.A.Lowney@Boeing.com) K. Modifications to handle HP-UX 10.20 running with tcb (Trusted Computing Base). Patches based on code from Minh Tran . ------------------- What's new for version 3.13.0 .. 3.13.5: These versions were never formally released. ------------------- What's new for version 3.12.2: A. Fixed configure script for AIX. Problem reported by Klaus Wacker (wacker@Physik.Uni-Dortmund.DE). B. Fixed error interpreting the argv0 option, and an error implementing it. The argv0 option was being incorrectly interpreted as an invalid arg[MMM-]NNN option. Problem reported by Hadmut Danisch (hadmut@danisch.de). C. Slightly improved help info. D. Slightly improved man page. E. Modifications to handle shadowed passwords properly on HP-UX 10.x and 11.x. F. Modifications to handle shadowed passwords properly on Linux. Problem report and bugfix from Edgar Nielsen . ------------------- What's new for version 3.12.1: A. Yet another buffer-overrun fix. Problem reported by root@sekure.org (http://www.sekure.org, aka the Brazilian Information Security Team). Super now has very strict option-checking, as follows: i) super now limits the length of each option passed to it (note that this is not the same as limiting the length of arguments passed to the commands invoked by super for the user); ii) super now limits the total length of all options passed to it (again, this is separate from limiting the length of arguments passed to commands invoked by super); iii) ensures that all its option characters are from a limited set. Items (i) and (ii) ensure that users can't pass execessively long strings. Item (iii) is just insurance :-) B. When super is running in debug mode, it won't execute any commands, but it will process user-supplied super.tab files. This makes potential security holes, because it might be possible that nasty data can be passed through a user-supplied super.tab file, just like there were buffer-overruns from command-line arguments. Therefore, super will no longer remain as root when checking a user-supplied super.tab file. Instead, it reverts to the caller's real uid, and prints a large explanatory message like the following: ** Since you have supplied a super.tab file that isn't the default, ** and your real uid isn't root, we're going to change back to your ** real uid for this test. That protects us against attacks via ** nasty constructions inside user-supplied super.tab files. ** Not that we don't trust you... ** Now using: ruid=545 euid=545 ** ------------------- What's new for version 3.12.0: A. This is supposed to be a nice and stable release, reflecting mainly the accumulated set of changes across 3.11. Those changes include not only patches but also enough new features that I changed the minor number to indicate that this now differs noticeably from 3.11.0. Changes from 3.11 include: i) the crucial buffer overrun patches; ii) various other bugfixes; iii) modifications to configure properly under more operating systems; iv) the following features, added since 3.11.0: --disable-rsyslog ...compile time switch. -U, -G, -M ...runtime switches for checking config files. syslog_error ...runtime configuration option. syslog_success ...runtime configuration option. argv0 ...runtime configuration option. B. Fix for a typo when checking the argument to the -U flag. Problem and fix from Benoit Speckel (Benoit.Speckel@IReS.in2p3.fr). C. Fix for insufficient setup when using the -U and -G options. Problem and fix from Gordon Lack (gml4410@ggr.co.uk). ------------------- What's new for version 3.11.9: A. Super was failing on per-user super commands (using the ~/.supertab file) because it tried to change supplementary groups after dropping root privs. Problem & fix from Gordon Lack (gml4410@ggr.co.uk). B. The new compile-time switch --disable-rsyslog turns off the use of the rsyslog() function, so that super only uses normal syslog(). rsyslog() has been improved to use gethostname() instead of "localhost" as a default. C. Bugfix: additional, new envvar checking had a bug that led to segfaults, because it passed a nil ptr to strlen(). Reported by swift@alum.mit.edu via the Debian bug-tracking system. D. New global options syslog_error and syslog_success for customizing syslog() output levels. By default, if logging to syslog is enabled, super logs errors at LOG_ERR and successful executions at LOG_INFO. The options syslog_error=xxx syslog_success=yyy set the error and success codes to xxx and yyy, respectively. Here, xxx and yyy are any of the usual syslog() priority and/or facility codes, e.g. syslog_error=LOG_ERR syslog_error=LOG_LOCAL2|LOG_ERR syslog_success="LOG_LOCAL7 | LOG_INFO" The LOG_xxx words can be separated by whitespace and/or "|". Super doesn't know what are sensible codes -- it's up to the super.tab writer to choose meaningful values. For instance, if you used the following (please don't!) syslog_success="LOG_LOCAL1 | LOG_LOCAL7 | LOG_INFO | LOG_ERR" then you will get all those values or'd together and passed to syslog(). E. Fixes for compiling under FreeBSD. The encryption buffer and salt buffer were extended to 256 bytes each -- plenty long under any current Unix, and hopefully for some time to come. From David O'Brien F. Patches for various glitches, such as using %ld instead of %d, %ld% instead of %ld, etc. From David O'Brien . ------------------- What's new for version 3.11.8: A. Fixed segfault that arose when handling certain combinations of globally- and locally-defined environment variables. Problem reported by Gordon Lack (gml4410@ggr.co.uk). ------------------- What's new for version 3.11.7: A. CRITICAL SECURITY FIXES: two separate buffer overruns allowed local root access. All versions between 3.9.6 and 3.11.6, inclusive, are affected. Buffer overrun #1 was reported by Gordon Lack (gml4410@ggr.co.uk); overrun #2 was reported by iss-xforce@iss.net. B. Patches for BSD Net/2. Contributed by David O'Brien . C. Related to (B), the prototyping macro __P() has been replaced by P__(), so that it will be legitimate on all conforming standard C implementations. D. Patches for Solaris 2.6. (I have become convinced that Sun has an engineer whose job title is something like Engineer in Charge of Modifying Standard Include Files So As To Ensure That Configure Scripts Will Break With Each Successive Solaris Release.) E. A few more minor modifications to the documentation (trying to make it easier to wade through). F. Some fixes for the Makefile's install and clean rules, from Martin Schulze (joey@Infodrom.North.DE) and Dmitry A. Fedorov (D.A.Fedorov@inp.nsk.su). G. Corrections to typo's in man pages, from Dmitry A. Fedorov (D.A.Fedorov@inp.nsk.su). H. Fix for the special per-user .supertab files: super was failing to parse user:commands properly. Fix from Terje Eggestad (Terje.Eggestad@novit.no). I. Fixed super so that it won't create a core file -- this is useful on systems w/ shadow passwords, to ensure that the shadow file contents aren't put into a core file. J. Added check for . This is needed for some versions of IRIX, which otherwise don't have FIOCLEX defined. K. New local option argv0. By default, super sets the first argument passed to a command (ie argv[0]) to be the Cmd string, not the path to the command. Thus "super doit" will set argv[0] to "doit", regardless of to the path being invoked. This will cause problems for programs that need a particular value of argv0. You can work around this by placing such programs into wrapper scripts that are in turn called from super, or you can use the local option argv0 to set the value of argv[0]: argv0=DesiredNameHere As a special case, "" means to use the fullpath by which super is invoking the command. For example, doit /Path/To/My/Prog argv0= will execute /Path/To/My/Prog with argv[0] set to "/Path/To/My/Prog". ------------------- What's new for version 3.11.6: A. SECURITY FIX: super -c or super -F xxx would check any file, e.g. /etc/shadow. This is now fixed by using access(2) to verify that the original caller has the right to read the specified file. Reported by Valentin Iliev . B. Bugfix: silly bugs in SAFE_PATH definition. C. added -U, -G, and -M options to support additional testing (-U uid means to act as if caller is user uid; -G gid means to act as if caller is group gid; -M mach means to act as if hostname==mach. Nothing is executed, but you can see what would have happened.) D. Added various patches from Martin Schulze (joey@infodrom.north.de), including documentation changes, Linux shadow password support, better hostname canonicalization. E. Bit more documentation. ------------------- What's new for version 3.11.5: A. Modified configure script, hsearch.c, localsys.h, and setuid.c so that super will auto-configure properly on AIX. ------------------- What's new for version 3.11.4: A. Fixed distribution: 3.11.3 didn't contain what it claimed. ------------------- What's new for version 3.11.3: A. Fixed configuration/compilation setup for Linux+glibc: - doesn't declare signal(); - defines _BSD_SOURCE. ------------------- What's new for version 3.11.2: A. Better debug information. Verbosity adjusted to make information presentation a little better. ------------------- What's new for version 3.11.1: A. New global option "lang" / bugfix. The "lang" global option lets you set the language used for daynames in time expressions to any locale available on your host, e.g. :global lang=de would typically cause super to use German names. This was a bugfix: super purported to support localization, but (a) it followed a non-POSIX implementation, and (b) it let the regular user specify the locale! B. Bugfix: super wasn't reporting enough information to users about execution being denied or requested command not existing. ------------------- What's new for version 3.11.0: A. NOTE WELL: The default locations for the super.tab and timestamps files have CHANGED, so that installation would work more smoothly with Gnu configure scripts: (a) super installs into the directory specified by configure --exec-prefix; the default is $PREFIX/bin. (b) super.tab installs into the directory specified by configure --sysconfdir; the default is $PREFIX/etc. (c) the timestamp directory is installed in the directory specified by configure --localstatedir; the default is $PREFIX/var; (c) the man pages are installed in subdirectories of configure --mandir; the default is $PREFIX/man. For example, if you use ./configure --prefix=/usr/local ...then the super executable will be /usr/local/bin/super, the super.tab file will be /usr/local/etc/super.tab, the timestamp directory will be /usr/local/var/superstamps, and the man pages into /usr/local/man/... B. New debug option: The option "-F path-to-superfile" is an extremely useful debug option. It lets you specify the super.tab file. For security, no command will ever be executed. If used with a commandname, the matched command will be shown but not other debug info. It lets you test an entry for a super.tab file without actually installing the file: super [-d | -D] -F my_new_super.tab some-command C. New debug option: The option "-T timeofday" is another useful debug option. It tells super to act as if the time of execution is timeofday, where timeofday has the format hh:mm/dayname (using the same daynames as are accepted in the super.tab file). For security, no command will ever be executed. This lets you test if a time condition is properly limiting execution of a command: super -d -F my_new_super.tab -T hh:mm/day some-command D. New builtin command: :if aaa op bbb rest-of-line provides limited conditional support. Here, aaa and bbb are strings (can be variables), op is one of "==" (equals), "!=" (does not equal), "~" (glob matches), "!~" (does not glob-match), and the rest-of-line is evaluated if and only if the expression is true. Examples: :if $UNAME_MACHINE ~ sun4* :include MySunSpecificFile ...includes MySunSpecificFile on Sun4-type machines only; :if $UNAME_MACHINE ~ sun4* \ :if $UNAME_MACHINE != sun4c :include MySunSpecificFile ...includes MySunSpecificFile on Sun4-type machines only, excluding Sun4c machines. E. New builtin command: :optinclude filename is like the :include command, except that if filename is missing, it's silently ignored. If you use this, be SURE not to write later super.tab entries that depend on the presence of the file. (I do _not_ recommend using :optinclude, because you won't be informed if you make a sysadmin error, and delete one of the include files.) F. New builtin variables: The following variables are automatically defined, so that you can use them in :if lines (or anywhere else, of course). Examples: :if $SI_ARCHITECTURE != alpha :include SomeFile :include super.tab.$NIS_DOMAIN Items that are unavailable on your system are set to "". (Items may be unavailable because your system doesn't offer the required function, or because your system's function doesn't support all the specific items super tries to get.) (a) From gethostname() or sysinfo(): HOSTNAME system's hostname. Depending on super's configuration, the hostname returned by the function may be modified if super attempts to canonicalize the name. (Use super -b to print the names and values of all builtin variables.) (b) From getdomainname(): NIS_DOMAIN The domain set for NIS purposes; it is not necessarily an Internet domain. (c) From the sysinfo() function: SI_SYSNAME name of operating system SI_HOSTNAME name of node SI_RELEASE release of operating system SI_VERSION version field of utsname SI_MACHINE kind of machine SI_ARCHITECTURE instruction set arch SI_HW_SERIAL hardware serial number SI_HW_PROVIDER hardware manufacturer SI_SRPC_DOMAIN secure RPC domain (d) From the uname() function: UNAME_SYSNAME Operating system name. UNAME_NODENAME The nodename. UNAME_RELEASE Operating system release. UNAME_VERSION Operating system version. UNAME_MACHINE Machine hardware name (class). G. New command-line option: The -b option prints out the builtin variables, then exits. This makes it easy to see what variable values to check for in :if lines: % super -b Builtin variables: UNAME_SYSNAME: SunOS UNAME_VERSION: 2 ... H. Added -I. to Makefile so that compilation would succeed under VPATH. I. Added env=... to be a global option as well as a local option. J. Added maxenvlen=nnn to be a global or local option; gives the maximum allowed length of an envvar definition. Default=1000. Negative=no limit. K. Pretty-printing: improved the formatting under super -d and super -H. L. Added option maxlen=[mmm,]nnn (local or global). Arguments are restricted to be a maximum of mmm characters long individually (including trailing null), and nnn characters total. The default limits are 1000 and 10000, respectively. Values < 0 mean no limits; unlimited argument length can be configured using: :global maxlen=-1,-1 M. Fixed missing initializations for some flags when super is invoked from a symlink. Reported by Jeff W. Stewart (jws@anaconda.cc.purdue.edu). N. Fixed SAFE_PATH initialization. Reported by Lawrence Lowe (lsl@hep.ph.bham.ac.uk) and Gordon Lack (gml4410@ggr.co.uk). O. Bugfix: if the nice increment was set to a negative value, and the program was to be run non-setuid-root, the nice increment was changed to be applied _before_ the setuid/setgid operations. (Negative nice increments can't be except while running as root, of course.) P. Bugfix: fixed envvar setting so that HOME, USER, and LOGNAME are set correctly when uid=NNN or u_g=NNN are numeric. For example, uid=0 had caused the USER envvar to be "0". Q. Bugfix: super -D core dumped. Reason: super was passing an integer to a debug message, at a place where a string was expected. (Reported by swift@alum.mit.edu.) R. Tried to make man pages, especially the super.1 page, more clear. S. Changed the -h option to only give a usage listing. Thus super -h ...usage super (no args) ...list available commands, tersely. super -H ...list available commands, expansively. ------------------- What's new for version 3.10.0b6: A. Instead of closing descriptors >2 right away, the close-on-exec flag is instead used for machines with this feature. For IRIX 5 (and others?), this is a bugfix, not just a general improvement: Gordon Lack wrote ``Irix NIS seems to "cache" a UDP connexion on a file-descriptor, and super closes this before execing''. Bugfix/improvement courtesy of Gordon Lack (gml4410@ggr.co.uk). ------------------- What's new for version 3.10.0: ** If you are familiar with super version <=3.7.2, but haven't used ** a more recent version, please read the changelist back through 3.8.0! ** There have been MANY enhancements since 3.7.2. A. EASIER INSTALLATION: configuration is now handled by a configure script. This reduces the number of items you have to hand-adjust from 20 to none at all (if you like the defaults). B. SECURITY FIX: Until version 3.9.7, super never did anything to change the supplementary groups list. This is not a security problem if you are adding privileges (such as switching to root), but it is a potential problem if you are switching to a different user and/or a different group. Solution: this version of super adds the following new semantics: If you use u+g=foo, then the user is set to foo and the group is set to foo's login group (as in earlier versions), and the supplementary groups are set to foo's supplementary groups list (new feature). Otherwise, the supplementary groups list is deleted. See also the new options groups=a,b,... and addgroups=a,b,... The problem was reported and a workaround supplied by Morten Rolland (Morten.Rolland@si.sintef.no). C. BUGFIX: Super had assumed that there would only be one ":global_option" line. If there were multiple :global_option instances, and logfile=xxx was used before the last :global_option instance, super would create multiple logging processes. Worse, interactions with password checking could lead to super's running a command without getting the user's password (when password=y). The bug was reported by Richard Czech (Richard.Czech@gmd.de) D. PER-USER SUPER.TAB FILES: Super now allows ordinary users to supply their own super.tab files. This lets users give well-controlled setuid/setgid access to their programs: the user who offers the program gets the assurance of safe IFS settings, safe environment variable settings, etc; and the user who executes the program knows that it will execute under the uid of the offering user. o The user-supplied super file is .supertab, in the home directory of the user, and must be owned and writable only by the owner. o Joe user's supplied command "foo" is invoked by typing super joe:foo Super will act as follows: i. immediately changes its uid, gid, and supplementary groups to be those of the owner of the super.tab file (joe); ii. close all descriptors except for stdin, stdout, and stderr; iii. follow its usual rules for processing super.tab files, except that any options that require setuid() or setgid() will fail since super is running as an ordinary user. E. EASIER LISTS: in the past, super permitted csh-style brace-expansion for valid-user patterns. It has also allowed comma-separated lists for some options (e.g. fd=n1,n2,...). These forms have been synthesized into a single format: anywhere a list makes sense, either comma-separated or brace-expansion is permitted. (The implementation is easy: the list is wrapped in braces, and then brace-expansion is done.) F. NEW OPTION groups=a,b,... supplementary group list is a,b,c groups= supplementary group list is empty causes super to set the supplementary groups to the named list, before exec'ing the command. G. NEW OPTION addgroups=a,b,... causes super to add the named groups to the supplementary set before exec'ing the command. (Note: the supplementary set is intialized to be empty unless the option u+g=foo is used, so addgroups=a,b,... usually has the same affect as groups=a,b,... Alternatively, groups= addgroups=a,b,... will set the groups' to the caller's login groups, then add a,b,... to the list.) H. NEW OPTION cd=SomePath causes super to change directory to SomePath before executing the command. This can be global or local; the local overrides the global setting. I. NEW OPTION rlog_host=hostname tells super which host's syslog daemon is to receive log messages when option syslog=y is enabled. Default=localhost. J. NEW OPTION gethostbyname=y|n tells super to enable/disable hostname lookup using gethostbyname(). Default: enabled (if you have gethostbyname()). K. CHANGE TO NETGROUP HANDLING: hostnames beginning with ``+'' are _always_ treated as NIS netgroup names -- that is, @+xyz means that anyone at a host in netgroup xyz can execute the command. If your system doesn't have innetgr(), patterns beginning with ``+'' will not ever match any hostname. (Previously, interpreting ``+'' as a special character was enabled as compile-time option.) L. CHANGE TO GETHOSTBYNAME() USAGE: if you have gethostbyname(), it gets compiled in and will be enabled by default; use global option gethostbyname=n to disable. (Previously, you had to define USE_GETHOSTBYNAME to compile it in, and there was no switch to turn it off.) M. CHANGE TO SYSLOG() USAGE: we always compile the rsyslog() function from Jean-luc Szpyrka, so you can always send syslog output to either a remote or local host. The new option rlog_host=xxxxx specifies the host that receives the messages; the default is "localhost" -- i.e. same behavior as plain syslog(). (Previously, neither syslog() nor rsyslog() use was compiled in unless USE_SYSLOG was defined.) N. SPECIAL NAMES: Two name have been added that you can use as an argument to any of the options owner=xxx, uid=xxx, gid=xxx, u+g=xxx, groups=xxx, addgroups=xxx, umask=xxx. These names are means owner of the file to be executed (or owner's group, whichever is appropriate in the context); means the owner or group of the user calling super. The angle brackets are literally part of the name. (Exception: umask= makes no sense and isn't defined.) Example: gid=Foo uid= would change the group only, but leave the uid unchanged -- this is something you could not formerly do in super. O. Updated man pages. P. Security enhancement: the default umask is no longer inherited from the caller; instead it is set to 022. However, you can set it to the caller's umask by using the option umask= Q. Dead code elimination: a branch of code made a call to the unsafe (on some systems) function getlogin(). This branch of code was never invoked, and has now been completely eliminated. ------------------- What's new for version 3.9.7: A. Super 3.9.6 installed the "setuid" program as setuid-root. This is a severe security hole. Version 3.9.7 removes the setuid-root entry from the Makefile. ------------------- What's new for version 3.9.6: A. Important bugfix for version 3.9. Super had its internal structure overhauled for version 3.9. Unfortunately, one important error was introduced: the super.tab options uid=xxx group=xxx u_g=xxx were not properly reset from one entry to the next. This version fixes that error. B. A new -c option: causes super to check the syntax of a super.tab file, but not actually execute anything. Its use: super -c [superfile] When you modify a super.tab file, you should use super -c to check the file's overall syntax, and also use super -d cmd for each modified command cmd, to verify that the details of the invoked command (args, uid, gid, umask, etc) are what you wanted to do. C. A new -f option: this is a "just the facts, ma'm" help mode: it prints lines like: CmdPattern FullPath [leading args] CmdPattern FullPath [leading args] ... which allows scripts to make lists of commands the user may execute. D. A new super.tab option has been added: print="msg" causes the message to be printed just before exec'ing the command. E. Better man page information. F. Replaced DIE=msg with die=msg. (Retaining DIE=msg as obsolete form.) ------------------- What's new for version 3.9.5: A. Patches to 3.9 for Digital UNIX, from Stephen Carney (carney@gvc.dec.com). ------------------- What's new for version 3.9.4: A. Bugfix for yet another silly error if invoked via symlink in version 3.9.2. Error pointed out and fixed by Rein Tollevik (Rein.Tollevik@si.sintef.no). B. Syslog messages were always logged at priority SYSLOG_PRIORITY. Error found and fixed by Rein Tollevik (Rein.Tollevik@si.sintef.no). C. If the preprocessor symbol SUNOS5 is defined, then the symbol SVR4 is also defined (if not already done) in super.h. One ifdef'd section of code was changed to look at SVR4 instead of SUNOS5; hopefully this will be an improvement for other SVR4-based systems. ------------------- What's new for version 3.9.3: A. Wrong processing if invoked without any arguments, or if invoked via symlink. Error pointed out and initial fix by Gerry Singleton (Gerry.Singleton@Canada.Sun.COM). ------------------- What's new for version 3.9.2: A. Makefile entries and a few #includes needed for TI SYS V 3.3, from Oyvind Gjerstad (ogj@it.tollpost.no). ------------------- What's new for version 3.9.1: A. Left some commas out of an #ifdef'd initialization array. Bugfix from Oyvind Gjerstad (ogj@it.tollpost.no). B. Fixed: variable expansion happening inside comments, reported by Oyvind Gjerstad (ogj@it.tollpost.no). ------------------- What's new for version 3.9.0: ** If you are familiar with super version <=3.7.2, make sure you ** ** read the changes in 3.8.0! There have been MANY enhancements ** ** made since 3.7.2. ** This version consolidates all of the changes done in beta tests of 3.8, and added enough new items that I had to change the version number to 3.9 (without pausing for a non-beta version of 3.8). The improvements have come thick and fast, but that will now stop and only corrections will be done to v3.9 for some time to come. The visible changes are: A. The super.tab control line format has been generalized. The old syntax and semantics remain a valid subset -- old super.tab files will continue to work as expected. Super now takes the following approach to selecting a command to execute. For each control line in the super.tab file, super requires that: 1. The user's typed command must match a control-line command; 2. The user's name/group/host must match one of the user/group/host entries; 3. The current time and day must match a time entry (if any are given); Otherwise, super "falls through" and tries the next control line. The user/group/host and time entries are called _conditions_ that must be matched. _Options_ on the control line are handled very differently from _conditions_. After conditions are met and a line is nominally selected for execution, all options must be satisfied, or super quits without executing the command and without trying further control lines in the super.tab file. This distinction between conditions and options is easy to use in practice: basically, super searches for a line that matches a command, user and time of day. When the line is found, super will execute the command if the options -- such as a required password or restrictions on command arguments -- are satisfied; otherwise, it stops. There are three important differences between conditions and options. 1. If conditions aren't matched, super will "fall through" and look at the next line. In contrast, when options are checked, super will quit if the options aren't satisfied. 2. Conditions can be "negated", that is, !condition~pattern means that if the pattern is matched, the user is _rejected_ from using this line. Options can't be negated. 3. Many similar conditions be applied, and the last-matching condition is used. For example, the list of user-conditions :develop !joeblow says that anybody in group "develop" can use the command, but then rejects joeblow, even if he is in the develop group. If an option can appear more than once on a line, all instances of the option must be satisfied, not just the last-matching instance. As part of the syntax generalization, user patterns may now begin with "user~": user~:develop !user~joeblow Options and conditions can be interleaved. B. time~pat is a new condition that has to be met before the line is accepted for execution. See next item for sample uses. All time patterns on a line must be matched or super will continue to the next control line. For example, time~{8:00-12:00,13:00-17:00} !time~{sat,sun} or time~{8:00-12:00,13:00-17:00}/{mon,tue,wed,thu,fri} restricts a command to being used during typical office hours on weekdays. C. DIE=msg is a new option that can be used in a command line to force super to exit (and print msg) if the rest of the command line is successfully matched. Here are a few examples that also illustrate use of the new :define command. :define RestrictedCommands ... :define weekdays {mon,tues,wed,thurs,fri} :define BadHours time~0-08:30/$weekdays \ time~17:30-24:00/$weekdays \ time~{sat,sun} $RestrictedCommands $BadHours \ DIE="You can't use this command outside of office hours." or :define RestrictedCommands ... :define officeHours {8:30-12:30,1:30-17:30}/{mo,tu,we,th,fr} $RestrictedCommands !time~$officeHours DIE="hahaha" Without the DIE option, super will try to execute the restricted commands during the restricted hours. D. gethostbyname() is now called both with and without a trailing dot in the hostname. If both forms succeed, the longer returned name is kept, except that any trailing dot is deleted. E. nice=nnn changes the ``nice'' level of the executed command by an amount nnn from the default level. (Positive increments reduce the command's priority; negative increments increase it.) F. umask=nnn (local or global option) makes commands run with the specified umask. Useful if you want to help ensure that files are created with restricted access permissions. G. :include filename allows a super.tab file to include other files. The filename must either be an absolute path or is interpreted relative to the directory containing the super.tab file, and the same restrictions are put on the file ownership and permissions as for the top-level super.tab file. The number of nested includes is limited only by the number of allowed open files. Use with caution! H. The new local option argMMM-NNN=SSS or argNNN=SSS (where MMM and NNN are positive integers, and SSS is a string) means that the MMM-NNN'th user-entered arguments must match pattern SSS. The pattern SSS must be enclosed in quotes if it contains whitespace. Note that this doesn't _require_ MMM-NNN arguments; it only says what those arguments must look like, if entered. I. Updated and corrected super.5 man page. J. Fixed "mail" option. It can be used as either a global or local option. ------------------- What's new for version 3.8.0: (The first 5 items are substantive visible changes/enhancements! Please read them!) A. The rule for processing backslash-newline-whitespace (indicating continued lines) IS MODIFIED. THE NEW RULE IS: - if it follows a letter, digit, or underscore, replace the sequence with a single space. - otherwise, it is eliminated entirely. Therefore, you can type Cmd File user1\ user2\ user3 and it is equivalent to Cmd File user1 user2 user3 But typing Cmd File {user1,\ user2,\ user3} is equivalent to Cmd File {user1,user2,user3} B. Variables are now supported! You can type :define okusers {joe,jane,tom,sally} The above could also have been written :define okusers {joe,\ jane,\ tom,\ sally} and then use Cmd FullPath $okusers with the obvious result. (The variable name may be enclosed in parentheses to insulate it from the characters which follow.) Read the man page super.5 before proceeding to use variables! C. New global option syntax: :global globaloptions... or :global_options globaloptions... The old syntax: / / globaloptions is still supported, but its use is discouraged. D. Multiple commands/filenames are now allowed on one line. Now you can type Cmd1::FullPath1 Cmd2::FullPath2 [...] ok-user-pats This can be useful for treating a group of commands as a unit: :define Common_cmds Cmd1::FullPath1 \ Cmd2::FullPath2 \ Cmd3::FullPath3 :define okusers {\ :operators,\ joe,jane,tom,sally} $Common_cmds $okusers E. In general, a colon in a Cmd part of a line is now reserved to super, and must not be used as part of the Cmd name. This has been done to support the :define and :global commands, the Cmd::File syntax, and provide space for future development. F. The super.tab file can now be owned by root or nobody. This change is to support networked accounts. G. Substantial modifications to hostname matching to improve handling of netgroups. (From Steve Robbins -- steve@cim.mcgill.ca) H. Added Makefile entry Max + header #ifdef's for SGI v5.3 (from Max Buchheit, buchheit@ccrs.emr.ca). I. Fixed comparison between char and NULL. Added Makefile adjustments for Solaris 2.4 (SunOS 5.4). J. Fixed an error related to an appended dot on hostnames. (from Geoffrey A. Lowney, Geoffrey.A.Lowney@Boeing.com) K. If compiled with __STDC__ defined, prototypes are used. L. Disabled "mail" global option. Nobody was using it, and it wasn't implemented right anyway... maybe that's why nobody used it :-). M. Disallowed relative pathnames unless global option relative_path is set. This is to prevent admins from accidentally making a stupid error. N. Disallowed slash in groupnames unless global option group_slash is set. This lets us find formatting errors more easily -- namely, using Cmd:File instead of Cmd::File. ------------------- What's new for version 3.7.4: A. Added setenv=var=xxx option. This option defines environment variable var to have value xxx, and adds it to the environment variables that are kept when the command is executed. Can be used multiple times to add definitions for multiple variables. Note that "setenv=DISPLAY" is syntactically invalid (missing the `=' after the variable name), and that "setenv=DISPLAY=" sets DISPLAY to the null string. (Recall that you can also use the option "env=var1,var2,..." to keep a list of user-defined environment variables.) B. Improved error reporting. ------------------- What's new for version 3.7.3: A. *** NOTE WELL *** Changed processing of FullPathNames with quoted arguments: the quotes are now stripped (it was an error that they weren't). For example, the super.tab entry doit "/usr/bin/xxx -o1 -o2 -xrm 'a b c'" willie allows user willie to type super doit and to execute /usr/bin/xxx with arglist argv[0]: doit argv[1]: -o1 argv[2]: -o2 argv[3]: -xrm argv[4]: a b c Previous versions of super would pass argv[4] as 'a b c', including the single quotes. B. Added #ifdef to define LOG_USER and LOG_ERR if they aren't defined in . C. When logging successful super uses, added #ifdef so that the message priority isn't set unless USE_SYSLOG is defined. D. Added Makefile entry for Ultrix 4.3 (from Christoph Geelen, geelen@rzulx1.mpie-duesseldorf.mpg.de). E. Added Makefile entry for UnixWare 2.0 (from Pete Holsberg, pjh@tecoma.mccc.edu). F. Added Makefile entry and super.c patches for Digital UNIX V3.2 (formerly DEC OSF/1); from Stephen Carney, carney@gvc.dec.com. ------------------- What's new for version 3.7.2: A. Added owner=xxx option so that super won't run a program unless it's owned by xxx. ------------------- What's new for version 3.7.1: A. Modified error msg for clarity. B. If super.tab isn't owned by root, then: + if real uid is root, bail out: don't run at all. + if real uid isn't root, run as real uid (can be useful for testing). ------------------- What's new for version 3.7.0: A. Changed hostname comparisons to be case-insensitive. (From Steve Robbins -- steve@cim.mcgill.ca) B. New capability: wildcard commands. In previous versions of super, entries in the super.tab file looked like: CmdName FullPathName PermittedUsers This is now supplanted by a new format, which is a superset of the previous one (note that all existing super.tab files remain valid): CmdPattern FullPathName-with-optional-"*" PermittedUsers There are two new features here: 1) The former CmdName string is now interpreted as a pattern (with csh-style brace expansion, so that it can actually stand for a variety of commands). 2) If there is an asterisk in FullPathName, it is replaced by the user's cmd. In the usual situation, in which CmdPattern is still just a plain name without wildcards, the user (a) types "super cmd"; (b) the cmd is matched against CmdPattern; (c) the user checked to be a PermittedUser, etc; (d) FullPathName is then executed. As long as CmdPattern is just made up of letters, digits, and underscore, and FullPathName has no asterisk, the effect will be exactly as super has always acted. If you put special pattern-matching characters into the CmdPattern, you simply give more ways a user can execute the same FullPathName. This isn't yet very exciting, and in fact isn't a good idea at all. The power of using patterns in the CmdPattern string comes when FullPathName includes an asterisk. In that case, the asterisk is replaced with the user's "cmd" string to form the actual command to exec. For instance, a SysV-based host might have an entry in the super.tab file that looks like: /usr/bin/{lp,lpstat,disable,enable,cancel} * :operators This would allow anybody in the "operators" group to have root access to the line printer commands. For instance, if the user typed: super /usr/bin/disable some_printer then the FullPathName == "*" would be replaced by /usr/bin/disable, and become the command to exec. More conveniently, the super.tab file could have a line like: {lp,lpstat,disable,enable,cancel} /usr/bin/* :operators In this case, the user can type super disable some_printer The asterisk is replaced by "disable" to form the command /usr/bin/disable. If you _completely_ trust some users, but want logging of all actions, you could use: /* * ReallyReallyTrustedUsers (if the global option patterns=shell has been set) or /.* * ReallyReallyTrustedUsers (the default case: patterns=regex). The user can now execute any command. Note that the pattern begins with a slash, to ensure that the cmd must be an absolute path -- this helps avoid accidental execs of the wrong program. Of course, if you were really going to give everything away as shown above, you'd probably want to exclude any public-area workstations, require the trusted users to periodically give their passwords, and set the real uid=root (instead of just the effective uid), so the entry might be modified to read: /* * TrustedUsers !{PatternsOfPublicWorstations} \ password=y timeout=5 uid=0 (if the global option patterns=shell has been set). (These changes were inspired by Aaron Schuman, schuman@sgi.com) ------------------- What's new for version 3.6.1: A. Added support for shadow passwords on HP-UX 9.x. ------------------- What's new for version 3.6.0: A. Changed super's logging to offer networked syslog messages: all syslog messages can be sent to a single host. B. Provided bugfix with -V option (super could coredump otherwise). (These changes provided by Jean-luc Szpyrka, jls@sophia.inria.fr) ------------------- What's new for version 3.5.2: A. Bugfix: the full path of the executed command was inserted as argv[1] in the output arguments, when it didn't belong there at all. B. Bugfix: log messages for _successful_ commands weren't being newline-terminated. (These bugs reported by Olof Backing, obg@nada.kth.se) ------------------- What's new for version 3.5.1: A. Added better copyright + licensing info. B. Did some code cleanup (getting rid of unused variables, adding declaration of wait(), etc). C. After logging a super call to the logfile, failed exec's might not be printed on the screen (although they were logged in the logfile). ------------------- What's new for version 3.5: A. Added pattern negation to super.tab: !pat says to disallow a user who matches the pattern. Until now, you could only give permission to users that matched, not take it away. Patterns are scanned left-to-right, and the allow/disallow depends on the last pattern that matches. This lets you do things like cmd /Full/Path :goodguys !jan to mean allow anybody in group goodguys, but then disallows user jan, even if jan is in goodguys. B. Added user/group/host patterns to the global settings: / / [global opts] pat pat ... <> pat pat ... User/group/host patterns to the left of "<>" are processed _before_ the per-command patterns; user/group/host patterns to the right of "<>" are processed _after_ the per-command patterns. If "<>" is missing, all patterns are processed after the user patterns. For example, / / jan <> !@+badhosts says that user jan can execute any command (unless a per-command pattern explicitly disallows jan from executing a particular command), but under no circumstances will a user on any host in netgroup ``badhosts'' be allowed to execute any command. (Thus jan can execute any command, but only from hosts _not_ in ``badhosts''.) (These changes were inspired by Jean-luc Szpyrka, jls@sophia.inria.fr .) C. Added special handling of hostnames: If a host is using DNS names, and the hostname isn't matched in the super.tab file, it's possible that the reason is simply that gethostname() returns a name with fewer or more components of the fully-qualified domain name (fqdn) than is in the hostname pattern in super.tab. For example, gethostname() might return "w.x.y.z", but the hostname pattern might be simply "w". Until now, super wouldn't consider this a successful match. If you enable the new feature USE_GETHOSTBYNAME, then if the hostname doesn't match the pattern directly, super will determine the fqdn, and then compare ever-shorter parts against the pattern. For instance, given the hostname "ab.cd.ef.gh", super will test "ab.cd.ef.gh", then "ab.cd.ef", then "ab.cd", and finally "ab". Warning: using this option may reduce security a bit - your host may query a nameserver on another host to obtain the FQDN, and that nameserver could conceivably have been subverted and then return incorrect hostnames. (Idea from Dave Curry, davy@ecn.purdue.edu). D. Fixed a bug in creating timestamp files. Basically, unless the global option timestampuid=0 was set, one frequently got a message "Timestamp creation failed" and then couldn't run a command requiring a password. (Bug reported by Brian Huntley, bhuntley%tsegw.tse.com@spectre.uunet.ca) E. Changed super's logging to include the arguments passed to the command. (Patch from Dave Curry, davy@ecn.purdue.edu). F. An error in the str_val() function allowed some typos in option names to pass unnoticed. Files with properly typed option names were not affected. G. Modified some error messages that were not printing accurate information about why access was being denied. H. Bugfix: comments in super.tab are supposed to only go up to newline, but instead they ran to the end of an input block. I. Ported to SCO 3.2v4. (Changes from Keith Menard, menard@gateway.wtc.com) J. Fixed error in processing backslashes in super.tab lines (backslash-newline was being processed correctly; others left super in an infinite loop). K. Stripped down the strqtok function that splits input lines of text. ------------------- What's new for version 3.4.9: A. Added #ifdef's and Makefile entries for Clix 3.1 r.7.1.3 (Intergraph) contributed by David Sandmann (das@ipro15.aaa.com). B. Added #ifdef'd code to implement scripts that start with "#! interpreter" on OS's which don't support it directly. ------------------- What's new for version 3.4.8: Minor bugfixes: A. _Successful_ executions of commands were not being logged by syslog unless they were also being logged to a (non-syslog) file. B. There were formatting errors and other minor mistakes in the super.5 man page. C. Changed the example in README and the super.1 man page regarding how a program can super itself, so that it will work on all Bourne shell variations (the argument to "test" had to be protected against empty strings.) ------------------- What's new for version 3.4.7: A. Bugfix for patterns like uuu:ggg and uuu: ...valid user is denied access. Bug report & fix came from Karen L Dickerson (kld@mudshark.sunquest.com). ------------------- What's new for version 3.4.6: A. Bugfix for sites that don't compile with USE_NETGROUP but do specify a hostname. Bug reported by Adam P. Harris (apharris@mcs.com). ------------------- What's new for version 3.4.5: A. Improved parsing for arguments that super supplies to commands. Previously, only whitespace would separate arguments. Version 3.4.5 parses the FullPathName with recognition of embedded quotes and backslashes. For example, suppose the super.tab file contains a line like cmd "FullPath -a -b 2\ 3 -xrm 'r s t \ u v w' ..." SuperOptions... validusers... The "FullPath..." string (containing the arguments -a, -b, ...) ... is parsed using Bourne-shell-like rules for backslashes and quotes, and the line is parsed as argv[0] FullPath argv[1] -a argv[2] -b argv[3] 2 3 argv[4] -xrm argv[5] r s t u v w (Use "super -d cmd" to check that your args are being parsed as expected before you unleash a new command on your users.) ------------------- What's new for version 3.4.4: A. The timestamp file of user@host.name.dom is now by default stored in TIMESTAMP_DIR/hostname/user with the old behavior (TIMESTAMP_DIR/user) being an option controlled with global option timestampbyhost=y|n. The timestampuid=xxx option has been added to allow timestamp files to be created under a particular uid. This allows for a cross-mounted timestamp directory on hosts that map NFS root accesses to nobody, but still keeps the password entries distinct on different hosts. B. TIMESTAMP_DIR is now documented in the Makefile, so that it is easily configured at compile time. ------------------- What's new for version 3.4.3: A. Option -H has been added to give the long-winded help information that has been the only thing printed until now. The -h option now prints a short help listing: Command Comments ------- -------- cmd1 help info for cmd1 cmd2 help info for cmd2 ... ------------------- What's new for version 3.4.2: A. If "xyz" is a symlink to super, then % xyz args... is treated by super just like % super xyz args... Super detects such symlinks by the rule that argv[0] must match "*/super" or "super"; otherwise, it's assumed to be a symlink. Therefore, a symlink named "super" won't work -- super won't recognize it's being invoked via symlink. ------------------- What's new for version 3.4.1: A. When printing debug info, there was misformatted output of any extra file descriptors being held open. (The problem only occurred in 3.4.0, not earlier versions.) ------------------- What's new for version 3.4: A. Added nargs=[mmm-]nnn to limit user-entered args. ------------------- What's new for version 3.3.2: A. Allow "@hostname", without any user or groupname part. ------------------- What's new for version 3.3.1: A. Fixed SunOS 5.x to use "getspnam()" when looking up passwords. ------------------- What's new for version 3.3: A. Added mail="....." global option. B. Fixed goofy error in parsing password=n. C. Added syslog=y|n option. ------------------- What's new for version 3.2: A. Added options password=y|n, timeout=n, renewtime=y|n to require passwords on specific commands (or all commands). B. A bugfix: if the super.tab file tried to pass options to the executable command, the exec would fail. ------------------- What's new for version 3.1: A. Added global option loguid=xxx to allow the logfile to be opened under a uid other than root. This allows the logfile to be shared across a network over which root doesn't have write access. ------------------- What's new for version 3.0: A. Command logging -- you can specify a file to receive a log of super uses and attempts. B. More environment variables -- for each entry, the super.tab file can specify environment variables that should be passed to the command instead of discarded. You simply add entries like env=TZ,TAPE to the super.tab file, to keep TZ and TAPE in addition to the default list. Of course one has to use this with caution. C. Set uid/gid -- for each entry, the super.tab file can specify the uid and/or gid (the default is to only change the effective uid to root). To use this, you add entries like uid=xxx gid=yyy to the super.tab file, or u+g=xxx to set the uid to xxx and the gid to xxx's login gid. As a supplement to the setuid/setgid ability, super defines some extra environment variables so that the invoked command can know the username and home directory of the user who invoked the command, as well as that of the uid under which the command is executing. D. Open file descriptors -- for each entry, the super.tab file can specify a list of file descriptors that should not be closed (in addition to the default 0,1,2). E. Initial arguments -- for each entry, the super.tab file can specify a set of initial arguments that are put into argv[] ahead of the arguments the user typed on the command line. F. super -h now only prints the commands that may be executed by the user; and the super.tab file can specify a line of explanatory text to be printed with each command. G. A bugfix: The TERM environment variable can now contain "-+_.:/" in addition to [a-zA-Z0-9]. H. The super.tab file can be configured with either Bourne-shell style or regex (ed-style) valid-user patterns; the default is regex. ------------------- What's new for version 2.0: A. A couple of bugfixes. (These fixes were first introduced in version 1.2.) B. You can restrict commands to particular users on particular hosts. This allows one "super.tab" file to serve many hosts. C. Entries in "super.tab" can now span multiple lines. Helpful when one file serves many users + hosts. D. csh-style brace-expansion: super's pattern-matching previously was done with the BSD 4.x regex routines. This is now extended allow csh-style braces. For instance, to allow users pam and sammy, executing from hosts alpha and beta, you can use an entry like {pam,sammy}@{alpha,beta} super-3.30.0/Copying0000400000104100002640000003030710732537455012604 0ustar willspg GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program 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 1, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! super-3.30.0/pam.c0000444000104100002640000001577410732537455012215 0ustar willspgstatic const char rcsid[] = "$Id: pam.c,v 1.6 2004/04/30 17:00:58 will Exp $"; /* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "super.h" #include "version.h" #ifndef HAVE_PAM_START int get_pam(cmd, caller, user) char *cmd; char *caller; /* the person who invoked super */ char *user; /* the person whose authentication is required */ { Error(0, 1, "Error in super.tab file -- this copy of super was compiled on a host without support for authtype=pam\n"); } #else #ifndef HAVE_PAM_STRERROR /* pam_strerror converts a PAM status code to a string, and a returns * a ptr to a static string. This is the Linux pam_strerror() code, * except that I've #ifdef'd everything so that it compiles on systems * that don't have all of the PAM_xxx values. (Note that this only * works if #define is used; an enum would break this.) */ char * pam_strerror(pam_handle_t *pamh, int status) { switch (errnum) { #ifdef PAM_SUCCESS case PAM_SUCCESS: return "Success"; #endif #ifdef PAM_ABORT case PAM_ABORT: return "Critical error - immediate abort"; #endif #ifdef PAM_OPEN_ERR case PAM_OPEN_ERR: return "dlopen() failure"; #endif #ifdef PAM_SYMBOL_ERR case PAM_SYMBOL_ERR: return "Symbol not found"; #endif #ifdef PAM_SERVICE_ERR case PAM_SERVICE_ERR: return "Error in service module"; #endif #ifdef PAM_SYSTEM_ERR case PAM_SYSTEM_ERR: return "System error"; #endif #ifdef PAM_BUF_ERR case PAM_BUF_ERR: return "Memory buffer error"; #endif #ifdef PAM_PERM_DENIED case PAM_PERM_DENIED: return "Permission denied"; #endif #ifdef PAM_AUTH_ERR case PAM_AUTH_ERR: return "Authentication failure"; #endif #ifdef PAM_CRED_INSUFFICIENT case PAM_CRED_INSUFFICIENT: return "Insufficient credentials to access authentication data"; #endif #ifdef PAM_AUTHINFO_UNAVAIL case PAM_AUTHINFO_UNAVAIL: return "Authentication service cannot retrieve authentication info."; #endif #ifdef PAM_USER_UNKNOWN case PAM_USER_UNKNOWN: return "User not known to the underlying authentication module"; #endif #ifdef PAM_MAXTRIES case PAM_MAXTRIES: return "Have exhasted maximum number of retries for service."; #endif #ifdef PAM_NEW_AUTHTOK_REQD case PAM_NEW_AUTHTOK_REQD: return "Authentication token is no longer valid; new one required."; #endif #ifdef PAM_ACCT_EXPIRED case PAM_ACCT_EXPIRED: return "User account has expired"; #endif #ifdef PAM_SESSION_ERR case PAM_SESSION_ERR: return "Cannot make/remove an entry for the specified session"; #endif #ifdef PAM_CRED_UNAVAIL case PAM_CRED_UNAVAIL: return "Authentication service cannot retrieve user credentials"; #endif #ifdef PAM_CRED_EXPIRED case PAM_CRED_EXPIRED: return "User credentials expired"; #endif #ifdef PAM_CRED_ERR case PAM_CRED_ERR: return "Failure setting user credentials"; #endif #ifdef PAM_NO_MODULE_DATA case PAM_NO_MODULE_DATA: return "No module specific data is present"; #endif #ifdef PAM_BAD_ITEM case PAM_BAD_ITEM: return "Bad item passed to pam_*_item()"; #endif #ifdef PAM_CONV_ERR case PAM_CONV_ERR: return "Conversation error"; #endif #ifdef PAM_AUTHTOK_ERR case PAM_AUTHTOK_ERR: return "Authentication token manipulation error"; #endif #ifdef PAM_AUTHTOK_LOCK_BUSY case PAM_AUTHTOK_LOCK_BUSY: return "Authentication token lock busy"; #endif #ifdef PAM_AUTHTOK_DISABLE_AGING case PAM_AUTHTOK_DISABLE_AGING: return "Authentication token aging disabled"; #endif #ifdef PAM_TRY_AGAIN case PAM_TRY_AGAIN: return "Failed preliminary check by password service"; #endif #ifdef PAM_IGNORE case PAM_IGNORE: return "Please ignore underlying account module"; #endif #ifdef PAM_MODULE_UNKNOWN case PAM_MODULE_UNKNOWN: return "Module is unknown"; #endif #ifdef PAM_AUTHTOK_EXPIRED case PAM_AUTHTOK_EXPIRED: return "Authentication token expired"; #endif #ifdef PAM_CONV_AGAIN case PAM_CONV_AGAIN: return "Conversation is waiting for event"; #endif #ifdef PAM_INCOMPLETE case PAM_INCOMPLETE: return "Application needs to call libpam again"; #endif } return "Unknown PAM error (need to upgrade libpam?)"; } #endif /* !HAVE_PAM_STRERROR */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get authentication via PAM */ /* Return 1 on success, -1 on error. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int get_pam(cmd, caller, user) char *cmd; char *caller; /* the person who invoked super */ char *user; /* the person whose authentication is required */ { int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr); static struct pam_conv conv = { misc_conv, NULL }; pam_handle_t *pamh = NULL; int ntry, pamstatus; char msg[500]; FILE *prompt_fp = NULL; char *prompt_dev="/dev/tty"; if (pam_start(ONETRUENAME, user, &conv, &pamh) != PAM_SUCCESS) { return Error(0, 0, "Internal error: can't start PAM authentication!\n"); } if (!(prompt_fp = fopen(prompt_dev, "r+"))) { return Error(0, 0, "Can't open %s for authentication message!\n", prompt_dev); } /* Note that the actual number of tries is the lesser of our MAXTRY * and the PAM module's maximum... */ for (ntry=0, pamstatus = PAM_AUTH_ERR; ntry < MAXTRY && pamstatus == PAM_AUTH_ERR; ntry++) { if (ntry == 0) { if (localinfo.authinfo.prompt && localinfo.authinfo.prompt[0]) { stringcopy(msg, do_variables(localinfo.authinfo.prompt), sizeof(msg)); } else if (strcmp(caller, user) == 0) { (void) sprintf(msg, "Authentication is required for super command `%.400s'...", cmd); } else { (void) sprintf(msg, "Authentication for user %s is required for super command `%.400s'...", user, cmd); } fprintf(prompt_fp, "%s\n", msg); } else { fprintf(prompt_fp, "Authentication failed; try again...\n"); } pamstatus = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK); } fclose(prompt_fp); if (pamstatus != PAM_SUCCESS) { pam_end(pamh, pamstatus); return Error(0, 0, "Authentication failed: %s\n", pam_strerror(pamh, pamstatus)); } if ((pamstatus=pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { pam_end(pamh, pamstatus); return Error(0, 0, "Authentication succeeded, \ but PAM doesn't grant access:\n\t%s\n", pam_strerror(pamh, pamstatus)); } if (pam_end(pamh, pamstatus) != PAM_SUCCESS) { return Error(0, 0, "Internal error: failed to release authenticator\n"); } return 1; } #endif /* HAVE_PAM_START */ super-3.30.0/README.Y2K0000600000104100002640000000364110732537455012540 0ustar willspg Super and Y2000 compliance. Super is not commercial software and I don't supply any guarantees. That said, however, I am confident that it contains no Y2000 bugs. The software is coded using the "time_t" typedef to declare the time-like variables, and it obtains the current time using the ANSI-standard time(3) function. Super converts time_t values into string form by using the ANSI-standard C functions ctime(3) and localtime(3), and it never uses the year number. Therefore, the time values used by super(1) will be as accurate as the underlying system. In other words, super is Y2K-safe on any POSIX-compatible Unix. [[ If you have built super(1) on a system that does _not_ supply the standard ctime() and localtime() functions, then super will supply a function that assumes days can be computed by dividing the time_t value by 86400, and super's accuracy depends on the correctness of this assumption. ]] FAQ: Q1. Will the software will operate correctly through the year 2038, at least? (Note that if your time_t is a 32-bit signed quantity, a time value cannot store time past approximately 03h 19-jan-2038.) A1. Yes. Super will work correctly as long as the system-supplied types and functions time_t, time(), ctime(), and localtime() will work; compiling super on a "Year-2038-compliant" system will produce a version of super that will be Y2038-safe. ------------- Q2. Will the software will operate properly and without incident if it is running between 23:59:59 31 Dec 1999 and 00:00:00 1 Jan 2000. A2. Yes. ------------- Q3. Does the software, in and of itself, understands dates after the year 1999, and correctly interpret them as such? A3. Not applicable: super doesn't use year numbers at all. Super is concerned only with the current time of day and day of week. It has no year numbers, and no "century" digits on which it can make mistakes. super-3.30.0/gsgroups.c0000444000104100002640000000232610732537455013276 0ustar willspgstatic const char rcsid[] = "$Id: gsgroups.c,v 1.8 2004/04/30 17:00:58 will Exp $"; /* This silly little file is here because gcc messes up badly with * prototyping the getgroups() / setgroups() functions on SunOS. * The problem is that on SunOS 4.x, there are two versions of each of * these functions: the usual (non-SysV) version takes an array of ints: * [gs]etgroups(int, int *) * but the Sys V version takes an array of gid_t's: * [gs]etgroups(int, gid_t *). * Unfortunately, gcc insists on the latter. This isn't right for * most compilations -- it won't work unless you link with the * /usr/5lib version of libc. * Hence this little file: it invokes [gs]etgroups declaring its * argument as pointer to void, and _hope_ that this is the same * size pointer as (gid_t *), (uid_t *), and (int *). If it is, * all will work smoothly on any host, yet we avoid including * the file wherein getgroups is inappropriately * prototyped. */ #include "config.h" #ifdef HAVE_GETGROUPS int Setgroups(n, g) int n; void *g; { int setgroups P__((int, void *)); return setgroups(n, g); } int Getgroups(n, g) int n; void *g; { int getgroups P__((int, void *)); return getgroups(n, g); } #endif super-3.30.0/colon.c0000444000104100002640000003063510732537455012543 0ustar willspgstatic const char rcsid[] = "$Id: colon.c,v 1.31 2007/03/07 15:00:18 will Exp $"; #include "super.h" #include "version.h" /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Processes the special ":" builtin commands */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Return -1 if caller should give up parsing the file; * return 0 on success; */ int process_colon_cmds(command, continue_after_if) char *command; int *continue_after_if; /* return !0 iff a :if command evaluates true, * and the caller should continue processing the * rest of the buffer as input text. */ { *continue_after_if = 0; if ((strcmp(":global", command) == 0) || (strcmp(":global_options", command) == 0) || (strcmp("/", command) == 0) /*obsolescent*/ ) { /* Process global options */ return colon_global(command); } else if (strcmp(":define", command) == 0) { /* Process variable definition */ return colon_define(command); } else if (strcmp(":die", command) == 0) { /* Force immediate exit */ return colon_die(command); } else if (strcmp(":getenv", command) == 0) { /* Define variable from envvar */ return colon_getenv(command); } else if (strcmp(":include", command) == 0) { /* Process include-file directive; don't allow missing files */ return colon_include(command, 0); } else if (strcmp(":optinclude", command) == 0) { /* Process include-file directive; allow missing files */ return colon_include(command, 1); } else if (strcmp(":if", command) == 0) { /* Process include-file directive */ return colon_if(command, continue_after_if); } return Error(0, 0, "%t\n\tUnknown builtin command `%s'.\n", command); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :global command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_global(command) char *command; { char *wd; if (strcmp("/", command) == 0) { /* OBSOLESCENT COMMAND */ /* Get the full path; verify that it is '/', then discard */ char *path = strqtokS(NULL, SEP, NULL, NULL, 1); if (!command || !*path || strcmp(path, "/") != 0) return Error(0, 0, "%t\n\tformat error in super.tab file: \ Cmd == '/' requires FullPathName == '/'.\n"); } /* Some global settings need to be reset on each new :global line. */ if (handle_option(NULL, NULL, 1) != 0) return -1; /* Now collect the options and process */ for (strqS_qm = my_qm, strqS_cc = my_cc, wd = strqtokS(NULL, SEP, NULL, NULL, 1); wd; wd = strqtokS(NULL, SEP, NULL, NULL, 1)) { if (global_arg(wd) == -1) return -1; } /* Process logfile requests as soon as possible */ if (globalinfo.log.newfile || globalinfo.log.newuid) if (process_logfile_opt() == -1) return -1; return 0; } /* Process logfile requests */ int process_logfile_opt() { if (globalinfo.log.newuid && !globalinfo.log.newfile) return Error(0, 0, "%t\n\tformat error in super.tab file: \n\t\ loguid=xxx must be used on the same :global_option line as logfile=yyy.\n"); globalinfo.log.newfile = globalinfo.log.newuid = 0; opensuperlog(); return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process a global arg */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int global_arg(word) char *word; /* opt=xxx or condition~Pattern or PermittedUserPattern */ { /* Return 0 on success, -1 if formatting error. */ int invert, iscondition; char **glob; char *s; char *pattern; if (strcmp("\\", word) == 0) return 0; s = word; if (*s == CONDITION_SEP || *s == OPTION_SEP) return Error(0, 0, "%t\n\tBad super.tab syntax: <%s>\n", word); for (s++; *s && ((*s != CONDITION_SEP && *s != OPTION_SEP) || (*(s-1) == '\\')); s++) ; /* s now points to one of: * - the OPTION_SEP or CONTITION_SEP (if there is one), * or * - the null character at the end of a plain PermittedUserPattern. */ invert = (*word == '!'); if (invert && *s == OPTION_SEP) { return Error(0, 0, "%t\n\tsuper.tab syntax error: options cannot be negated: <%s>\n", word); } else if (invert) { word++; } /* Note that word has been advanced past the '!' inversion character */ if (strcmp(word, "<>") == 0) { /* End of globalinfo.before list. Since we accumulate into * globalinfo.after list, just move that list over to * globalinfo.before. */ if (invert) return Error(0, 0, "%t\n\tInvalid global condition \"!<>\"\n"); if (globalinfo.use_after != 0) return Error(0, 0, "%t\n\tMultiple use of `<>' in :global list.\n"); globalinfo.use_after = 1; globalinfo.userbefore.next = globalinfo.userafter.next; globalinfo.userafter.next = NULL; globalinfo.timebefore.next = globalinfo.timeafter.next; globalinfo.timeafter.next = NULL; return 0; } iscondition = (*s != OPTION_SEP); if (iscondition) { /* Do brace globbing. Remember that if the pattern is a plain * PermittedUserPattern, then s points to the null character. * Use a new pointer to point to the actual pattern. */ int i; if (*s == '\0') pattern = word; /* s pts to end of plain PermittedUserPattern */ else pattern = s+1; /* s points to "~"; advance past to pattern */ if (balancedbraces(pattern) != 0) { return Error(0, 0, "%tUnbalanced braces in `%s'.\n", pattern); } if ((i=globbraces(pattern, 1, &glob)) != 0) { /* Global condition */ return Error(0, 0, "%tMissing `%c'.\n", i); } } if (iscondition && STRMATCH3("user", word, s)) { /* It's a PermittedUser pattern */ /* Put the (user/group/host) pattern into the after list. * If we eventually see "<>", we'll move the list to * before list (see above). */ if (globalinfo.user_clear) { free_Simple2List(&globalinfo.userbefore); free_Simple2List(&globalinfo.userafter); free_SimpleList(&globalinfo.b_a_text); globalinfo.user_clear = 0; } if (InsertUserList(pattern, glob, &globalinfo.userafter, &globalinfo.b_a_text, invert) == -1) return -1; } else if (iscondition && STRMATCH3("time", word, s)) { /* It's a PermittedTime pattern. Put it into the after list. * If we eventually see "<>", we'll move the list to * before list (see above). */ if (globalinfo.time_clear) { free_TimeList(&globalinfo.timebefore); free_TimeList(&globalinfo.timeafter); globalinfo.time_clear = 0; } if (InsertTimeList(pattern, glob, &globalinfo.timeafter, "global", invert) == -1) return -1; } else if (iscondition) { return Error(0, 0, "%t\n\tInternal error -- unrecognized global condition <%s>\n", word); } else { return handle_option(word, s+1, 1); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :define command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_define(command) char *command; { extern char *strqS_start; char *varname, *varbody; char *s; varname = strqtokS(NULL, SEP, NULL, NULL, 1); if (!varname) return Error(0, 0, "%t\n\tformat error in super.tab file: \ variable name missing after ':define'.\n"); varbody = strqS_start; if (!varbody) varbody = ""; /* Skip leading whitespace in variable body */ while (strchr(SEP, *varbody)) varbody++; /* Delete final newline from varbody */ s = varbody + strlen(varbody)-1; if (s >= varbody && *s == '\n') *s = '\0'; return add_variable(varname, varbody); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :die command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_die(command) char *command; { char *text; #ifdef COLLECT_ALL_TOKENS extern char *strqS_start; #endif #ifndef COLLECT_ALL_TOKENS /* This collects next token only */ text = strqtokS(NULL, SEP, NULL, NULL, 1); #else /* This collects all tokens (but comments have been elided); however, * quotes remain in text. */ text = strqS_start; #endif Error(0, 1, "%s\n", text); /* shouldn't ever get here */ return -1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :getenv command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_getenv(command) char *command; { char *varname; char *defn; for ( ; (varname = strqtokS(NULL, SEP, NULL, NULL, 1)) ; ) { defn = getenv(varname); if (!defn) { defn = ""; } else if (checkenv(varname, defn, "^[-/:+._a-zA-Z0-9]*$") == -1) { /* Record the problem but continue. */ Error(0,0, "%t\n\timproper definition of envvar `%s': `%-.500s'\n", varname, defn); continue; } /* Store value */ if (add_variable(varname, defn) != 0) { /* Better return -- we couldn't store a definition */ return -1; } } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :if command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_if(command, colonif_succeeded) char *command; int *colonif_succeeded; { char *left, *op, *right; left = strqtokS(NULL, SEP, NULL, NULL, 1); if (!left) return Error(0, 0, "%t\n\tformat error in super.tab file: \ left operand missing after ':if'.\n"); op = strqtokS(NULL, SEP, NULL, NULL, 1); if (!op) return Error(0, 0, "%t\n\tformat error in super.tab file: \ operator missing after ':if'.\n"); right = strqtokS(NULL, SEP, NULL, NULL, 1); if (!right) return Error(0, 0, "%t\n\tformat error in super.tab file: \ right operand missing after ':if'.\n"); if (strcmp(op, "==") == 0) { *colonif_succeeded = (strcmp(left, right) == 0); } else if (strcmp(op, "!=") == 0) { *colonif_succeeded = (strcmp(left, right) != 0); } else if (strcmp(op, "~") == 0) { *colonif_succeeded = wildmat(left, right); } else if (strcmp(op, "!~") == 0) { *colonif_succeeded = (wildmat(left, right) == 0); } else { return Error(0, 0, "%t\n\tformat error in super.tab file: \ invalid operator `%s' in ':if'.\n", op); } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process the :include command */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int colon_include(command, allow_missing) char *command; int allow_missing; /* don't complain if file is missing */ { char *filename, *wd, *s, *opt; extern char *strqS_start; struct passwd *uid_pw; struct group *gr; FileList *fl; char *owner = NULL; /* xxx from owner=xxx */ char *group = NULL; /* xxx from group=xxx */ uid_t uid; /* uid of owner=xxx; -1 means no owner=xxx is set */ gid_t gid; /* gid of group=xxx; -1 means no group=xxx is set */ filename = strqtokS(NULL, SEP, NULL, NULL, 1); if (!filename) return Error(0, 0, "%t\n\tformat error in super.tab file: \ filename missing after ':include'.\n"); /* Check for owner= and group= options */ while ((opt = strqtokS(NULL, SEP, NULL, NULL, 1))) { /* Check for and delete possible newline from opt */ s = opt + strlen(opt)-1; if (s >= opt && *s == '\n') *s = '\0'; if (strncmp(opt, "owner=", 6) == 0) { owner = opt + 6; if (*owner == '\0') { return Error(0, 0, "%t\n\towner not specified in `owner=' option"); } } else if (strncmp(opt, "group=", 6) == 0) { group = opt + 6; if (*group == '\0') { return Error(0, 0, "%t\n\tgroup not specified in `group=' option"); } } else { return Error(0, 0, "%t\n\tgarbage text <%s> after :include command", opt); } } if (owner) { /* :include line contained owner= entry */ if (!(uid_pw = getpwentry(0, owner))) { return -1; } uid = uid_pw->pw_uid; } if (group) { /* :include line contained owner= entry */ if (!(gr = getgrentry(group))) { return -1; } gid = gr->gr_gid; } wd = strqS_start; if (wd && *wd != '\n' && *wd != '\0') return Error(0, 0, "%t\n\tformat error in super.tab file: \n\t\ extra text <%s> after :include filename\n", wd); /* Check for and delete possible newline from filename */ s = filename + strlen(filename)-1; if (s >= filename && *s == '\n') *s = '\0'; fl = file_open(currfile, filename, allow_missing, owner ? &uid : NULL, group ? &gid : NULL); if (!fl) return -1; currfile = fl; return 0; } super-3.30.0/version.h0000444000104100002640000000005710732537455013116 0ustar willspg#define Version "3.30" #define Patchlevel "0" super-3.30.0/options.h0000444000104100002640000001012010732537455013114 0ustar willspg/* Functions for processing option strings are OptionFunc's, and they * have the following arguments: * wd -- the entire "xxxyyy" string; * s -- points to "yyy" in wd; * global -- is !0 if this is a global invocation. */ typedef int (*OptionFunc) P__((char *wd, char *s, int global)); /* Flags for use in the options description */ #define GLOBAL 002 /* option is permitted as global opt */ #define LOCAL 004 /* option is permitted as local opt */ #define LIST 010 /* Run globbraces on argument, then * expanded list as well as string. */ struct option { char *name; /* name of option */ int flags; OptionFunc process; /* Function to process this option */ }; typedef struct option Option; /* Option-processing functions */ int option_clear_settings P__(( char *word, char *s, int isglobal )); int option_global_reset_settings P__(( void )); int option_local_clear_settings P__(( void )); static int option_arg P__(( char *word, char *p, int isglobal )); static int option_argv0 P__(( char *word, char *s, int isglobal )); static int option_auth P__(( char *word, char *s, int isglobal )); static int option_authprompt P__(( char *word, char *s, int isglobal )); static int option_authtype P__(( char *word, char *s, int isglobal )); static int option_authuser P__(( char *word, char *s, int isglobal )); static int option_cd P__(( char *word, char *s, int isglobal )); static int option_checkvar P__(( char *word, char *s, int isglobal )); static int option_die P__(( char *word, char *s, int isglobal )); static int option_egid P__(( char *word, char *s, int isglobal )); static int option_env P__(( char *word, char *s, int isglobal )); static int option_euid P__(( char *word, char *s, int isglobal )); static int option_fd P__(( char *word, char *s, int isglobal )); static int option_gethostbyname P__(( char *word, char *s, int isglobal )); static int option_gid P__(( char *word, char *s, int isglobal )); static int option_group_slash P__(( char *word, char *s, int isglobal )); static int option_groups P__(( char *word, char *s, int isglobal )); static int option_info P__(( char *word, char *s, int isglobal )); static int option_lang P__(( char *word, char *s, int isglobal )); static int option_logfile P__(( char *word, char *s, int isglobal )); static int option_loguid P__(( char *word, char *s, int isglobal )); static int option_mail P__(( char *word, char *s, int isglobal )); static int option_mailany P__(( char *word, char *s, int isglobal )); static int option_nargs P__(( char *word, char *s, int isglobal )); static int option_maxenvlen P__(( char *word, char *s, int isglobal )); static int option_maxlen P__(( char *word, char *s, int isglobal )); static int option_nice P__(( char *word, char *s, int isglobal )); static int option_owner P__(( char *word, char *s, int isglobal )); static int option_password P__(( char *word, char *s, int isglobal )); static int option_patterns P__(( char *word, char *s, int isglobal )); static int option_print P__(( char *word, char *s, int isglobal )); static int option_relative_path P__(( char *word, char *s, int isglobal )); static int option_renewtime P__(( char *word, char *s, int isglobal )); /* static int option_rgid P__(( char *word, char *s, int isglobal )); */ static int option_rlog_host P__(( char *word, char *s, int isglobal )); /* static int option_ruid P__(( char *word, char *s, int isglobal )); */ static int option_setenv P__(( char *word, char *s, int isglobal )); static int option_syslog P__(( char *word, char *s, int isglobal )); static int option_syslog_error P__(( char *word, char *s, int isglobal )); static int option_syslog_success P__(( char *word, char *s, int isglobal )); static int option_timeout P__(( char *word, char *s, int isglobal )); static int option_timestampbyhost P__(( char *word, char *s, int isglobal )); static int option_timestampuid P__(( char *word, char *s, int isglobal )); static int option_u_g P__(( char *word, char *s, int isglobal )); static int option_uid P__(( char *word, char *s, int isglobal )); static int option_umask P__(( char *word, char *s, int isglobal )); super-3.30.0/setuid.c0000444000104100002640000000325710732537455012726 0ustar willspgstatic const char rcsid[] = "$Id: setuid.c,v 1.9 2004/04/30 17:00:58 will Exp $"; #define _POSIX_SOURCE #include #include #include #include #include #include "config.h" #ifdef HAVE_STDLIB_H #include #endif /* setuid -- * changes uid, then executes command. * Use: * setuid uid|username command [args...] * Unlike su, doesn't ever ask for password when executed with effective * uid=root. In contrast, some OS's (e.g. SunOS 4.1.x) seems to prompt * for the root password if your effective uid, but not real uid, is root. * Will Deich * will@astro.caltech.edu * Mar 1992 */ char *prog; int main(argc, argv) int argc; char **argv; { int uid; char *s; struct passwd *pw = NULL; int atoi(), setuid(), execvp(); prog = (s = strrchr(argv[0], '/')) ? s+1 : argv[0]; if (argc <= 2) { fprintf(stderr,"Use: %s uid|username command [args...]\n", prog); fprintf(stderr,"Purpose: changes uid, then executes command.\n"); fprintf(stderr,"Unlike su(1):\n"); fprintf(stderr, " * won't ever ask for password\n"); fprintf(stderr," * args are given to execvp(), not to a shell\n"); (void) exit(1); } if (isdigit(*argv[1])) { uid = atoi(argv[1]); } else { pw = getpwnam(argv[1]); if (pw == (struct passwd *) NULL) { (void) fprintf(stderr, "%s: can't find uid for user `%s'\n", prog, argv[1]); (void) exit(1); } uid = pw->pw_uid; } if (setuid(uid)!= 0) { if (pw) fprintf(stderr, "%s: setuid(user=%s) failed: ", prog, argv[1]); else fprintf(stderr, "%s: setuid(uid=%d) failed: ", prog, uid); perror(""); (void) exit(1); } (void) exit(execvp(argv[2], &argv[2])); } super-3.30.0/sample.cdmount0000444000104100002640000000141710732537455014135 0ustar willspg#!/bin/sh prog=`basename $0` # If script invoked w/o super, then exec super to run this script. test "X$SUPERCMD" = "X$prog" || exec /usr/local/bin/super $prog ${1+"$@"} usage() { cat <<-END Use: $prog hsfs | 4.2 Purpose: Mounts a cdrom on /cdrom. Argument: the cdrom type; specify one of hsfs - cdrom is High Sierra File System 4.2 - usual Unix disk format END } case $# in 1 ) ;; * ) usage ; exit 1 ;; esac type="$1" case "$type" in 4.2 | hsfs ) ;; -h ) usage ; exit 0 ;; * ) echo "$prog: unknown cd type $1" ; usage ; exit 1 ;; esac PATH=$PATH:/usr/etc # SunOS 4.x needs this to understand type hsfs export PATH echo /etc/mount -v -r -t $type -o nosuid /dev/sr0 /cdrom /etc/mount -v -r -t $type -o nosuid /dev/sr0 /cdrom super-3.30.0/options.c0000444000104100002640000011020410732537455013113 0ustar willspgstatic const char rcsid[] = "$Id: options.c,v 1.131 2007/03/07 15:00:20 will Exp $"; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process a global xxx=yyy option */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "super.h" #include "options.h" /* KEEP SORTED IN INCREASING ORDER! (If you don't, we do sort the list * later, but you may as well do your bit to decrease entropy :-) */ Option opts[] = { { "DIE", LOCAL, option_die }, /* OBSOLETE */ { "addgroups", LIST|GLOBAL|LOCAL, option_groups }, { "arg", GLOBAL|LOCAL, option_arg }, { "argv0", LOCAL, option_argv0 }, { "auth", GLOBAL|LOCAL, option_auth }, { "authprompt", GLOBAL|LOCAL, option_authprompt }, { "authtype", GLOBAL|LOCAL, option_authtype }, { "authuser", GLOBAL|LOCAL, option_authuser }, { "cd", GLOBAL|LOCAL, option_cd }, { "checkvar", LIST|LOCAL, option_checkvar }, { "die", LOCAL, option_die }, { "egid", LOCAL, option_egid }, { "env", LIST|GLOBAL|LOCAL, option_env }, { "euid", LOCAL, option_euid }, { "fd", LIST|LOCAL, option_fd }, { "gethostbyname", GLOBAL, option_gethostbyname }, { "gid", LOCAL, option_gid }, { "group_slash", GLOBAL, option_group_slash }, { "groups", LIST|GLOBAL|LOCAL, option_groups }, { "info", LOCAL, option_info }, { "lang", GLOBAL, option_lang }, { "logfile", GLOBAL, option_logfile }, { "loguid", GLOBAL, option_loguid }, { "mail", GLOBAL|LOCAL, option_mail }, { "mailany", GLOBAL|LOCAL, option_mailany }, { "maxenvlen", GLOBAL|LOCAL, option_maxenvlen }, { "maxlen", GLOBAL|LOCAL, option_maxlen }, { "nargs", GLOBAL|LOCAL, option_nargs }, { "nice", GLOBAL|LOCAL, option_nice }, { "owner", GLOBAL|LOCAL, option_owner }, { "password", GLOBAL|LOCAL, option_password }, { "patterns", GLOBAL, option_patterns }, { "print", LOCAL, option_print }, { "pwprompt", GLOBAL|LOCAL, option_authprompt }, { "relative_path", GLOBAL, option_relative_path }, { "renewtime", GLOBAL, option_renewtime }, { "rlog_host", GLOBAL, option_rlog_host }, { "setenv", GLOBAL|LOCAL, option_setenv }, { "syslog", GLOBAL, option_syslog }, { "syslog_success", GLOBAL, option_syslog_success }, { "syslog_error", GLOBAL, option_syslog_error }, { "timeout", GLOBAL|LOCAL, option_timeout }, { "timestampbyhost", GLOBAL, option_timestampbyhost }, { "timestampuid", GLOBAL, option_timestampuid }, { "u+g", LOCAL, option_u_g }, { "uid", LOCAL, option_uid }, { "umask", GLOBAL|LOCAL, option_umask }, { "", 0, NULL }, }; /* OK, so it's a really stupid hack, but it does let me have all option_xxx() * functions take the same argument lists; those that are LIST types, and * need an extra list argument passed, can pick it up here. */ static char **optionlist; void sort_optlist() { /* Sort the options list. This is just an insertion sort, but * it'll work well for almost-sorted data. */ int i, j; int N = NELEM(opts)-1; /* use NELEM-1 because the last element is * the empty end-of-list marker. */ for (i=1; i < N; i++) { for (j=i; j && strcmp(opts[j-1].name, opts[j].name) > 0; j--) { Option o; /* Swap elements; use memcpy in case struct assignment isn't * allowed by this compiler. */ memcpy((void *) &o, (void *) &opts[j-1], sizeof(opts[0])); memcpy((void *) &opts[j-1], (void *) &opts[j], sizeof(opts[0])); memcpy((void *) &opts[j], (void *) &o, sizeof(opts[0])); } } } /* binary search in options list for option word. */ Option * find_option(word) char *word; { int i, wordlen, namelen; static int firsttime=1; Option *lower = &opts[0]; Option *upper = &opts[NELEM(opts)-1]; /* 1 past last non-empty elt */ Option *mid; char *sep; if (firsttime) { sort_optlist(); firsttime=0; } if ((strncmp(word, "arg", 3) == 0) && strchr("0123456789", word[3])) { /* The argMMM[-NNN] option has to be treated as if it were "arg". */ word = "arg"; wordlen = 3; } else if (!(sep = strchr(word, OPTION_SEP))) { Error(0, 0, "%t\n\tsuper.tab option `%s' is missing separator `%c'\n", word, OPTION_SEP); return NULL; } else { /* word length up to the separator */ wordlen = sep - word; } while (lower < upper) { mid = lower + (upper - lower) / 2; namelen = strlen(mid->name); if ((i=strncmp(word, mid->name, namelen)) < 0) { upper = mid; } else if (i > 0) { lower = mid + 1; } else if (wordlen == namelen) { /* exact match */ return mid; } else { /* It didn't compare right. If wordlen < namelen, the strncmp() * above would have failed, hence we know that wordlen > namelen, * hence hence word > mid... */ lower = mid + 1; } } return NULL; } int handle_option(word, value, isglobal) char *word; /* The input xxxyyy string; NULL means clear settings */ char *value; /* pts to yyy in word; can be NULL if wd is NULL */ int isglobal; /* bool: are we processing a global or local entry? */ { Option *opt; /* We only want to print debug info at just the right points, else we * get too much junk output. So define a macro to print our stuff, then * invoke it as necessary. Result: messier programming but better output. */ #define DoDebug() \ { if (debug>1) fprintf(stderr, \ "\thandle_option(): word=<%s> value=<%s>; is %s\n", \ word, value, isglobal ? "global" : "local"); } if (!word) return option_clear_settings(word, NULL, isglobal); if (*word == '!') { DoDebug(); return Error(0, 0, "%t\n\tsuper.tab syntax error: \n\ options cannot be negated: <%s>\n", word); } opt = find_option(word); if (opt) { if (isglobal && !(opt->flags & GLOBAL)) { DoDebug(); return Error(0, 0, "%t\n\t`%s' may not be used as a global option\n", word); } if (!isglobal && !(opt->flags & LOCAL)) { DoDebug(); return Error(0, 0, "%t\n\t`%s' may not be used as a local option\n", word); } if (opt->flags & LIST) { /* Brace-expand arg list and pass */ char **globlist; int i; if (balancedbraces(value) != 0) { return Error(0, 0, "%tUnbalanced braces in `%s'.\n", value); } if ((i=globbraces(value, 1, &globlist)) != 0) { /* Option argument */ DoDebug(); return Error(0, 0, "%tMissing `%c'.\n", i); } optionlist = globlist; } return opt->process(word, value, isglobal); } else { DoDebug(); if (value-word == 5 && strncmp(word, "time", 4) == 0) { return Error(0, 0, "%t\n\tUnrecognized %s option `%s'.\n\ \tPerhaps you meant to use the condition `time~%s'?\n", isglobal ? "global" : "local", word, value); } else { return Error(0, 0, "%t\n\tInvalid %s option `%s'.\n", isglobal ? "global" : "local", word); } } /* NOTREACHED */ return 0; /* Unreachable statement. Including this shuts up a warning * from some compilers, but generates a warning from others. */ #undef DoDebug } int option_clear_settings(word, s, isglobal) char *word; char *s; int isglobal; { if (isglobal) return option_global_reset_settings(); else return option_local_clear_settings(); /* NOTREACHED */ } int option_global_reset_settings() { /* reset global user/group/host patterns pointers, so that more names * form a new list, and are not appended to the old one. * Similarly for time~pattern pointers. * *** Note that we don't free any pattern space! * *** We assume that there is plenty of memory in the computer * *** to slurp up all _global_ patterns. */ if (debug>1) fprintf(stderr, "\toption_global_reset_settings()\n"); globalinfo.user_clear = 1; globalinfo.time_clear = 1; return 0; } int option_local_clear_settings() { /* Clear local settings */ int i; int maxfd = MAXFD; if (debug>1) fprintf(stderr, "\toption_local_clear_settings()\n"); maxfd = MAXFD; if (localinfo.info) free(localinfo.info); localinfo.info = NULL; if (localinfo.die) free(localinfo.die); localinfo.die = NULL; if (localinfo.print) free(localinfo.print); localinfo.print = NULL; if (localinfo.chdir_path) free(localinfo.chdir_path); localinfo.chdir_path = NULL; if (localinfo.argv0) free(localinfo.argv0); localinfo.argv0 = NULL; *localinfo.euser = *localinfo.user = '\0'; *localinfo.egroup = *localinfo.group = '\0'; *localinfo.u_g = '\0'; if (localinfo.env) blkfree(localinfo.env); if (globalinfo.env) { if (!(localinfo.env = blkdup(globalinfo.env))) (void) Error(0, 2, "failed to alloc space for envvar list.\n"); } else { localinfo.env = NULL; } localinfo.setenv[0] = NULL; for (i=0; i<=MAXSETENV; i++) { if (localinfo.setenv[i]) free(localinfo.setenv[i]); localinfo.setenv[i]=NULL; } localinfo.maxlen1arg = globalinfo.maxlen1arg; localinfo.maxlenargs = globalinfo.maxlenargs; strcpy(localinfo.owner, globalinfo.owner); if (localinfo.fdlist) free(localinfo.fdlist); localinfo.fdlist = NULL; if (!localinfo.fd) { localinfo.fd = (int *) malloc(sizeof(int) * (maxfd + 1)); if (!localinfo.fd) return Error(1, 0, "%t\n\tFailed to malloc space for file descriptor list: "); } for (i=0; i<=maxfd; i++) { localinfo.fd[i] = 0; } localinfo.mailcmd[0] = '\0'; localinfo.mail_success = -1; /* Don't let local groups default to global groups, because then we * can't tell if local groups were assigned, and we want to set priority * to be (1) local groups=xxx; (2) local u+g=xxx; (3) global groups=xxx. */ localinfo.ngroups = GROUPS_NOTSET; localinfo.groups_added = 0; error_command = globalinfo.mailcmd[0] ? globalinfo.mailcmd : NULL; init_umask(0); localinfo.file_uid = UID_NOTSET; localinfo.file_gid = GID_NOTSET; localinfo.nice_incr = globalinfo.nice_incr; free_TimeList(&localinfo.time); free_Simple2List(&localinfo.userpats); free_SimpleList(&localinfo.origtext); localinfo.usr_args[0] = globalinfo.usr_args[0]; localinfo.usr_args[1] = globalinfo.usr_args[1]; /* special case: don't initialize localinfo argpats to be * a copy of globalinfo argpats. That's because the * argpats accumulate, and we mustn't accumulate a pile * of local options on top of a copy of the global ones. * When we need to use them, we'll copy from global value * if the local value is still a null ptr. */ ARfree(localinfo.argpats.next); localinfo.argpats.next = NULL; if (localinfo.checkvar) blkfree(localinfo.checkvar); localinfo.checkvar = NULL; /* should use struct assignment, but that's not portable to * all k&r compilers. */ localinfo.authinfo.required = globalinfo.authinfo.required; localinfo.authinfo.method = globalinfo.authinfo.method; localinfo.authinfo.timeout = globalinfo.authinfo.timeout; localinfo.authinfo.renewtime = globalinfo.authinfo.renewtime; localinfo.authinfo.perhost = globalinfo.authinfo.perhost; if (localinfo.authinfo.prompt) free(localinfo.authinfo.prompt); localinfo.authinfo.prompt = globalinfo.authinfo.prompt; strcpy(localinfo.authinfo.user, globalinfo.authinfo.user); strcpy(localinfo.authinfo.ts_user, globalinfo.authinfo.ts_user); return 0; } /***************************************************************************/ /* */ /***************************************************************************/ static int option_auth(word, s, isglobal) char *word; char *s; int isglobal; { int required; if (debug) fprintf(stderr, "\toption:auth=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "y") == 0) { required = 1; } else if (strcmp(s, "n") == 0) { required = 0; } else { return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } if (required && using_user_supertab) { return Error(0, 0, "%t\n\tUser-supplied .supertab files may not do \ authentication checking -- sorry.\n"); } if (isglobal) globalinfo.authinfo.required = required; else localinfo.authinfo.required = required; return 0; } static int option_authprompt(word, s, isglobal) char *word; char *s; int isglobal; { char *str; if (debug) fprintf(stderr, "\toption:authprompt=%s (%s)\n", s, isglobal ? "global" : "local"); if (using_user_supertab) { return Error(0, 0, "%t\n\tUser-supplied .supertab files may not do \ password checking -- sorry.\n"); } str = strdup(s); if (!str) return Error(0, 0, "%t\n\tfailed to malloc space for authprompt=<%s>\n", s); if (isglobal) globalinfo.authinfo.prompt = str; else localinfo.authinfo.prompt = str; return 0; } static int option_authtype(word, s, isglobal) char *word; char *s; int isglobal; { int method; if (debug) fprintf(stderr, "\toption:authtype=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "pam") == 0) { method = SUPER_AUTH_PAM; } else if (strcmp(s, "password") == 0) { method = SUPER_AUTH_PASSWORD; } else { return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `pam' or `password'\n", word); } if (isglobal) globalinfo.authinfo.method = method; else localinfo.authinfo.method = method; return 0; } static int option_authuser(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:authuser=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if debugging or just checking syntax! */ if (check_syntax || it_came_from_cmdline) { Error(0, 0, "%t\n\tIgnoring authuser option, due to debug mode\n"); return 0; } if (isglobal) strcpy(globalinfo.authinfo.user, s); else strcpy(localinfo.authinfo.user, s); return 0; } /***************************************************************************/ /* */ /***************************************************************************/ static int option_arg(word, pat, isglobal) char *word; char *pat; int isglobal; { /* Must be argMMM-NNNSSS or argNNNSSS */ int i, iarg1, iarg2; char eq; ArgRangePat *argpats; if (debug) fprintf(stderr, "\toption:looks like argMMM-NNN=%s (%s)...\n", pat, isglobal ? "global" : "local"); if (isglobal) { argpats = &globalinfo.argpats; } else { argpats = &localinfo.argpats; } /* Check that word matches argNNN=SSS */ i = sscanf(word, "arg%d-%d%c", &iarg1, &iarg2, &eq); if (i != 3 || eq != OPTION_SEP) { i = sscanf(word, "arg%d%c", &iarg1, &eq); if (i == 2) i = 3; iarg2 = iarg1; } if (debug) fprintf(stderr, "\toption:is arg%d-%d=%s (%s)\n", iarg1, iarg2, pat, isglobal ? "global" : "local"); if (i != 3 || eq != OPTION_SEP || iarg1 <= 0 || iarg2 < iarg1) return Error(0, 0, "%t\n\tImproper use of argNNN%cXXX option\n", OPTION_SEP); /* Put pattern into the argpat list. */ { char buf[500]; if (strlen(pat) > sizeof(buf)-3) return Error(0, 0, "%t\n\tArgument pattern <%s> too long (max %d)\n", pat, sizeof(buf)-3); anchor(pat, buf); if (ARinsert(argpats, iarg1, iarg2, buf) == -1) { return Error(0, 0, "Failed to malloc space for argument pattern <%s>\n", buf); } } return 0; } static int option_argv0(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:argv0=%s (%s)\n", s, isglobal ? "global" : "local"); localinfo.argv0 = strdup(s); if (!localinfo.argv0) return Error(0, 0, "Failed to malloc space for argv0=<%s>\n", s); return 0; } static int option_cd(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:cd=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) { globalinfo.chdir_path = strdup(s); if (!globalinfo.chdir_path) return Error(0, 0, "Failed to malloc space for cd=<%s>\n", s); } else { localinfo.chdir_path = strdup(s); if (!localinfo.chdir_path) return Error(0, 0, "Failed to malloc space for cd=<%s>\n", s); } return 0; } static int option_checkvar(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:checkvar=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) { return Error(0, 0, "internal error -- option_checkvar called as global!\n"); } else { localinfo.checkvar = optionlist; } return 0; } static int option_die(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:die=%s (%s)\n", s, isglobal ? "global" : "local"); localinfo.die = strdup(s); if (!localinfo.die) return Error(0, 0, "%t\n\tfailed to malloc space for die=<%s>\n", s); return 0; } static int option_egid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:egid=%s (%s)\n", s, isglobal ? "global" : "local"); stringcopy(localinfo.egroup, s, sizeof(localinfo.egroup)); return 0; } static int option_euid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:euid=%s (%s)\n", s, isglobal ? "global" : "local"); stringcopy(localinfo.euser, s, sizeof(localinfo.euser)); return 0; } static int option_env(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:env=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) { globalinfo.env = optionlist; } else { localinfo.env = optionlist; } return 0; } static int option_maxenvlen(word, s, isglobal) char *word; char *s; int isglobal; { int i, m; if (debug) fprintf(stderr, "\toption:env=%s (%s)\n", s, isglobal ? "global" : "local"); i = sscanf(s, "%d", &m); if (i != 1) { return Error(0, 0, "%t\n\tmaxenvlen must be maxenvlen=nnn.\n", word); } if (isglobal) { globalinfo.maxenvlen = m; } else { localinfo.maxenvlen = m; } return 0; } static int option_fd(word, s, isglobal) char *word; char *s; int isglobal; { int n; int iwd; char *p, *wd; int maxfd = MAXFD; if (debug) fprintf(stderr, "\toption:fd=%s (%s)\n", s, isglobal ? "global" : "local"); localinfo.fdlist = strdup(s); if (!localinfo.fdlist) return Error(0, 0, "Failed to malloc space for copy of fd=<%s>\n", s); for (iwd=0; (wd=optionlist[iwd]); iwd++) { if (((n=strtol(wd, &p, 0)) >= 0) && n <= maxfd && p != wd) localinfo.fd[n] = 1; else return Error(0, 0, "%t\n\tRidiculous value in file descriptor list: `%s'\n", word); } blkfree(optionlist); return 0; } static int option_gid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:gid=%s (%s)\n", s, isglobal ? "global" : "local"); stringcopy(localinfo.group, s, sizeof(localinfo.group)); return 0; } static int option_group_slash(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:group_slash=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "n") == 0) { globalinfo.group_slash = 0; } else { globalinfo.group_slash = 1; if (strcmp(s, "y") != 0) return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } return 0; } #ifndef HAVE_GETGROUPS static int option_groups(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:%s=%s (%s)\n", word, s, isglobal ? "global" : "local"); return Error(0, 0, "Option %s= not supported on this machine\n", word); } #else static int option_groups(word, s, isglobal) char *word; char *s; int isglobal; { int i, is_addgroups, *ngroups_p; int iwd; char *wd; GETGROUPS_T *group_p; if (debug) fprintf(stderr, "\toption:%s=%s (%s)\n", word, s, isglobal ? "global" : "local"); if (strcmp(word, "groups") == 0) { is_addgroups = 0; } else if (strcmp(word, "addgroups") != 0) { is_addgroups = 1; } else { return Error(0, 0, "%tInternal error:\n\ \tDon't know what to do when option isn't groups or addgroups!\n"); } if (isglobal) { group_p = globalinfo.groups; ngroups_p = &globalinfo.ngroups; globalinfo.groups_added = is_addgroups; } else { group_p = localinfo.groups; ngroups_p = &localinfo.ngroups; localinfo.groups_added = is_addgroups; } if (*ngroups_p != GROUPS_NOTSET) return Error(0, 0, "%t\n\t\tCan't have multiple addgroups=xxx and/or \ groups=xxx options in one entry\n"); for (*ngroups_p = 0, iwd=0; (wd=optionlist[iwd]); iwd++) { i = findgid(1, wd); if (i == -1) { *ngroups_p = 0; return Error(0, 0, "%t\n\tCan't set gid: no such group as `%s' in group file.\n", wd); } else { *group_p++ = (GETGROUPS_T) i; (*ngroups_p)++; } } blkfree(optionlist); return (wd) ? Error(0, 0, "%t\n\ttoo many supplementary \ groups (max=%d) in option %s=...", word) : 0; } #endif static int option_info(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:info=%s (%s)\n", s, isglobal ? "global" : "local"); localinfo.info = strdup(s); if (!localinfo.info) return Error(0, 0, "Failed to malloc space for info=<%s>\n", s); return 0; } static int option_lang(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:lang=%s (%s)\n", s, isglobal ? "global" : "local"); #ifndef HAVE_LOCALE_H return Error(0, 0, "%t\n\tOption `lang' isn't supported on this host, \ because the locale functions aren't available\n"); #endif if (!setlocale(LC_TIME, s)) return Error(0, 0, "%t\n\tCan't set time locale to `%s'. \ No such locale?\n", s); /* Update the list of day names */ readtime_init(); return 0; } static int option_logfile(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:logfile=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if debugging or just checking syntax! */ if (check_syntax || it_came_from_cmdline) { Error(0, 0, "%t\n\tIgnoring logfile option, due to debug mode\n"); return 0; } strcpy(globalinfo.log.filename, s); globalinfo.log.newfile = 1; return 0; } static int option_loguid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:loguid=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if debugging or just checking syntax! */ if (check_syntax || it_came_from_cmdline) { Error(0, 0, "%t\n\tIgnoring loguid option, due to debug mode\n"); return 0; } strcpy(globalinfo.log.user, s); globalinfo.log.newuid = 1; return 0; } static int option_mail(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:mail=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if just checking syntax! */ if (check_syntax) return 0; if (isglobal) { if (strlen(s) > sizeof(globalinfo.mailcmd)-1) return Error(0, 0, "%t\n\tRidiculous length of string: `%s'.\n\ \tMaximum permitted length is %d; the entry used %d\n", word, sizeof(globalinfo.mailcmd)-1, strlen(s)); strcpy(globalinfo.mailcmd, s); error_command = globalinfo.mailcmd; globalinfo.mail_success = 0; } else { if (strlen(s) > sizeof(localinfo.mailcmd)-1) return Error(0, 0, "%t\n\tRidiculous length of string: `%s'.\n\ \tMaximum permitted length is %d; the entry used %d\n", word, sizeof(localinfo.mailcmd)-1, strlen(s)); strcpy(localinfo.mailcmd, s); error_command = localinfo.mailcmd; localinfo.mail_success = 0; } return 0; } static int option_mailany(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:mailany=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if just checking syntax! */ if (check_syntax) return 0; if (isglobal) { if (strlen(s) > sizeof(globalinfo.mailcmd)-1) return Error(0, 0, "%t\n\tRidiculous length of string: `%s'.\n\ \tMaximum permitted length is %d; the entry used %d\n", word, sizeof(globalinfo.mailcmd)-1, strlen(s)); strcpy(globalinfo.mailcmd, s); error_command = globalinfo.mailcmd; globalinfo.mail_success = 1; } else { if (strlen(s) > sizeof(localinfo.mailcmd)-1) return Error(0, 0, "%t\n\tRidiculous length of string: `%s'.\n\ \tMaximum permitted length is %d; the entry used %d\n", word, sizeof(localinfo.mailcmd)-1, strlen(s)); strcpy(localinfo.mailcmd, s); error_command = localinfo.mailcmd; localinfo.mail_success = 1; } return 0; } static int option_nargs(word, s, isglobal) char *word; char *s; int isglobal; { int i, m, n; int *nargsp; if (debug) fprintf(stderr, "\toption:nargs=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) { nargsp = globalinfo.usr_args; } else { nargsp = localinfo.usr_args; } i = sscanf(s, "%u-%u", &m, &n); switch(i) { case 1: nargsp[0] = nargsp[1] = m; break; case 2: nargsp[0] = m; nargsp[1] = n; break; default: return Error(0, 0, "%t\n\tnargs must be nargs=nnn or nargs=mmm-nnn.\n", word); } return 0; } static int option_maxlen(word, s, isglobal) char *word; char *s; int isglobal; { int i; long m, n; if (debug) fprintf(stderr, "\toption:maxlen=%s (%s)\n", s, isglobal ? "global" : "local"); i = sscanf(s, "%ld,%ld", &m, &n); switch(i) { case 1: n = m; break; case 2: break; default: return Error(0, 0, "%t\n\tmaxlen must be maxlen=nnn or maxlen=mmm,nnn.\n", word); } if (isglobal) { globalinfo.maxlen1arg = m; globalinfo.maxlenargs = n; } else { localinfo.maxlen1arg = m; localinfo.maxlenargs = n; } return 0; } static int option_nice(word, s, isglobal) char *word; char *s; int isglobal; { int nice_incr; char *p; if (debug) fprintf(stderr, "\toption:nice=%s (%s)\n", s, isglobal ? "global" : "local"); nice_incr = strtol(s, &p, 0); if (p == word) return Error(0, 0, "%t\n\tillegal value in `nice=%s'\n", word); store_nice_incr(nice_incr, isglobal); return 0; } static int option_owner(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:owner=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) stringcopy(globalinfo.owner, s, sizeof(globalinfo.owner)); else stringcopy(localinfo.owner, s, sizeof(localinfo.owner)); return 0; } static int option_password(word, s, isglobal) char *word; char *s; int isglobal; { int required; if (debug) fprintf(stderr, "\toption:password=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "n") == 0) { required = 0; } else { required = 1; if (strcmp(s, "y") != 0) return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } if (required && using_user_supertab) { return Error(0, 0, "%t\n\tUser-supplied .supertab files may not do \ password checking -- sorry.\n"); } if (isglobal) { globalinfo.authinfo.required = required; if (required) globalinfo.authinfo.method = SUPER_AUTH_PASSWORD; } else { localinfo.authinfo.required = required; if (required) localinfo.authinfo.method = SUPER_AUTH_PASSWORD; } return 0; } static int option_patterns(word, pat_name, isglobal) char *word; char *pat_name; int isglobal; { char *p; if (debug) fprintf(stderr, "\toption:patterns=%s (%s)\n", pat_name, isglobal ? "global" : "local"); if (strcmp(pat_name, "shell") == 0) { pat_compile = shell_compile; pat_compare = shell_compare; need_re_anchor = 0; } else if (strcmp(pat_name, "regex") == 0) { pat_compile = s_re_comp; pat_compare = s_re_exec; need_re_anchor = 1; #ifdef HAVE_POSIX_REGEX } else if (strncmp(pat_name, "posix", 5) == 0 && (pat_name[5] == '/' || strlen(pat_name) == 5)) { char *buf = strdup(pat_name); if (!buf) { return Error(0, 0, "%t\n\tCan't malloc space for copy of <%s>\n", pat_name); } /* Check the options: we allow: * posix[/extended][/icase] */ p = strtok(buf, "/"); if (strcmp(p, "posix") != 0) { return Error(0, 0, "%t\n\tInternal error: got pat type <%s> when altready checked it's simply `posix'!\n", p); } for (p=strtok(NULL, "/"); p; p=strtok(NULL, "/")) { if (strcmp(p, "extended") == 0) { p_regcomp_flags(REG_EXTENDED); } else if (strcmp(p, "icase") == 0) { p_regcomp_flags(REG_ICASE); } else { return Error(0, 0, "%t\n\tUnknown posix pattern variant `%s'.\n", p); } } free(buf); pat_compile = p_compile; pat_compare = p_compare; need_re_anchor = 1; #endif } else { #ifdef HAVE_POSIX_REGEX return Error(0, 0, "%t\n\tInvalid pattern type `%s'. \ Valid: \"shell\", \"regex\", and \"posix[/extended][/icase]\"\n", pat_name); #else return Error(0, 0, "%t\n\tInvalid pattern type `%s'. \ Valid: \"shell\" and \"regex\"\n", pat_name); #endif } add_variable("PATTERNS", pat_name); return 0; } static int option_print(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:print=%s (%s)\n", s, isglobal ? "global" : "local"); localinfo.print = strdup(s); if (!localinfo.print) return Error(0, 0, "%t\n\tfailed to malloc space for print=<%s>\n", s); return 0; } static int option_relative_path(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:relative_path=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "n") == 0) { globalinfo.relative_path = 0; } else { globalinfo.relative_path = 1; if (strcmp(s, "y") != 0) return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } return 0; } static int option_renewtime(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:renewtime=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "y") == 0) { globalinfo.authinfo.renewtime = 1; } else { globalinfo.authinfo.renewtime = 0; if (strcmp(s, "n") != 0) return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } return 0; } static int option_rlog_host(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:rlog_host=%s (%s)\n", s, isglobal ? "global" : "local"); #ifndef USE_RSYSLOG return Error(0, 0, "%t\n\tOption rlog_host is not allowed, because \ this copy of super was compiled with rsyslog disabled.\n"); #endif if (*s == '\0') return Error(0, 0, "%t\n\tInvalid option value in `%s' \ -- empty value not allowed.\n", word); error_rlog_host = strdup(s); return 0; } static int option_setenv(word, s, isglobal) char *word; char *s; int isglobal; { char **p; int i; if (debug) fprintf(stderr, "\toption:setenv=%s (%s)\n", s, isglobal ? "global" : "local"); /* s must have form v=xxx, where v is any string not including `='. */ if (*s == '=' || !strchr(s+1, '=')) return Error(0, 0, "%t\n\tbad syntax for setenv%cvar=xxx; you used `setenv%c%s'.\n", OPTION_SEP, OPTION_SEP, s); /* Append this variable: first skip past already-set variables... */ if (isglobal) { for (i=0, p=globalinfo.setenv; p[i] && i < MAXSETENV; i++) ; /* ...then add this definition */ if (i == MAXSETENV) { return Error(0, 0, "%t\n\ttoo many global setenv%cvar=xxx entries; max is %d.\n", OPTION_SEP, MAXSETENV); } else { char *t = strdup(s); if (!t) return Error(0, 0, "Failed to malloc space for setenv using <%s>\n", s); globalinfo.setenv[i++] = t; globalinfo.setenv[i] = NULL; } } else { /* islocal */ for (i=0, p=localinfo.setenv; p[i] && i < MAXSETENV; i++) ; /* ...then add this definition */ if (i == MAXSETENV) { return Error(0, 0, "%t\n\ttoo many local setenv%cvar=xxx entries; max is %d.\n", OPTION_SEP, MAXSETENV); } else { char *t = strdup(s); if (!t) return Error(0, 0, "Failed to malloc space for setenv using <%s>\n", s); localinfo.setenv[i++] = t; localinfo.setenv[i] = NULL; } } return 0; } static int option_syslog(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:syslog=%s (%s)\n", s, isglobal ? "global" : "local"); /* Don't do any logging if just checking syntax! */ if (check_syntax) return 0; if (strcmp(s, "n") == 0) { error_syslog = 0; } else { error_syslog = 1; if (strcmp(s, "y") != 0) return Error(0, 0, "%t\n\tInvalid option value in `%s' \ -- value must be `y' or `n'.\n", word); #ifndef HAVE_SYSLOG return Error(0, 0, "%t\n\tCan't use option syslog -- \ not compiled with HAVE_SYSLOG defined.\n"); #endif } return 0; } static int option_syslog_error(word, s, isglobal) char *word; char *s; int isglobal; { int syslogcode; if (debug) fprintf(stderr, "\toption:syslog_error=%s (%s)\n", s, isglobal ? "global" : "local"); #ifndef HAVE_SYSLOG return Error(0, 0, "%t\n\tCan't use option syslog_error -- \ not compiled with HAVE_SYSLOG defined.\n"); #endif if (read_syslogcode(s, &syslogcode) == -1) return -1; error_priority = syslogcode; if (debug) fprintf(stderr, "\t\t\t=%#x\n", syslogcode); return 0; } static int option_syslog_success(word, s, isglobal) char *word; char *s; int isglobal; { int syslogcode; if (debug) fprintf(stderr, "\toption:syslog_success=%s (%s)\n", s, isglobal ? "global" : "local"); #ifndef HAVE_SYSLOG return Error(0, 0, "%t\n\tCan't use option syslog_success -- \ not compiled with HAVE_SYSLOG defined.\n"); #endif if (read_syslogcode(s, &syslogcode) == -1) return -1; globalinfo.log.syslog_success = syslogcode; if (debug) fprintf(stderr, "\t\t\t=%#x\n", syslogcode); return 0; } static int option_timeout(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:timeout=%s (%s)\n", s, isglobal ? "global" : "local"); if (isglobal) globalinfo.authinfo.timeout = atoi(s); else localinfo.authinfo.timeout = atoi(s); return 0; } static int option_timestampbyhost(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:timestampbyhost=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "n") == 0) { globalinfo.authinfo.perhost = 0; } else if (strcmp(s, "y") == 0) { globalinfo.authinfo.perhost = 1; } else { return Error(0, 0, "%t\n\tInvalid option value in `%s' -- \ value must be `y' or `n'.\n", word); } return 0; } static int option_timestampuid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:timestampuid=%s (%s)\n", s, isglobal ? "global" : "local"); strcpy(globalinfo.authinfo.ts_user, s); return 0; } static int option_u_g(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:u+g=%s (%s)\n", s, isglobal ? "global" : "local"); stringcopy(localinfo.u_g, s, sizeof(localinfo.u_g)); return 0; } static int option_uid(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:uid=%s (%s)\n", s, isglobal ? "global" : "local"); stringcopy(localinfo.user, s, sizeof(localinfo.user)); return 0; } static int option_umask(word, s, isglobal) char *word; char *s; int isglobal; { char *p; int mask; if (debug) fprintf(stderr, "\toption:umask=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "") == 0) { mask = userinfo.orig_mask; } else if (strcmp(s, "") == 0) { return Error(0, 0, "%t\n\tThe value isn't allowed in the umask=xxx option\n", word); } else { mask = strtol(s, &p, 0); if (mask < 0 || p == word) return Error(0, 0, "%t\n\tillegal value in `%s'\n", word); } store_umask(mask, isglobal); return 0; } static int option_gethostbyname(word, s, isglobal) char *word; char *s; int isglobal; { if (debug) fprintf(stderr, "\toption:gethostbyname=%s (%s)\n", s, isglobal ? "global" : "local"); if (strcmp(s, "n") == 0) { globalinfo.gethostbyname = 0; } else { globalinfo.gethostbyname = 1; if (strcmp(s, "y") != 0) return Error(0, 0, "%t\n\tInvalid option value \ in `%s' -- value must be `y' or `n'\n", word); } return 0; } super-3.30.0/approve.c0000444000104100002640000007404710732537455013112 0ustar willspgstatic const char rcsid[] = "$Id: approve.c,v 1.153 2007/12/20 16:26:38 will Exp $"; /* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "super.h" #include "version.h" /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Look up command "usrcmd" in file "superfile". Return path to execute * if approved, empty string if no action should be taken, NULL ptr * if error. As a ``side effect'': Sets the fields in the superinfo struct. * approve() returns: * - NULL ptr if error: * a) username not found; * b) superfile can't be opened for reading; * c) no such command as usrcmd in superfile; * d) user not allowed to execute this command; * e) invalid superfile contents. * - ptr to empty string if all ok, but no program should be executed. * - ptr to path of file to exec, if user allowed to do so. * Any error also generates a message to stderr. * New calls to approve() overwrite the buffer containing the returned path. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char * approve(usrcmd, givehelp, verbosity) char *usrcmd; /* command we're to check on. Should NOT be a * command-line option! Can be a NULL pointer * or empty string, in which case we give help, * print version info, or whatever. */ int givehelp; /* Don't execute command; give help instead. */ int verbosity; /* HELP_BASIC, HELP_FULL, or HELP_FACTS */ { char *buf, *bbuf; char *do_variables(); int indentok; /* Do we (1) give help, or (2) match a command with this user? */ if (givehelp && !check_syntax) printhelp_hello(verbosity, usrcmd); if (givehelp && verbosity == HELP_USAGE) return ""; /* Open the super.tab file we are supposed to process, and then... */ if (!(currfile = file_open(NULL, superfile, 0, NULL, NULL))) { return NULL; } /* ...immediately chain-open the common super file (if it exists), so * that it is always invoked by all commands (super.tab or per-user), * and require it to be root-owned. */ if (!(currfile = file_open(currfile, superfile_init, 1, 0, NULL))) { return NULL; } for (localinfo.progs.commandfound=NULL, currfile->line = 1; (buf=fillbuffer(currfile->fp, &indentok, &currfile->nl)) || ( (check_syntax || indentok) && currfile->prev != NULL); currfile->line += currfile->nl) { if (!buf) { /* Reached EOF on this file -- close it, continue with prev file */ currfile = file_close(currfile); continue; } error_srcfile = currfile->fullname; error_line = currfile->line; error_nl = currfile->nl; if (!indentok) { Error(0, 0, "%t\n\tformat error in super.tab file:\n\ \tContinued line not indented.\n"); if (check_syntax) { continue; } else { return NULL; } } /* Discard empty lines and pure-comment lines */ bbuf = buf + strspn(buf, SEP); /* skip leading whitespace */ if (!*bbuf || *bbuf == '#') continue; if (bbuf != buf) { Error(0, 0, "%t\n\tformat error in super(1) file: \n\ \tNon-comments must begin in column 1.\n"); if (check_syntax) { continue; } else { return NULL; } } /* Clean out embedded comments, whitespace-newline-whitespace. */ buf = clean_buf(buf, NULL); if (!buf) { return NULL; } if (debug) { fprintf(stderr, "==============================================================\n"); fprintf(stderr, "Input text: %s", buf); } /* Do variable expansion */ buf = do_variables(buf); if (!buf) { if (check_syntax) { continue; } else { return NULL; } } /* Initialize localinfo */ if (handle_option(NULL, NULL, 0) == -1) { if (check_syntax) { continue; } else { return NULL; } } if (check_syntax) { if (parseline(0, 1, buf, usrcmd) == -1) { } } else if (givehelp) { switch (parseline(1, 0, buf, usrcmd)) { case -1: return NULL; break; case 0: break; default: printhelp(verbosity); } } else { switch(parseline(0, 0, buf, usrcmd)) { case -1: return NULL; break; case 0: break; default: /* Have an acceptable line, unless die=xxx was used */ return localinfo.progs.cmd_file[localinfo.progs.match].File; } } } file_close(currfile); if (!check_syntax && !indentok) { return NULL; } else if (givehelp || check_syntax) { return ""; } else if (!localinfo.progs.evermatched) { Error(0, 0, "No such super command as `%-.500s'.\n", usrcmd); return NULL; } else { Error(0, 0, "%-.500s - Permission denied to user %s\n", usrcmd, userinfo.caller.pw_name); return NULL; } /* NOTREACHED */ } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Parse one control line (may contain several text lines). * Side effect: prints help information if givehelp is set. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Return -1 if caller should give up parsing the file; * return 0 if caller should loop to next chunk (because we * are doing help processing, because of nomatch, because * of ":"-command, etc.); * return 1 if success. * The cmd/file list and which one matched (if any) are returned * through the localinfo.progs struct. */ int parseline(givehelp, checksyntax, buf, usrcmd) int givehelp; /* request is to give help, not check valid command. */ int checksyntax; /* request is to check syntax of super.tab file, * not check valid command. */ char *buf; /* Input chunk. Gets modified by strqtokS(). */ char *usrcmd; /* Command user wants to execute -- can be * NULL if givehelp_or_checksyntax!=0. */ { char *word1; char *cond_or_opt_wd; char *bbuf; int i, continue_after_if; int condition_match; /* FullPath is twice MAXPATHLEN, because this allows room for * MAXPATHLEN characters of arguments as well as MAXPATHLEN * characters for the filename itself. */ static char FullPath[2*MAXPATHLEN]; localinfo.progs.commandfound = NULL; bbuf = buf; buf += strspn(buf, SEP); /* skip leading whitespace */ if (!*buf || *buf == '#') return 0; /* Discard empty lines and pure-comment lines */ if (bbuf != buf) { return Error(0, 0, "%t\n\tformat error in super(1) file: \n\ \tCommandPatterns must begin in column 1.\n"); } /* Get the list of command/file pairs */ strqS_qm = my_qm; strqS_cc = my_cc; if (localinfo.progs.nalloc == 0) { int nalloc = 10; if ( !(localinfo.progs.cmd_file = (ProgList *) malloc(nalloc * sizeof(ProgList))) ) return Error(1, 0, "%tFailed to malloc space for Cmd+File list\n"); localinfo.progs.nalloc = 10; } localinfo.progs.n = 0; /* Initialize to 0 cmd/file pairs */ /* Start by inspecting the first word. If it begins ":", it is * a special builtin command. Otherwise, if it contains "::", it * must be a command/file pair. Otherwise it's a single command. */ word1 = strqtokS(buf, SEP, NULL, NULL, 1); if (!word1) return Error(0, 0, "%t\n\tformat error in super.tab file: \ CmdPattern or FullPathName missing.\n"); do { continue_after_if = 0; if (*word1 == ':' || strcmp(word1, "/") == 0) { /* It's a special builtin command beginning ":" (or the obsolete * special command name "/".) */ int i; i = process_colon_cmds(word1, &continue_after_if); if (!continue_after_if) { return (i < 0) ? -1 : 0; } else { /* A :if evaluated to true; replace "word1" with the next * word from this line, and process the rest of the line. */ word1 = strqtokS(NULL, SEP, NULL, NULL, 1); if (!word1) return 0; /* no body for conditional */ } } } while (continue_after_if); /* Build lists of cmd::file entries */ if ((i=build_cmd_file(usrcmd, givehelp || checksyntax, word1, &cond_or_opt_wd)) <= 0) { return i; } if (!(givehelp || checksyntax)) { int indx = (localinfo.progs.match >= 0) ? localinfo.progs.match : 0; /* Check if we are supposed to generate a modified FullPath */ char *path = localinfo.progs.cmd_file[indx].File; /* Adjust fullpath as necessary */ if (fixup_fullpath(indx, usrcmd, path, FullPath, sizeof(FullPath)) == -1) { return -1; } } else { /* givehelp or check syntax */ int indx = (localinfo.progs.match >= 0) ? localinfo.progs.match : 0; localinfo.progs.commandfound = localinfo.progs.cmd_file[indx].Cmd; } if (!debug && it_came_from_cmdline) { /* Not debug, but -F / -T / -U / -G / -M flag was given -- so, let's * print a separator line to help out the reader. */ fprintf(stderr, "==============================================================\n"); } if (!givehelp && (debug || it_came_from_cmdline)) { fprintf(stderr, "\tCommandfound = `%s' path = `%s'\n", localinfo.progs.commandfound, localinfo.progs.match >= 0 ? localinfo.progs.cmd_file[localinfo.progs.match].File : "-"); } /* Now process command-line conditions and options */ if ((condition_match=conditions_and_options(cond_or_opt_wd)) == -1) { return condition_match; } if (condition_match && localinfo.die) { if (checksyntax || givehelp) { return 0; } else { extern char *error_prog; char *save_prog = error_prog; error_prog = NULL; Error(0, 0, "%s\n", strdup(do_variables(localinfo.die))); error_prog = save_prog; return -1; } } return condition_match; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Builds list of cmd::file pairs for a control line. * Return -1 if caller should give up parsing the file; * return 0 if caller should loop to next chunk (because we * are doing help processing, because of nomatch, etc. * return 1 if success. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int build_cmd_file(usrcmd, givehelp_or_checksyntax, word1, cond_or_opt_wd) char *usrcmd; /* User's typed command */ int givehelp_or_checksyntax; /* Just giving help or checking syntax * of super.tab file? */ char *word1; /* First wd to process; get rest w/ strqtokS */ char **cond_or_opt_wd; { /* Expect to see either * cmd::file ... * or * cmd file */ char *s, *coloncolon, *pair; extern char *taglines(); if ((s = strchr(word1, ':')) && *(s+1) == ':') { /* It's a Cmd::Filename pair. Go through the list of * command/filenames, until they are all used up, and record * the matching filename. */ pair = word1; localinfo.progs.match = -1; /* initialize to no match */ do { s = strchr(pair, ':'); coloncolon = (s && *(s+1) == ':') ? s : NULL; if (!coloncolon) { /* Reached end of cmd::file list. */ *cond_or_opt_wd = pair; break; } if (debug) fprintf(stderr, "\tCommand::file = `%s'\n", pair); if (coloncolon == pair) return Error(0, 0, "%t\n\tFormat error in super.tab file:\n\ \tCmd::File used, but the Cmd part is missing.\n"); *coloncolon = '\0'; localinfo.progs.n++; /* Have a new cmd/file pair */ if (localinfo.progs.n == localinfo.progs.nalloc) { localinfo.progs.nalloc *= 2; localinfo.progs.cmd_file = (ProgList *) realloc(localinfo.progs.cmd_file, localinfo.progs.nalloc * sizeof(ProgList)); if (!localinfo.progs.cmd_file) return Error(1, 0, "%tFailed to malloc space for Cmd+File list\n"); } localinfo.progs.cmd_file[localinfo.progs.n - 1].Cmd = pair; localinfo.progs.cmd_file[localinfo.progs.n - 1].File = coloncolon + 2; if ((givehelp_or_checksyntax && !usrcmd) || match_pattern(0, 2, usrcmd, pair) == 1) { /* Matched the command */ localinfo.progs.match = localinfo.progs.n - 1; localinfo.progs.evermatched = 1; if (localinfo.progs.cmd_file[localinfo.progs.match].File[0] == '\0') return Error(0, 0, "%t\n\tFormat error in super.tab file:\n\ \tCmd::File used, but the File part is missing.\n"); if (globalinfo.relative_path == 0 && localinfo.progs.cmd_file[localinfo.progs.match].File[0] != '/') return Error(0, 0, "%t\n\tFormat error in super.tab file:\n\ \tfilename `%s' is not an absolute path.\n\ \tUse global option relative_path=y if you really want such foolishness!\n", localinfo.progs.cmd_file[localinfo.progs.match].File); } } while ( (pair = strqtokS(NULL, SEP, NULL, NULL, 1)) ); if (!pair) *cond_or_opt_wd = NULL; if (!(givehelp_or_checksyntax && !usrcmd) && localinfo.progs.match == -1) return 0; /* no match */ } else if (s && *s == ':') { /* Embedded `:' in command name! */ return Error(0, 0, "%t\n\tFormat error in super.tab file: \ The CmdPattern (%s) may not contain an embedded colon\n", word1); } else { /* It was a plain command name. Get the full path. */ localinfo.progs.n = 1; localinfo.progs.match = -1; /* initialize to no match */ localinfo.progs.cmd_file[0].Cmd = word1; localinfo.progs.cmd_file[0].File = strqtokS(NULL, SEP, NULL, NULL, 1); if (localinfo.progs.cmd_file[0].File == NULL || localinfo.progs.cmd_file[0].File[0] == '\0') return Error(0, 0, "%t\n\tformat error in super.tab file: \ CmdPattern or FullPathName missing.\n"); if (globalinfo.relative_path == 0 && localinfo.progs.cmd_file[0].File[0] != '/') return Error(0, 0, "%t\n\tFormat error in super.tab file: \ filename `%s' is not an absolute path.\n\ \tUse global option relative_path=y if you really want such foolishness!\n", localinfo.progs.cmd_file[0].File); if (debug) fprintf(stderr, "\tCmdPattern = `%s' %s\n", localinfo.progs.cmd_file[0].Cmd, taglines(1)); if ((givehelp_or_checksyntax && !usrcmd) || match_pattern(0, 2, usrcmd, localinfo.progs.cmd_file[0].Cmd) == 1) { localinfo.progs.match = 0; /* success */ localinfo.progs.evermatched = 1; } if (!(givehelp_or_checksyntax && !usrcmd) && localinfo.progs.match == -1) return 0; /* Skip non-matching commands */ /* The next word has to be ready in advance of the next loop: */ *cond_or_opt_wd = strqtokS(NULL, SEP, NULL, NULL, 1); } return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Take user's command, and the path from the control line, and generate * the full path that should be executed. * Returns -1 on error, indicating file should be parsed no further. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int fixup_fullpath(indx, usrcmd, path, FullPath, l_FullPath) int indx; /* Index into cmd_file array whence comes the path */ char *usrcmd; /* User's entered command */ char *path; /* Matched path from control line */ char *FullPath; /* output: the generated full path */ int l_FullPath; /* length of the FullPath buffer */ { register char *p, *q; int lpath, n; /* Watch out for sneaky users */ if (strcspn(usrcmd, SEP) != strlen(usrcmd) || strchr(usrcmd, '\\')) return Error(0, 0, "You entered `%s',\nbut you may NOT include whitespace or \ backslashes in the cmd!\n", usrcmd); /* Determine the length of the filename part of the path -- remember * that it may contain whitespace-separated arguments following the * filename. */ lpath = strcspn(path, SEP); p = strchr(path, '*'); /* Check for asterisk in filename part */ n = p ? p - path : 0; /* number of characters before asterisk */ if (p && n < lpath) { /* Wildcard command -- replace asterisk with the usrcmd */ if ((strlen(path) + strlen(usrcmd)) > l_FullPath) return Error(0, 0, "%t\n\tRidiculously long path would be formed from Cmd \ and FullPathName:\n<%s> + <%s>", path, usrcmd); if ((q=strchr(p+1, '*')) && q < (path + lpath)) return Error(0, 0, "%t\n\tFullPathName can only have 1 asterisk, \ but the superfile entry\nreads `%s'\n", path); if (n > 0) strncpy(FullPath, path, n); strcpy(FullPath + n, usrcmd); strcat(FullPath, p+1); localinfo.progs.commandfound = usrcmd; localinfo.progs.cmd_file[indx].File = FullPath; } else { /* Regular command */ localinfo.progs.commandfound = usrcmd; } return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Process command-line conditions and options. * Returns -1 on syntax and other errors; * otherwise returns 0 if conditions fail to match; * otherwise conditions match, and returns 1; */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int conditions_and_options(cond_or_opt_wd) char *cond_or_opt_wd; /* First word to process; rest we get with strqtokS */ { int condition_match; int invert; register char *p; strqS_qm = my_qm; strqS_cc = my_cc; if (cond_or_opt_wd) { do { p = cond_or_opt_wd; if (*p == CONDITION_SEP || *p == OPTION_SEP) return Error(0, 0, "%t\n\tBad syntax: <%s>\n", cond_or_opt_wd); for (p++; *p && ((*p != CONDITION_SEP && *p != OPTION_SEP) || (*(p-1) == '\\')); p++) ; if (*p == OPTION_SEP) { /* ************** */ /* It's an option */ /* ************** */ if (handle_option(cond_or_opt_wd, p+1, 0) == -1) return -1; continue; } else if (*p == CONDITION_SEP) { /* **************** */ /* It's a condition */ /* **************** */ if (InsertCondition(cond_or_opt_wd, p+1, 0) == -1) return -1; } else { /* Default is to treat it as user~ pattern. * Insert in user list. */ int i; char *s, **glob; invert = *cond_or_opt_wd == '!'; s = invert ? cond_or_opt_wd+1 : cond_or_opt_wd; /* Do brace globbing */ if (balancedbraces(s) != 0) { return Error(0, 0, "%tUnbalanced braces in `%s'.\n", s); } if ((i=globbraces(s, 1, &glob)) != 0) { return Error(0, 0, "%tMissing `%c'.\n", i); } if (InsertUserList(s, glob, &localinfo.userpats, &localinfo.origtext, invert) == -1) return -1; } } while ( (cond_or_opt_wd = strqtokS(NULL, SEP, NULL, NULL, 1)) ); } condition_match = 1; /* Look at condition lists in reverse order, and stop as soon * as there is a result. */ if (globalinfo.userafter.next || localinfo.userpats.next || globalinfo.userbefore.next) { /* We have user fields to match */ matches.user = -1; /* no yes/no has yet been made for this user */ /* Start with the global pats that get put after the per-line pats */ match_ugh_user(&globalinfo.userafter, 1); if (matches.user == -1) { /* no yes or no yet for this user; try the per-line pats */ match_ugh_user(&localinfo.userpats, 0); if (matches.user == -1) { /* no yes or no yet; try the global before-line pats */ match_ugh_user(&globalinfo.userbefore, 1); } } if (matches.user == -1) { /* No yes or no for this user; use a default. * Default for root is to allow; * default for all others is disallow */ matches.user = (userinfo.caller.pw_uid == 0) ? 1 : 0; } } else { return Error(0, 0, "%t\n\tNo user patterns given on control line or in :global line.\n"); } if (!matches.user) condition_match = 0; if (condition_match != 0) { if (globalinfo.timeafter.next || localinfo.time.next || globalinfo.timebefore.next) { /* We have time fields to match */ /* Default depends on whether all time fields are inverted */ matches.time = -1; matches.allinverted = 1; matchtime(&userinfo.ourtime, &globalinfo.timeafter); if (matches.time == -1) { matchtime(&userinfo.ourtime, &localinfo.time); if (matches.time == -1) { matchtime(&userinfo.ourtime, &globalinfo.timebefore); } } if (matches.time == -1) { /* Default is permit execution if all patterns were inverting; * deny execution if there were some non-inverting patterns. */ condition_match = matches.allinverted ? 1 : 0; if (debug || it_came_from_cmdline) { if (matches.allinverted) fputs("\tPermission allowed (default for non-match \ when all times are !time~xxx)\n", stderr); else fputs("\tPermission denied (default for non-match \ when >=1 time is non-negated)\n", stderr); } } else { condition_match = matches.time; } } } return condition_match; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Prints help information title */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void printhelp_hello(verbosity, usrcmd) int verbosity; char *usrcmd; { static char *usage[] = { "", " %s [-r path] command [args...] executes command [args].", "", " %s ........................ basic listing of permitted cmds.", " %s [-H | -f] [-S] [MasqOpts] list ok cmds: -H=verbose,-f=just-facts.", " %s [-H | -f] [-S] [MasqOpts] cmd ...give help only for `cmd'.", " %s -h ..................... print this usage info, then exits.", "", " %s -b ..................... lists builtin variables, then exits.", " %s -c [superfile] ......... just check syntax of the superfile.", " %s -V ..................... print version number, then exits.", " %s [-d | -D] [-S] [MasqOpts] cmd [args] ...debug mode.", "", "Notes on options:", " -d Basic debug: show what would be done, but don't execute anything.", " -D Same as -d, plus tell more about variables, plus other details.", " -f (just the facts, ma'm): lists your cmds as: Cmd FullPath [args]", " Useful for scripts that want a list of what you may execute.", " -r path -- error if command doesn't expand to invoking .", " -S -- force stdin to be used for reading passwords.", " -t -- test mode: do all checks excepting user input; generate normal", " output (no special debug output); do not not execute anything.", " Exit code=0 if ok to execute, else 1." "", "MasqueradeOptions:", " ** No command is ever executed when any MasqueradeOption is used.**", " Additionally, some debugging output is enabled when these are used:", " -F superfile -- names the super file to use.", " -G gid -- act as if the invoking user was group gid.", " -M mach -- act as if the command was executed from host mach.", " -T hh[:mm]/day -- act as if this is execution time.", " -U uid -- act as if the invoking user was user uid.", }; if (verbosity == HELP_FACTS) return; if (verbosity == HELP_USAGE) { int i; for (i = 0; i < NELEM(usage); i++) { fprintf(stderr, usage[i], prog); putc('\n', stderr); } printf("\nSuper.tab file: `%s'\n\n", superfile); return; } if (verbosity == HELP_FULL) { printf("(Use %s -h for general usage information.)\n", prog); } if (verbosity != HELP_BASIC) { printf("Super.tab file: `%s'\n\n", superfile); } if (usrcmd) { if (verbosity == HELP_BASIC) (void) printf("Terse help on command `%s' for user %s:\n\n", usrcmd, userinfo.caller.pw_name); else if (verbosity == HELP_FULL) (void) printf("Long help on command `%s' for user %s:\n\n", usrcmd, userinfo.caller.pw_name); } else { if (verbosity) { (void) printf("===============================================\n"); } (void) printf("Commands available to user %s%s:\n\n", userinfo.caller.pw_name, verbosity ? " (use option `-h' for a general usage listing)" : " (use option `-H' for a long-winded listing)"); if (!verbosity) { (void) printf("Command Name Comments\n"); (void) printf("or Pattern \n"); (void) printf("------------ --------\n"); } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Prints help information for a command. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void printhelp(verbosity) int verbosity; { char **p, *s; int i, j, n; ArgRangePat *arp; if (verbosity == HELP_BASIC) { if (localinfo.progs.n < 1) { ; } else if (localinfo.progs.n == 1) { /* The entry contains a single CmdPattern/FullPath pairs */ /* If the command contains a wildcard, print the full filename, * otherwise just the command name. */ if (strchr(localinfo.progs.cmd_file[0].Cmd, '*')) { printf("%s -> %s:\n", localinfo.progs.cmd_file[0].Cmd, localinfo.progs.cmd_file[0].File); if (localinfo.info) printf("\t\t-- %s\n", localinfo.info); } else { printf("%-15s %s\n", localinfo.progs.cmd_file[0].Cmd, localinfo.info ? localinfo.info : ""); } } else { /* The entry contains multiple CmdPattern/FullPath pairs */ /* If any command contains a wildcard, print the * full filenames, otherwise just the command name. */ int havewildcard=0; for (i=0; havewildcard==0 && i %s;\n", prog, localinfo.progs.cmd_file[i].Cmd, localinfo.progs.cmd_file[i].File); } i = localinfo.progs.n - 1; printf("%s: %s -> %s:\n", prog, localinfo.progs.cmd_file[i].Cmd, localinfo.progs.cmd_file[i].File); if (localinfo.info && *localinfo.info) (void) printf(" -- %s\n", localinfo.info); } else { /* Now wildcards in names */ printf("%s", localinfo.progs.cmd_file[0].Cmd); for (i=1; i %s\n", prog, localinfo.progs.cmd_file[i].Cmd, localinfo.progs.cmd_file[i].File); } else { (void) Error(0, 0, "%s: printhelp(): Unknown verbosity level %d\n", verbosity); return; } /* Assert verbosity == HELP_FULL */ if (localinfo.info) printf("\t## %s\n", localinfo.info); if (localinfo.die) { printf("\tCommand forces exit using 'die' option:\n\t\tdie=\"%s\"", localinfo.die); return; } if (localinfo.print) printf("\tCommand prints msg before execution:\n\t\t\"%s\"", localinfo.print); if (globalinfo.timebefore.next || globalinfo.timeafter.next || localinfo.time.next) { printf("\tPermitted times for execution (in reverse input order):\n"); for (j = 0; j<3; j++) { TimeList *tl; switch (j) { case 0: tl = globalinfo.timebefore.next; break; case 1: tl = localinfo.time.next; break; default: tl = globalinfo.timeafter.next; break; } for ( ; tl; tl=tl->next) { printf("\t\t%stime~%d:%02d-%d:%02d/%s\n", tl->te.invert ? "!" : "", tl->te.begin / 60, tl->te.begin % 60, tl->te.end / 60, tl->te.end % 60, dayname(tl->te.day)); } } } if ( *localinfo.user || *localinfo.euser || *localinfo.group || *localinfo.egroup || *localinfo.u_g || localinfo.fdlist || *localinfo.owner || localinfo.env) { (void) fputs("\tExecutes with:", stdout); if (*localinfo.euser) { (void) printf(" euid=%s", localinfo.euser); if (*localinfo.user) (void) printf(" ruid=%s", localinfo.user); } else if (*localinfo.user) { (void) printf(" uid=%s", localinfo.user); } if (*localinfo.egroup) { (void) printf(" egid=%s", localinfo.egroup); if (*localinfo.group) { (void) printf(" gid=%s", localinfo.group); } } else if (*localinfo.group) { (void) printf(" gid=%s", localinfo.group); } if (*localinfo.u_g) (void) printf(" u+g=%s", localinfo.u_g); if (localinfo.env) { for (p=localinfo.env; *p; p++) (void) printf("%s%s", p==localinfo.env ? " env=" : ",", *p); } if (localinfo.setenv) { for (p=localinfo.setenv; *p; p++) (void) printf(" setenv=%s", *p); } if (localinfo.fdlist) (void) printf(" fdlist=%s", localinfo.fdlist); if (*localinfo.owner) (void) printf(" owner=%s", localinfo.owner); (void) fputs("\n", stdout); } if (localinfo.usr_args[0] < 0) ; else if (localinfo.usr_args[0] == localinfo.usr_args[1] && localinfo.usr_args[0] == 0) (void) printf("\tNo user-entered args are allowed.\n"); else if (localinfo.usr_args[0] == localinfo.usr_args[1]) (void) printf("\t%d user-entered arg%s required.\n", localinfo.usr_args[0], localinfo.usr_args[0] == 1? " is" : "s are"); else (void) printf("\t%d - %d user-entered args are required.\n", localinfo.usr_args[0], localinfo.usr_args[1]); if (localinfo.maxlen1arg < 0) (void) printf("\tNo per-arg length limit; "); else (void) printf("\tMax per-arg length: %ld chars; ",localinfo.maxlen1arg); if (localinfo.maxlenargs < 0) (void) printf("no limit on sum of all args.\n"); else (void) printf("max over all args: %ld chars.\n", localinfo.maxlenargs); arp = (localinfo.argpats.next) ? localinfo.argpats.next : globalinfo.argpats.next; if (arp) { printf("\tUser-entered arguments must match following patterns:\n"); for ( ; arp && arp->pat && arp->pat[0]; arp = arp->next) { if (arp->arg1 == arp->arg2) { fprintf(stderr, "\t\tArg %d must match pattern: %s\n", arp->arg1, arp->pat); } else { fprintf(stderr, "\t\tArgs %d - %d must match pattern: %s\n", arp->arg1, arp->arg2, arp->pat); } } } if (rcl_nice_incr() != 0) printf("\tCommand executes with nice increment = %d.\n", rcl_nice_incr()); if (rcl_umask() != userinfo.orig_mask) printf("\tCommand executes with umask set to 0%o.\n", rcl_umask()); if (localinfo.authinfo.required) { if (localinfo.authinfo.timeout == 0) (void) printf("\t%s authentication is required on each use.\n", auth_name()); else (void) printf( "\t%s authentication is required; good for %d minutes%s.\n", auth_name(), localinfo.authinfo.timeout, localinfo.authinfo.renewtime ? ", extended with each use" : ""); } if (localinfo.checkvar) { (void) printf("\tCaller must enter check-variables:"); for (i=0; localinfo.checkvar[i]; i++) { printf(" %s", localinfo.checkvar[i]); } (void) putchar('\n'); } (void) putchar('\n'); } super-3.30.0/mkdir_p0000555000104100002640000000255010732537455012633 0ustar willspg#! /bin/sh usage() { cat << END A poor man's mkdir -p. Useful on old systems that don't have the -p option. It won't work right if a target directory includes whitespace; tough luck. Options: -h print this info, then exit. -oxxx chown xxx any created directory (put no space between -o and xxx). -gxxx chgrp xxx any created directory (put no space between -g and xxx). -pxxx chperm xxx any created directory (put no space between -p and xxx). END } owner= group= perm= while [ $# -gt 0 ] ; do case "$1" in -h ) usage ; exit 0 ;; -o* ) owner=`expr "$1" : '-o\(.*\)'` ; shift case "$owner" in "" ) usage ; exit 1 ;; esac ;; -g* ) group=`expr "$1" : '-g\(.*\)'` ; shift case "$group" in "" ) usage ; exit 1 ;; esac ;; -p* ) perm=`expr "$1" : '-p\(.*\)'` ; shift case "$perm" in "" ) usage ; exit 1 ;; esac ;; -- ) break ;; -* ) echo "unknown option $1" ; usage ; exit 1 ;; * ) break ;; esac done for longpath in ${1+"$@"} ; do case "$longpath" in /* ) dir="" ;; * ) dir=. ;; esac for d in `echo "$longpath" | sed -e 'sX/X Xg'` ; do dir="$dir/$d" test -d $dir || { mkdir $dir || exit case "$owner" in "" ) ;; * ) chown $owner $dir ;; esac case "$group" in "" ) ;; * ) chgrp $group $dir ;; esac case "$perm" in "" ) ;; * ) chmod $perm $dir ;; esac } done done