/* 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 #define SUPERFILE "/usr/local/lib/super.tab" #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 */ /* 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 )); 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 )); 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* 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 ));