X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=client.c;h=9d12491be10c38eefc8bff5f22cd72fc3f90e833;hb=c7032f9d19f70ce53dd36b1f0ddede792f1974ca;hp=527da1b9653baae800748653e6088d1aea2d5a30;hpb=703b99b834625829d6b285e5bca619475ef54511;p=userv.git diff --git a/client.c b/client.c index 527da1b..9d12491 100644 --- a/client.c +++ b/client.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include "config.h" #include "common.h" +#include "version.h" struct optioninfo; @@ -143,7 +145,7 @@ static unsigned long timeout=0; static int signalsexit=254; static int sigpipeok=0, hidecwd=0; static int overridetype= ot_none; -static const char *overridevalue; +static const char *overridevalue, *spoofuser=0; static FILE *srfile, *swfile; @@ -272,19 +274,20 @@ static void xfflush(FILE *file) { static void usage(void) { if (fprintf(stderr, - "usage: userv [--] [ ...]\n" - "options: -f|--file []=\n" - " -D|--defvar =\n" - " -t|--timeout \n" - " -S|--signals |number|number-nocore|highbit|stdout\n" - " -w|--fdwait =wait|nowait|close\n" - " -P|--sigpipe -H|--hidecwd -h|--help --copyright\n" - " --override } available only to\n" - " --override-file } root or same user\n" - "fdmodifiers: read write overwrite trunc[ate]\n" - "(separate with commas) append sync excl[usive] creat[e] fd\n\n" - "userv and uservd are copyright (C)1996-1997 Ian Jackson.\n" - "They come with NO WARRANTY; type `userv --copyright' for details.\n") + "usage: userv [--] [ ...]\n" + "options: -f|--file []=\n" + " -D|--defvar =\n" + " -t|--timeout \n" + " -S|--signals |number|number-nocore|highbit|stdout\n" + " -w|--fdwait =wait|nowait|close\n" + " -P|--sigpipe -H|--hidecwd -h|--help --copyright\n" + " --override } available only\n" + " --override-file } to root\n" + " --spoof-user } or same user\n" + "fdmodifiers: read write overwrite trunc[ate]\n" + "(separate with commas) append sync excl[usive] creat[e] fd\n\n" + "userv and uservd version " VERSION "; copyright (C)1996-1997 Ian Jackson.\n" + "there is NO WARRANTY; type `userv --copyright' for details.\n") == EOF) syscallerror("write usage to stderr"); } @@ -392,17 +395,20 @@ static void of_file(const struct optioninfo *oip, const char *value, char *key) static void of_fdwait(const struct optioninfo *oip, const char *value, char *key) { const struct fdmodifierinfo *fdmip; - unsigned long fd; + unsigned long ul; + int fd; char *delim; fd= fdstdnumber(key); if (fd<0) { - fd= strtoul(value,&delim,0); + ul= strtoul(key,&delim,0); if (*delim) usageerror("first part of argument to --fdwait must be " "numeric or fd name - `%s' is not recognised",key); + if (ul>INT_MAX) usageerror("first part of argument to --fdwait is far too large"); + fd= ul; } if (fd >= fdsetupsize || !fdsetup[fd].filename) - usageerror("file descriptor %lu specified in --fdwait option is not open",fd); + usageerror("file descriptor %d specified in --fdwait option is not open",fd); for (fdmip= fdmodifierinfos; fdmip->string && strcmp(fdmip->string,value); fdmip++); if (!fdmip->string || !(fdmip->implies & (fdm_wait|fdm_nowait|fdm_close))) usageerror("value for --fdwait must be `wait', `nowait' or `close', not `%s'",value); @@ -490,6 +496,11 @@ static void of_overridefile(const struct optioninfo *oip, overridevalue= value; } +static void of_spoofuser(const struct optioninfo *oip, + const char *value, char *key) { + spoofuser= value; +} + const struct optioninfo optioninfos[]= { { 'f', "file", 2, of_file }, { 'w', "fdwait", 2, of_fdwait }, @@ -502,6 +513,7 @@ const struct optioninfo optioninfos[]= { { 0, "copyright", 0, of_copyright }, { 0, "override", 1, of_override }, { 0, "override-file", 1, of_overridefile }, + { 0, "spoof-user", 1, of_spoofuser }, { 0, 0 } }; @@ -658,17 +670,19 @@ 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; + int sfd, ngids, i, j, tempfd, l, c, reading, fd, r, status, ngidssize; sigset_t sset; unsigned long ul; size_t cwdbufsize; - char *cwdbuf; + char *cwdbuf, **mem; struct opening_msg opening_mbuf; struct request_msg request_mbuf; struct progress_msg progress_mbuf; struct event_msg event_mbuf; struct passwd *pw; - gid_t mygid, *gidarray; + struct group *gr; + gid_t mygid, spoofgid, *gidarray; + uid_t spoofuid; pid_t mypid; const char *logname; FILE *ovfile; @@ -752,19 +766,44 @@ int main(int argc, char *const *argv) { if (!pw) miscerror("requested service user `%s' is not a user",serviceuser); serviceuid= pw->pw_uid; - if (overridetype != ot_none && myuid != 0 && myuid != serviceuid) - miscerror("--override options only available to root or to" + if ((overridetype != ot_none || spoofuser) && myuid != 0 && myuid != serviceuid) + miscerror("--override and --spoof options only available to root or to" " the user who will be providing the service"); - logname= getenv("LOGNAME"); - if (!logname) logname= getenv("USER"); - if (logname) { + if (spoofuser) { + logname= spoofuser; pw= getpwnam(logname); - if (!pw || pw->pw_uid != myuid) logname= 0; - } - if (!logname) { - pw= getpwuid(myuid); if (!pw) syscallerror("cannot determine your login name"); - logname= pw->pw_name; + if (!pw) miscerror("spoofed login name `%s' is not valid",logname); + spoofuid= pw->pw_uid; + spoofgid= pw->pw_gid; + ngidssize= ngids; ngids= 0; + if (ngidssize<5) { + ngidssize= 5; + gidarray= xrealloc(gidarray,sizeof(gid_t)*ngidssize); + } + gidarray[ngids++]= spoofgid; + while ((gr= getgrent())) { /* ouch! getgrent has no error behaviour! */ + for (mem= gr->gr_mem; *mem && strcmp(*mem,logname); mem++); + if (!*mem) continue; + if (ngids>=ngidssize) { + ngidssize= (ngids+5)<<1; + gidarray= xrealloc(gidarray,sizeof(gid_t)*ngidssize); + } + 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; @@ -873,7 +912,7 @@ int main(int argc, char *const *argv) { request_mbuf.servicelen= strlen(argv[0]); request_mbuf.lognamelen= strlen(logname); request_mbuf.cwdlen= cwdbufsize; - request_mbuf.callinguid= myuid; + request_mbuf.callinguid= spoofuid; request_mbuf.ngids= ngids+1; request_mbuf.nreadfds= 0; request_mbuf.nwritefds= 0; @@ -892,7 +931,7 @@ int main(int argc, char *const *argv) { xfwrite(logname,sizeof(*logname)*request_mbuf.lognamelen,swfile); xfwrite(cwdbuf,sizeof(*cwdbuf)*request_mbuf.cwdlen,swfile); if (ovused>=0) xfwrite(ovbuf,sizeof(*ovbuf)*ovused,swfile); - xfwrite(&mygid,sizeof(gid_t),swfile); + xfwrite(&spoofgid,sizeof(gid_t),swfile); xfwrite(gidarray,sizeof(gid_t)*ngids,swfile); xfwritefds(fdm_read,request_mbuf.nreadfds,swfile); xfwritefds(fdm_write,request_mbuf.nwritefds,swfile);