From 464d71c37246e556de9ec05f7b97af834a5224ee Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 6 Sep 1997 18:27:14 +0000 Subject: [PATCH] Up to halfway down rhs p.12, inc builtin services, but not working yet. --- INSTALL | 1 + Makefile.in | 2 +- client.c | 94 ++++++++++++++++++++++---------------- common.h | 7 ++- daemon.h | 26 ++++++++--- debug.c | 115 ++++++++++++++++++++++++++-------------------- language.i4 | 22 ++++++++- lexer.l.m4 | 14 +++++- parser.c | 128 ++++++++++++++++++++++++++++++++++++---------------- process.c | 63 ++++++++++++++++---------- servexec.c | 99 ++++++++++++++++++++++++++++++++++++---- spec.sgml | 67 +++++++++++++++++++++++++-- 12 files changed, 460 insertions(+), 178 deletions(-) diff --git a/INSTALL b/INSTALL index d7211b6..8c5db28 100644 --- a/INSTALL +++ b/INSTALL @@ -32,6 +32,7 @@ C Library: * strtoul; * memcpy, memset, memcpy; * realloc(0,size) must work and be equivalent to malloc(size). +* free(0) must work and do nothing * (not varargs) and v[sf][n]printf. System interfaces: diff --git a/Makefile.in b/Makefile.in index 0df4f95..4ef8e7d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -72,7 +72,7 @@ process.o: config.h common.h pcsum.h daemon.h lib.h tokens.h overlord.o: config.h common.h pcsum.h daemon.h -servexec.o: config.h common.h pcsum.h daemon.h lib.h +servexec.o: config.h common.h pcsum.h daemon.h lib.h version.h lib.o: config.h lib.h diff --git a/client.c b/client.c index bee10a1..7a810b5 100644 --- a/client.c +++ b/client.c @@ -135,15 +135,17 @@ struct fdsetupstate { enum signalsexitspecials { se_number=-100, se_numbernocore, se_highbit, se_stdout }; enum overridetypes { ot_none, ot_string, ot_file }; -static const char *serviceuser=0; +struct constkeyvaluepair { const char *key, *value; }; + +static const char *serviceuser; static uid_t serviceuid, myuid; -static struct fdsetupstate *fdsetup=0; -static int fdsetupsize=0; -static const char *(*defvarsarray)[2]; -static int defvarsavail=0, defvarsused=0; -static unsigned long timeout=0; +static struct fdsetupstate *fdsetup; +static int fdsetupsize, builtin; +static struct constkeyvaluepair *defvararray; +static int defvaravail, defvarused; +static unsigned long timeout; static int signalsexit=254; -static int sigpipeok=0, hidecwd=0; +static int sigpipeok, hidecwd; static int overridetype= ot_none; static const char *overridevalue, *spoofuser=0; @@ -276,6 +278,7 @@ static void xfflush(FILE *file) { static void usage(void) { if (fprintf(stderr, "usage: userv [--] [ ...]\n" + "usage: userv -B|--builtin [--] [ ...]\n" "options: -f|--file []=\n" " -D|--defvar =\n" " -t|--timeout \n" @@ -420,19 +423,21 @@ static void of_fdwait(const struct optioninfo *oip, const char *value, char *key static void of_defvar(const struct optioninfo *oip, const char *value, char *key) { int i; + if (!key[0]) + usageerror("empty string not allowed as variable name"); if (strlen(key)>MAX_GENERAL_STRING) usageerror("variable name `%s' is far too long",key); if (strlen(value)>MAX_GENERAL_STRING) usageerror("variable `%s' has value `%s' which is far too long",key,value); - for (i=0; i= MAX_ARGSDEFVARS) usageerror("far too many --defvar or -D options"); - if (i>=defvarsavail) { - defvarsavail+=10; defvarsavail<<=1; - defvarsarray= xrealloc(defvarsarray,sizeof(const char*)*2*defvarsavail); + for (i=0; i= MAX_ARGSDEFVAR) usageerror("far too many --defvar or -D options"); + if (i>=defvaravail) { + defvaravail+=10; defvaravail<<=1; + defvararray= xrealloc(defvararray,sizeof(struct constkeyvaluepair)*defvaravail); } - if (i==defvarsused) defvarsused++; - defvarsarray[i][0]= key; - defvarsarray[i][1]= value; + if (i==defvarused) defvarused++; + defvararray[i].key= key; + defvararray[i].value= value; } static void of_timeout(const struct optioninfo *oip, const char *value, char *key) { @@ -467,6 +472,10 @@ static void of_hidecwd(const struct optioninfo *oip, const char *value, char *ke hidecwd=1; } +static void of_builtin(const struct optioninfo *oip, const char *value, char *key) { + builtin=1; +} + static void of_help(const struct optioninfo *oip, const char *value, char *key) { usage(); exit(0); @@ -515,6 +524,7 @@ const struct optioninfo optioninfos[]= { { 'S', "signals", 1, of_signals }, { 'P', "sigpipe", 0, of_sigpipe }, { 'H', "hidecwd", 0, of_hidecwd }, + { 'B', "builtin", 0, of_builtin }, { 'h', "help", 0, of_help }, { 0, "copyright", 0, of_copyright }, { 0, "override", 1, of_override }, @@ -676,7 +686,7 @@ int main(int argc, char *const *argv) { char *argp; const struct optioninfo *oip; struct sockaddr_un ssockname; - int sfd, ngids, i, j, tempfd, l, c, reading, fd, r, status, ngidssize; + int sfd, ngids, i, tempfd, l, c, reading, fd, r, status, ngidssize; sigset_t sset; unsigned long ul; size_t cwdbufsize; @@ -715,7 +725,7 @@ int main(int argc, char *const *argv) { of_file(0,"stderr",fd2key); for (argpp= argv+1; - (argp= *argpp) && *argp == '-'; + (argp= *argpp) && *argp == '-' && argp[1]; argpp++) { if (!*++argp) usageerror("unknown option/argument `%s'",*argpp); if (*argp == '-') { /* Two hyphens */ @@ -749,9 +759,15 @@ int main(int argc, char *const *argv) { } } } - if (!*argpp) usageerror("no service user given after options"); - serviceuser= *argpp++; - if (!*argpp) usageerror("no service name given after options and service user"); + if (builtin) { + serviceuser= "-"; + } else { + if (!*argpp) usageerror("no service user given after options"); + serviceuser= *argpp++; + } + if (!*argpp) usageerror(builtin ? + "no service name given after options and service user" : + "no builtin service given after options"); for (fd=0; fd MAX_ARGSDEFVARS) usageerror("far too many arguments"); + if (argc > MAX_ARGSDEFVAR) usageerror("far too many arguments"); if (ngids > MAX_GIDS) miscerror("caller is in far too many gids"); + spoofuid= myuid; + spoofgid= mygid; + logname= getenv("LOGNAME"); + if (!logname) logname= getenv("USER"); + if (logname) { + pw= getpwnam(logname); + if (!pw || pw->pw_uid != myuid) logname= 0; + } + if (!logname) { + pw= getpwuid(myuid); if (!pw) miscerror("cannot determine your login name"); + logname= pw->pw_name; + } + + if (!strcmp(serviceuser,"-")) serviceuser= logname; pw= getpwnam(serviceuser); if (!pw) miscerror("requested service user `%s' is not a user",serviceuser); serviceuid= pw->pw_uid; @@ -799,19 +829,6 @@ int main(int argc, char *const *argv) { } gidarray[ngids++]= gr->gr_gid; } - } else { - spoofuid= myuid; - spoofgid= mygid; - logname= getenv("LOGNAME"); - if (!logname) logname= getenv("USER"); - if (logname) { - pw= getpwnam(logname); - if (!pw || pw->pw_uid != myuid) logname= 0; - } - if (!logname) { - pw= getpwuid(myuid); if (!pw) miscerror("cannot determine your login name"); - logname= pw->pw_name; - } } cwdbufsize= 0; cwdbuf= 0; @@ -931,7 +948,7 @@ int main(int argc, char *const *argv) { else request_mbuf.nreadfds++; } request_mbuf.nargs= argc-1; - request_mbuf.nvars= defvarsused; + request_mbuf.nvars= defvarused; request_mbuf.overridelen= ovused; xfwrite(&request_mbuf,sizeof(request_mbuf),swfile); xfwrite(serviceuser,sizeof(*serviceuser)*request_mbuf.serviceuserlen,swfile); @@ -945,9 +962,10 @@ int main(int argc, char *const *argv) { xfwritefds(fdm_write,request_mbuf.nwritefds,swfile); for (i=1; i #define RESET_CONFIGURATION " \n\ - cd " USERDIRPREFIX " \n\ + cd ~/ \n\ reject \n\ no-set-environment \n\ suppress-args \n\ @@ -64,7 +64,6 @@ #define DEFAULTINCLUDELOOKUP ":default" #define EMPTYINCLUDELOOKUP ":empty" -#define USERDIRPREFIX USERDIR "/" #define USERCONFIGDIRBASE SYSTEMUSERVCONFIGDIR #define USERCONFIGDIR HIDDENPREFIX USERCONFIGDIRBASE #define USERUSERVCONFIGPATH USERDIR "/" USERCONFIGDIR @@ -118,15 +117,25 @@ const char *printtoken(int token); void senderrmsgstderr(const char *errmsg); void disconnect(int exitstatus) NONRETURNING; +void always_dumpparameter(const char *parm, char **values); +void always_dumpexecsettings(void); + void debug_dumprequest(pid_t mypid); void debug_dumpexecsettings(void); void debug_dumpparameter(const char *parm, char **values); pid_t nondebug_fork(void); const char *nondebug_serviceuserdir(const char *ifnondebug); +typedef void builtinserviceexec_fnt(const char *const *args); +builtinserviceexec_fnt NONRETURNING bisexec_environment, bisexec_parameter; +builtinserviceexec_fnt NONRETURNING bisexec_version; +builtinserviceexec_fnt NONRETURNING bisexec_toplevel, bisexec_override, bisexec_reset; +builtinserviceexec_fnt NONRETURNING bisexec_execute; + void execservice(const int synchsocket[], int clientfd) NONRETURNING; void servicerequest(int sfd) NONRETURNING; int synchread(int fd, int ch); +const char *defaultpath(void); struct fdstate { int iswrite, realfd, holdfd; @@ -137,22 +146,25 @@ struct fdstate { /* tokv_word_read, tokv_word_write */ }; -extern char **argarray; -extern char *((*defvararray)[2]); +struct keyvaluepair { char *key, *value; }; + +extern struct request_msg request_mbuf; +extern struct keyvaluepair *defvararray; extern struct fdstate *fdarray; /* indexed by nominal fd */ extern int fdarraysize, fdarrayused; extern int restfdwantstate, restfdwantrw; -extern struct request_msg request_mbuf; +extern int service_ngids; +extern char **argarray; extern char *serviceuser, *service, *logname, *cwd; extern char *overridedata, *userrcfile; extern char *serviceuser_dir, *serviceuser_shell, *callinguser_shell; -extern int service_ngids; extern gid_t *calling_gids, *service_gids; -extern const char **calling_groups, **service_groups; extern uid_t serviceuser_uid; +extern const char **calling_groups, **service_groups; extern char *execpath, **execargs; extern int execute; /* One of the execution modes tokt_execmode */ extern int setenvironment, suppressargs, disconnecthup; +extern builtinserviceexec_fnt *execbuiltin; extern int syslogopenfacility; #endif diff --git a/debug.c b/debug.c index 9174d83..19713af 100644 --- a/debug.c +++ b/debug.c @@ -34,31 +34,6 @@ #include "lib.h" #include "tokens.h" -#ifdef DEBUG - -static const char *sl_ident= "UNSET"; -static int sl_option=0, sl_facility=0; - -void openlog(const char *ident, int option, int facility) { - sl_ident= ident; - sl_option= option; - sl_facility= facility; -} - -void syslog(int priority, const char *fmt, ...) { - va_list al; - fprintf(stderr,"syslog: %s<%d.%d>(%d): ",sl_ident,sl_facility,priority,sl_option); - va_start(al,fmt); - vfprintf(stderr,fmt,al); - va_end(al); - fputc('\n',stderr); -} - -void closelog(void) { - sl_ident= "CLOSED"; - sl_option= sl_facility= 0; -} - static void fdwantdumprwhead(int *donehead, const char *whichstr, const char *rwstr) { if (*donehead) return; printf("fds %s%s%s:",whichstr,rwstr?" ":"",rwstr?rwstr:""); @@ -96,6 +71,69 @@ static void truefalsedump(const char *whichstr, int val) { printf("%s: %s\n",whichstr,val?"yes":"no"); } +void always_dumpparameter(const char *parm, char **values) { + printf("config parameter `%s':",parm); + while (*values) printf(" `%s'",*values++); + printf("\n"); +} + +void always_dumpexecsettings(void) { + char **cpp; + + if (userrcfile) printf("user-rcfile: `%s'\n",userrcfile); + else printf("user-rcfile: \n"); + fdwantdump("required",tokv_word_requirefd,"ERROR"); + fdwantdump("allowed",tokv_word_allowfd,"either"); + fdwantdump("ignored",tokv_word_ignorefd,0); + fdwantdump("null",tokv_word_nullfd,"both"); + fdwantdump("rejected",tokv_word_rejectfd,0); + fputs("execute: ",stdout); + switch (execute) { + case tokv_word_reject: printf("reject"); break; + case tokv_word_execute: printf("`%s'",execpath); break; + case tokv_word_executefromdirectory: printf("from directory, `%s'",execpath); break; + case tokv_word_executefrompath: printf("from path"); break; + case tokv_word_executebuiltin: printf("builtin %s",execpath); break; + default: abort(); + } + if (execargs) { + fputs("\n" "no exec arguments\n",stdout); + } else { + fputs("\n" "exec arguments:",stdout); + for (cpp= execargs; cpp; cpp++) printf(" `%s'",*cpp); + putchar('\n'); + } + truefalsedump("set-environment",setenvironment); + truefalsedump("suppress-args",suppressargs); + truefalsedump("disconnect-hup",disconnecthup); + truefalsedump("set-environment",setenvironment); +} + +#ifdef DEBUG + +static const char *sl_ident= "UNSET"; +static int sl_option=0, sl_facility=0; + +void openlog(const char *ident, int option, int facility) { + sl_ident= ident; + sl_option= option; + sl_facility= facility; +} + +void syslog(int priority, const char *fmt, ...) { + va_list al; + fprintf(stderr,"syslog: %s<%d.%d>(%d): ",sl_ident,sl_facility,priority,sl_option); + va_start(al,fmt); + vfprintf(stderr,fmt,al); + va_end(al); + fputc('\n',stderr); +} + +void closelog(void) { + sl_ident= "CLOSED"; + sl_option= sl_facility= 0; +} + static void groupsdump(int ngids, const gid_t *gids, const char *const *groups) { int i; @@ -136,39 +174,18 @@ void debug_dumprequest(pid_t mypid) { for (i=0; i\n"); - fdwantdump("required",tokv_word_requirefd,"ERROR"); - fdwantdump("allowed",tokv_word_allowfd,"either"); - fdwantdump("ignored",tokv_word_ignorefd,0); - fdwantdump("null",tokv_word_nullfd,"both"); - fdwantdump("rejected",tokv_word_rejectfd,0); - printf("execute: "); - switch (execute) { - case tokv_word_reject: printf("reject"); break; - case tokv_word_execute: printf("`%s'",execpath); break; - case tokv_word_executefromdirectory: printf("from directory, `%s'",execpath); break; - case tokv_word_executefrompath: printf("from path"); break; - default: abort(); - } - printf("\n"); - truefalsedump("set-environment",setenvironment); - truefalsedump("suppress-args",suppressargs); - truefalsedump("disconnect-hup",disconnecthup); - truefalsedump("set-environment",setenvironment); + always_dumpexecsettings(); } void debug_dumpparameter(const char *parm, char **values) { - printf("config parameter `%s':",parm); - while (*values) printf(" `%s'",*values++); - printf("\n"); + always_dumpparameter(parm,values); } static int groupsallin(int na, const gid_t *lista, diff --git a/language.i4 b/language.i4 index 09b4a61..8857c2f 100644 --- a/language.i4 +++ b/language.i4 @@ -66,6 +66,7 @@ autovaldeftype(`readwrite') autovaldeftype(`string') autovaldeftype(`execmode') autovaldeftype(`ehandlemode') +autovaldeftype(`builtinservice') autovaldeftype(`misc') autovaldeftype(`internal') @@ -85,10 +86,12 @@ define(`isflagpair',`isdirectivefn(`$1',`dfg_setflag',`', `lr_flag= &'makename(`$1')`; lr_flagval= 1; ') isdirectivefn(`no-$1',`dfg_setflag',`', `lr_flag= &'makename(`$1')`; lr_flagval= 0; ')') +dnl `reset' is also a builtin service isexecmode(`reject') -isexecmode(`execute') +dnl `execute' is also a builtin service isexecmode(`execute-from-directory') isexecmode(`execute-from-path') +isexecmode(`execute-builtin') isehandlemode(`errors-to-stderr') isehandlemode(`errors-to-syslog') isehandlemode(`errors-to-file') @@ -101,7 +104,6 @@ isflagpair(`set-environment') isflagpair(`suppress-args') isflagpair(`disconnect-hup') isdirective(`cd') -isdirective(`reset') isdirective(`user-rcfile') isdirective(`include') isdirectivefn(`include-ifexist',`df_include') @@ -144,6 +146,22 @@ isparmcondition(`glob') isparmcondition(`range') isparmcondition(`grep') +dnl builtin services +define(`isbuiltinservice',`wordtypelexexec(`$1',`tokt_builtinservice', + `lr_bispa= bispa_'makename(`$2')`; lr_bisexec= bisexec_'makename(`$1')`; ')') +isbuiltinservice(`environment',`none') +isbuiltinservice(`parameter',`parameter') +isbuiltinservice(`version',`none') +isbuiltinservice(`toplevel',`none') +isbuiltinservice(`override',`none') + +dnl builtin services that are also directive names +define(`isdirectivebuiltinservice', + `wordtypelexexec(`$1',`tokt_directive|tokt_builtinservice$3', + `lr_dir= df_'makename(`$1')`; lr_bispa= bispa_'makename(`$2')`; lr_bisexec= bisexec_'makename(`$1')`; ')') +isdirectivebuiltinservice(`reset',`none') +isdirectivebuiltinservice(`execute',`none',`|tokt_execmode') + dnl parameters define(`isparameter',`wordtypelexexec(`$1',`tokt_parameter', `lr_parameter= pf_'makename(`$1')`; ')') diff --git a/lexer.l.m4 b/lexer.l.m4 index 0337686..2f36060 100644 --- a/lexer.l.m4 +++ b/lexer.l.m4 @@ -46,7 +46,7 @@ include(language.i4) typedef int directive_fnt(int dtoken); static directive_fnt df_reject, df_execute, df_executefrompath; -static directive_fnt df_executefromdirectory; +static directive_fnt df_executefromdirectory, df_executebuiltin; static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile; static directive_fnt dfg_fdwant, dfg_setflag; static directive_fnt df_reset, df_cd, df_userrcfile, df_include; @@ -81,11 +81,23 @@ static parameter_fnt pf_callingusershell, pf_serviceusershell; * freeparm can be used to free such an array. */ +typedef int builtinserviceparse_fnt(char ***rnewargs); +static builtinserviceparse_fnt bispa_none, bispa_parameter; +/* These parse the arguments to a builtin service, including the + * newline at the end of the line. *rnewargs will initially be + * null, indicating that no arguments are to be set; the function + * may store a mallocd array of mallocd strings in it, + * containing the arguments it wishes to have set (null-pointer + * terminated). + */ + static int yylex(void); /* Returns a token (which may be an eof or error exception) */ static directive_fnt *lr_dir; static parmcondition_fnt *lr_parmcond; +static builtinserviceparse_fnt *lr_bispa; +static builtinserviceexec_fnt *lr_bisexec; static parameter_fnt *lr_parameter; static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; static int lr_flagval, lr_controlend; diff --git a/parser.c b/parser.c index 0f8e195..4b55743 100644 --- a/parser.c +++ b/parser.c @@ -22,13 +22,6 @@ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -static directive_fnt *lr_dir=0; -static parmcondition_fnt *lr_parmcond=0; -static parameter_fnt *lr_parameter=0; -static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; -static int lr_flagval, lr_controlend; -static int lr_fdwant_readwrite; - static void useless(void) { (void)yyunput; (void)useless; /* to shut up GCC ! */ } static void closeerrorfile(void) { @@ -303,30 +296,39 @@ static int paa_1path(const char **rv) { *rv= string2path(cp); return 0; } -static int pa_parameter(char ***rvalues) { +static int pa_parameter(char ***rvalues, char **rname) { /* Scans a single parameter token and calls the appropriate parameter * function, returning tokv_error or 0 just like the parameter function. + * If rname is non-null then the name of the parameter (malloc'd) will + * be stored in it. */ int token, r, i; + char *name; token= yylex(); if (token == tokv_error) return token; + name= xstrsave(yytext); if ((token & tokm_repres) != tokr_nonstring && !memcmp(yytext,"u-",2) && strlen(yytext)>=3) { for (i=0; - i=request_mbuf.nvars) { *rvalues= xmalloc(sizeof(char*)); **rvalues= 0; } else { - parm_1string(rvalues,defvararray[i][1]); + parm_1string(rvalues,defvararray[i].value); } } else { - if (!(token & tokt_parameter)) return unexpected(token,-1,"parameter name"); + if (!(token & tokt_parameter)) { + free(name); + return unexpected(token,-1,"parameter name"); + } r= (lr_parameter)(token,rvalues); - if (r) return r; + if (r) { free(name); return r; } } - debug_dumpparameter(yytext,*rvalues); + debug_dumpparameter(name,*rvalues); + if (rname) *rname= name; + else free(name); return 0; } @@ -372,7 +374,7 @@ static int pa_condition(int *rtrue) { *rtrue= actrue; return 0; } else if (token & tokt_parmcondition) { r= pa_mwsp(); if (r) return r; - r= pa_parameter(&parmvalues); if (r) return r; + r= pa_parameter(&parmvalues,0); if (r) return r; r= (lr_parmcond)(token,parmvalues,rtrue); freecharparray(parmvalues); return r; } @@ -684,26 +686,6 @@ int pf_serviceusershell(int ptoken, char ***rvalues) { /* Directive functions and associated `common code' functions */ -int df_reject(int dtoken) { - int r; - - r= pa_mnl(); if (r) return r; - execute= tokv_word_reject; - free(execpath); execpath= 0; - freecharparray(execargs); execargs= 0; - return 0; -} - -int df_executefrompath(int dtoken) { - int r; - - r= pa_mnl(); if (r) return r; - execute= tokv_word_executefrompath; - free(execpath); execpath= 0; - freecharparray(execargs); execargs= 0; - return 0; -} - static int paa_pathargs(const char **rv, char ***newargs_r) { /* Repeated calls do _not_ overwrite newargs_r; caller must free. * Repeated calls _do_ overwrite string returned in rv. @@ -742,15 +724,41 @@ error: return r; } +static void execreset(void) { + execute= 0; + execbuiltin= 0; + free(execpath); execpath= 0; + freecharparray(execargs); execargs= 0; +} + +int df_reject(int dtoken) { + int r; + + r= pa_mnl(); if (r) return r; + execreset(); + execute= tokv_word_reject; + return 0; +} + +int df_executefrompath(int dtoken) { + int r; + + r= pa_mnl(); if (r) return r; + execreset(); + execute= tokv_word_executefrompath; + return 0; +} + int df_execute(int dtoken) { const char *rv; char **newargs; int r; r= paa_pathargs(&rv,&newargs); if (r) return r; + execreset(); execute= tokv_word_execute; - freecharparray(execargs); execargs= newargs; - free(execpath); execpath= xstrsave(rv); + execargs= newargs; + execpath= xstrsave(rv); return 0; } @@ -792,9 +800,51 @@ int df_executefromdirectory(int dtoken) { " or link to one (mode=0%o)",fn,stab.st_mode); free(fn); freecharparray(newargs); return tokv_error; } + execreset(); execute= tokv_word_executefromdirectory; - freecharparray(execargs); execargs= newargs; - free(execpath); execpath= fn; + execargs= newargs; + execpath= fn; + return 0; +} + +static int bispa_none(char ***rnewargs) { + return pa_mnl(); +} + +static int bispa_parameter(char ***rnewargs) { + int r, i; + char **parmvalues, *name, **newargs; + + r= pa_mwsp(); if (r) return r; + r= pa_parameter(&parmvalues,&name); if (r) return r; + for (i=0; parmvalues[i]; i++); + newargs= xmalloc(sizeof(char*)*(i+2)); + newargs[0]= name; + memcpy(newargs+1,parmvalues,sizeof(char*)*(i+1)); + free(parmvalues); + r= pa_mnl(); if (r) { free(newargs); return r; } + *rnewargs= newargs; + return 0; +} + +int df_executebuiltin(int dtoken) { + int r; + builtinserviceexec_fnt *bisexec; + char *newpath, **newargs; + + r= pa_mwsp(); if (r) return r; + r= yylex(); if (r == tokv_error) return r; + if (!(r & tokt_builtinservice)) return unexpected(r,-1,"builtin service name"); + bisexec= lr_bisexec; + newpath= xstrsave(yytext); + newargs= 0; + r= lr_bispa(&newargs); if (r) { free(newpath); return r; } + + execreset(); + execute= tokv_word_executebuiltin; + execbuiltin= bisexec; + execpath= newpath; + execargs= newargs; return 0; } @@ -1009,7 +1059,7 @@ int df_includelookup(int dtoken) { int r, done, thisdone, cpl, c; r= pa_mwsp(); if (r) return r; - r= pa_parameter(&parmvalues); if (r) return r; + r= pa_parameter(&parmvalues,0); if (r) return r; r= paa_1path(&cp); if (r) { freecharparray(parmvalues); return r; } if (stat(cp,&stab)) { parseerrprint("unable to access directory `%s': %s",cp,strerror(errno)); diff --git a/process.c b/process.c index 8d20ce0..109c501 100644 --- a/process.c +++ b/process.c @@ -65,22 +65,23 @@ /* NB: defaults for the execution state are not set here, but in * the RESET_CONFIGURATION #define in daemon.h. */ -char **argarray; -char *((*defvararray)[2]); +struct request_msg request_mbuf; +struct keyvaluepair *defvararray; struct fdstate *fdarray; int fdarraysize, fdarrayused; int restfdwantstate= tokv_word_rejectfd, restfdwantrw; -struct request_msg request_mbuf; +int service_ngids; +char **argarray; char *serviceuser, *service, *logname, *cwd; char *overridedata, *userrcfile; char *serviceuser_dir, *serviceuser_shell, *callinguser_shell; -int service_ngids; gid_t *calling_gids, *service_gids; -const char **calling_groups, **service_groups; uid_t serviceuser_uid=-1; +const char **calling_groups, **service_groups; char *execpath, **execargs; int execute; int setenvironment, suppressargs, disconnecthup; +builtinserviceexec_fnt *execbuiltin; int syslogopenfacility=-1; static FILE *swfile, *srfile; @@ -104,6 +105,10 @@ int synchread(int fd, int ch) { return 0; } +const char *defaultpath(void) { + return serviceuser_uid ? DEFAULTPATH_USER : DEFAULTPATH_ROOT; +} + /* General-purpose functions; these do nothing special about signals */ static void blocksignals(void) { @@ -408,7 +413,7 @@ static void send_opening(void) { } static void receive_request(void) { - int i,j, fd; + int i, fd; unsigned long ul; xfread(&request_mbuf,sizeof(request_mbuf)); @@ -439,36 +444,41 @@ static void receive_request(void) { fdarray[fd].iswrite= (i>=request_mbuf.nreadfds); } - assert(request_mbuf.nargs <= MAX_ARGSDEFVARS); + assert(request_mbuf.nargs <= MAX_ARGSDEFVAR); argarray= xmalloc(sizeof(char*)*(request_mbuf.nargs)); for (i=0; ipw_dir)); serviceuser_shell= xstrsave(pw->pw_shell); serviceuser_uid= pw->pw_uid; + if (initgroups(pw->pw_name,pw->pw_gid)) syscallerror("initgroups"); if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 1"); if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 2"); @@ -523,6 +534,8 @@ static void check_find_executable(void) { r= stat(execpath,&stab); if (r) syscallfailure("checking for executable in directory, `%s'",execpath); break; + case tokv_word_executebuiltin: + break; case tokv_word_executefrompath: if (strchr(service,'/')) { r= stat(service,&stab); @@ -531,11 +544,11 @@ static void check_find_executable(void) { execpath= service; } else { string= getenv("PATH"); - if (!string) failure("execute-from-path, but daemon inherited no PATH !"); + if (!string) string= defaultpath(); while (string) { delim= strchr(string,':'); if (delim) { - if (delim-string > INT_MAX) + if (delim-string > MAX_GENERAL_STRING) failure("execute-from-path, but PATH component too long"); partsize= delim-string; nextstring= delim+1; @@ -586,7 +599,7 @@ static void check_fds(void) { fdarray[fd].realfd= open("/dev/null", fdarray[fd].iswrite == -1 ? O_RDWR : fdarray[fd].iswrite ? O_WRONLY : O_RDONLY); - if (fdarray[fd].realfd == -1) + if (fdarray[fd].realfd<0) syscallfailure("cannot open /dev/null for null fd"); break; case tokv_word_requirefd: @@ -597,7 +610,7 @@ static void check_fds(void) { if (fdarray[fd].realfd == -1) { fdarray[fd].iswrite= (fdarray[fd].wantrw == tokv_word_write); fdarray[fd].realfd= open("/dev/null",fdarray[fd].iswrite ? O_WRONLY : O_RDONLY); - if (fdarray[fd].realfd == -1) + if (fdarray[fd].realfd<0) syscallfailure("cannot open /dev/null for allowed but not provided fd"); } else { if (fdarray[fd].iswrite) { @@ -675,7 +688,7 @@ void servicerequest(int sfd) { "",1); ensurelogopen(USERVD_LOGFACILITY); - if (r == tokv_error) failure("error encountered while parsing configuration files"); + if (r == tokv_error) failure("error encountered while parsing configuration"); assert(r == tokv_quit); debug_dumpexecsettings(); diff --git a/servexec.c b/servexec.c index 48a6e29..abd3608 100644 --- a/servexec.c +++ b/servexec.c @@ -34,6 +34,7 @@ #include "common.h" #include "daemon.h" #include "lib.h" +#include "version.h" static void NONRETURNING serv_syscallfail(const char *msg) { fputs("uservd(service): ",stderr); @@ -41,6 +42,87 @@ static void NONRETURNING serv_syscallfail(const char *msg) { _exit(-1); } +static void NONRETURNING serv_checkstdoutexit(void) { + if (ferror(stdout) || fclose(stdout)) serv_syscallfail("write stdout"); + _exit(0); +} + +void bisexec_environment(const char *const *argv) { + execlp("env","env",(char*)0); + serv_syscallfail("execute `env'"); +} + +void bisexec_parameter(const char *const *argv) { + always_dumpparameter(execargs[0],execargs+1); + serv_checkstdoutexit(); +} + +void bisexec_version(const char *const *argv) { + const unsigned char *p; + int i; + + printf("uservd version " VERSION "; copyright (C)1996-1997 Ian Jackson.\n" +#ifdef DEBUG + "DEBUGGING VERSION" +#else + "production version" +#endif + " - protocol magic number %08lx\n" + "protocol checksum:", + BASE_MAGIC); + for (i=0, p=protocolchecksumversion; i0) { putchar(' '); nspaces--; } + putchar(c); + } + } + assert(*--string == '\n'); + serv_checkstdoutexit(); +} + +void bisexec_toplevel(const char *const *argv) { + dumpconfig(TOPLEVEL_CONFIGURATION); +} + +void bisexec_override(const char *const *argv) { + dumpconfig(TOPLEVEL_OVERRIDDEN_CONFIGURATION); +} + +void bisexec_reset(const char *const *argv) { + dumpconfig(RESET_CONFIGURATION); +} + +void bisexec_execute(const char *const *argv) { + always_dumpexecsettings(); + serv_checkstdoutexit(); +} + static void serv_resetsignal(int signo) { struct sigaction sig; @@ -54,10 +136,6 @@ static const char *see_logname(void) { return serviceuser; } static const char *see_home(void) { return serviceuser_dir; } static const char *see_shell(void) { return serviceuser_shell; } -static const char *see_path(void) { - return serviceuser_uid ? DEFAULTPATH_USER : DEFAULTPATH_ROOT; -} - static const char *see_service(void) { return service; } static const char *see_c_cwd(void) { return cwd; } static const char *see_c_logname(void) { return logname; } @@ -104,7 +182,7 @@ static const struct serv_envinfo { { "LOGNAME", see_logname }, { "HOME", see_home }, { "SHELL", see_shell }, - { "PATH", see_path }, + { "PATH", defaultpath }, { "USERV_SERVICE", see_service }, { "USERV_CWD", see_c_cwd }, { "USERV_USER", see_c_logname }, @@ -190,10 +268,10 @@ void execservice(const int synchsocket[], int clientfd) { for (sei= serv_envinfos; sei->name; sei++) if (setenv(sei->name,sei->fn(),1)) serv_syscallfail("setenv standard"); for (i=0; ienvvarbufsize) { envvarbufsize= l; envvarbuf= xrealloc(envvarbuf,l); } - snyprintf(envvarbuf,l,"USERV_U_%s",defvararray[i][0]); - if (setenv(envvarbuf,defvararray[i][1],1)) serv_syscallfail("setenv defvar"); + snyprintf(envvarbuf,l,"USERV_U_%s",defvararray[i].key); + if (setenv(envvarbuf,defvararray[i].value,1)) serv_syscallfail("setenv defvar"); } nargs= 0; @@ -209,7 +287,10 @@ void execservice(const int synchsocket[], int clientfd) { if (!suppressargs) for (i=0; i userv

The service name is interpreted by the userv + +Requests that a builtin service be provided. This is equivalent to +using the for details of the builtin services available, +and for details of the @@ -315,7 +331,7 @@ status method -Security-overriding options +Security-overriding options

There are also some options which are available for debugging and to @@ -817,7 +833,7 @@ error will not be caught. -Directives for changing execution settings +Directives for changing execution settings

The following directives modify the execution settings; the server @@ -867,6 +883,51 @@ directive is +Executes the builtin service + + +In the future other builtin services may be defined which do more than +just print information. + -- 2.30.2