#include <unistd.h>
#include <ctype.h>
#include <pwd.h>
+#include <grp.h>
#include <signal.h>
#include <limits.h>
#include <sys/time.h>
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;
" -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"
+ " --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"
- "They come with NO WARRANTY; type `userv --copyright' for details.\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);
struct request_msg request_mbuf;
char *serviceuser=0, *service=0, *logname=0, *cwd=0;
char *overridedata=0, *userrcfile=0;
-char *serviceuser_dir=0, *serviceuser_shell=0;
+char *serviceuser_dir=0, *serviceuser_shell=0, *callinguser_shell;
uid_t serviceuser_uid=-1;
gid_t serviceuser_gid=-1;
char *execpath=0, **execargs=0;
static FILE *swfile= 0, *srfile= 0;
static pid_t child= -1, childtokill= -1;
-
-static struct passwd *servicepw, *callingpw;
static const char **grouparray;
static void sigchildhandler(int x) {
return 0;
}
-static const char *see_logname(void) { return servicepw->pw_name; }
-static const char *see_home(void) { return servicepw->pw_dir; }
-static const char *see_shell(void) { return servicepw->pw_shell; }
+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 servicepw->pw_uid ?
+ return serviceuser_uid ?
"/usr/local/bin:/bin:/usr/bin" :
"/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin";
}
static const char *see_c_logname(void) { return logname; }
static const char *see_c_uid(void) {
static char buf[CHAR_BIT*sizeof(uid_t)/3+4];
- snyprintf(buf,sizeof(buf),"%lu",(unsigned long)callingpw->pw_uid);
+ snyprintf(buf,sizeof(buf),"%lu",(unsigned long)request_mbuf.callinguid);
return buf;
}
struct stat stab;
struct sigaction sig;
struct group *cgrp;
+ struct passwd *pw;
ensurelogopen(USERVD_LOGFACILITY);
syslog(LOG_DEBUG,"call connected");
if (close(tempfd)) syscallerror("close prelim fd onto pipe");
}
- servicepw= getpwnam(serviceuser);
- if (!servicepw) syscallerror("look up service user");
- assert(!strcmp(servicepw->pw_name,serviceuser));
- serviceuser_dir= xstrdup(nondebug_serviceuserdir(servicepw->pw_dir));
- serviceuser_shell= xstrdup(servicepw->pw_shell);
- serviceuser_uid= servicepw->pw_uid;
- serviceuser_gid= servicepw->pw_gid;
- if (initgroups(servicepw->pw_name,servicepw->pw_gid)) syscallerror("initgroups");
- if (setreuid(servicepw->pw_uid,servicepw->pw_uid)) syscallerror("setreuid 1");
- if (setreuid(servicepw->pw_uid,servicepw->pw_uid)) syscallerror("setreuid 2");
- if (servicepw->pw_uid)
- if (!setreuid(servicepw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded");
+ pw= getpwnam(serviceuser);
+ if (!pw) miscerror("look up service user");
+ assert(!strcmp(pw->pw_name,serviceuser));
+ serviceuser_dir= xstrdup(nondebug_serviceuserdir(pw->pw_dir));
+ serviceuser_shell= xstrdup(pw->pw_shell);
+ serviceuser_uid= pw->pw_uid;
+ serviceuser_gid= pw->pw_gid;
+ 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");
+ if (pw->pw_uid)
+ if (!setreuid(pw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded");
if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way");
debug_dumprequest(mypid);
- callingpw= getpwnam(logname);
- if (!callingpw) syscallerror("get passwd entry for calling user");
grouparray= xmalloc(sizeof(char*)*request_mbuf.ngids);
for (i=0; i<request_mbuf.ngids; i++) {
cgrp= getgrgid(gidarray[i]);
- if (!cgrp) syscallerror("get group entry for calling group");
+ if (!cgrp) miscerror("get group entry for calling group");
grouparray[i]= xmstrsave(cgrp->gr_name);
}