#include <unistd.h>
#include <ctype.h>
#include <pwd.h>
+#include <grp.h>
#include <signal.h>
#include <limits.h>
#include <sys/time.h>
#include "config.h"
#include "common.h"
+#include "version.h"
struct optioninfo;
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;
static void usage(void) {
if (fprintf(stderr,
- "usage: userv <options> [--] <service-user> <service-name> [<argument> ...]\n"
- "options: -f|--file <fd>[<fdmodifiers>]=<filename>\n"
- " -D|--defvar <name>=<value>\n"
- " -t|--timeout <seconds>\n"
- " -S|--signals <status>|number|number-nocore|highbit|stdout\n"
- " -w|--fdwait <fd>=wait|nowait|close\n"
- " -P|--sigpipe -H|--hidecwd -h|--help --copyright\n"
- " --override <configuration-data> } available only to\n"
- " --override-file <filename> } 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 <options> [--] <service-user> <service-name> [<argument> ...]\n"
+ "options: -f|--file <fd>[<fdmodifiers>]=<filename>\n"
+ " -D|--defvar <name>=<value>\n"
+ " -t|--timeout <seconds>\n"
+ " -S|--signals <status>|number|number-nocore|highbit|stdout\n"
+ " -w|--fdwait <fd>=wait|nowait|close\n"
+ " -P|--sigpipe -H|--hidecwd -h|--help --copyright\n"
+ " --override <configuration-data> } available only\n"
+ " --override-file <filename> } to root\n"
+ " --spoof-user <username> } 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");
}
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 },
{ 0, "copyright", 0, of_copyright },
{ 0, "override", 1, of_override },
{ 0, "override-file", 1, of_overridefile },
+ { 0, "spoof-user", 1, of_spoofuser },
{ 0, 0 }
};
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;
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;
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;
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);