X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv.git;a=blobdiff_plain;f=process.c;h=636255a286f18209d2eed766e18d42bf260ec169;hp=35eba59ccd115c9091a277637b6b38e422a0f22a;hb=c7ad3b51358d0b7704e5670d973ad1a376caf4e1;hpb=db59ee1476515a65cfcca10a3059d8ccb2d24d32 diff --git a/process.c b/process.c index 35eba59..636255a 100644 --- a/process.c +++ b/process.c @@ -2,7 +2,7 @@ * userv - process.c * daemon code to process one request (is parent of service process) * - * Copyright (C)1996-1997 Ian Jackson + * Copyright (C)1996-1999 Ian Jackson * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +51,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -60,6 +61,7 @@ #include "config.h" #include "common.h" +#include "both.h" #include "daemon.h" #include "lib.h" #include "tokens.h" @@ -73,7 +75,7 @@ int fdarraysize, fdarrayused; int restfdwantstate= tokv_word_rejectfd, restfdwantrw; int service_ngids; char **argarray; -char *serviceuser, *service, *logname, *cwd; +char *serviceuser, *service, *loginname, *cwd; char *overridedata, *userrcfile; char *serviceuser_dir, *serviceuser_shell, *callinguser_shell; gid_t *calling_gids, *service_gids; @@ -126,7 +128,7 @@ static void xfwriteerror(void) { if (errno != EPIPE) syscallerror("writing to client"); blocksignals(); ensurelogopen(USERVD_LOGFACILITY); - syslog(LOG_DEBUG,"client went away (broken pipe)"); + syslog(LOG_INFO,"client went away (broken pipe)"); disconnect(8); } @@ -147,11 +149,11 @@ static void xfflush(FILE *file) { static void xfread(void *p, size_t sz) { size_t nr; - nr= fread(p,1,sz,srfile); if (nr == sz) return; + nr= working_fread(p,sz,srfile); if (nr == sz) return; if (ferror(srfile)) syscallerror("reading from client"); blocksignals(); assert(feof(srfile)); - syslog(LOG_DEBUG,"client went away (unexpected EOF)"); + syslog(LOG_INFO,"client went away (unexpected EOF)"); swfile= 0; disconnect(8); } @@ -183,7 +185,7 @@ static void getevent(struct event_msg *event_r) { blocksignals(); syslog(LOG_ERR,"client sent bad file descriptor %d to close (max %d)", fd,fdarrayused-1); - disconnect(12); + disconnect(20); } if (fdarray[fd].holdfd!=-1) { if (close(fdarray[fd].holdfd)) syscallerror("cannot close holding fd"); @@ -192,7 +194,7 @@ static void getevent(struct event_msg *event_r) { break; case et_disconnect: blocksignals(); - syslog(LOG_DEBUG,"client disconnected"); + syslog(LOG_INFO,"client disconnected"); disconnect(4); default: return; @@ -218,7 +220,7 @@ void syscallerror(const char *what) { e= errno; blocksignals(); syslog(LOG_ERR,"system call failure: %s: %s",what,strerror(e)); - disconnect(18); + disconnect(16); } /* Functions which may be called from signal handlers. These @@ -269,8 +271,18 @@ void NONRETURNING disconnect(int exitstatus) { _exit(exitstatus); } -static void NONRETURNING sighandler_chld(int ignored) { +static void reporttermination(int status) { struct progress_msg progress_mbuf; + + memset(&progress_mbuf,0,sizeof(progress_mbuf)); + progress_mbuf.magic= PROGRESS_MAGIC; + progress_mbuf.type= pt_terminated; + progress_mbuf.data.terminated.status= status; + xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile); + xfflush(swfile); +} + +static void NONRETURNING sighandler_chld(int ignored) { int status; pid_t returned; @@ -280,14 +292,8 @@ static void NONRETURNING sighandler_chld(int ignored) { if (returned!=child) syscallerror("spurious child process"); child= childtokill= -1; - memset(&progress_mbuf,0,sizeof(progress_mbuf)); - progress_mbuf.magic= PROGRESS_MAGIC; - progress_mbuf.type= pt_terminated; - progress_mbuf.data.terminated.status= status; - xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile); - xfflush(swfile); - - syslog(LOG_DEBUG,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff); + reporttermination(status); + syslog(LOG_INFO,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff); _exit(0); } @@ -327,7 +333,7 @@ static void NONRETURNING generalfailure(const char *prefix, int reserveerrno, strnytcat(errmsg,strerror(errnoval),sizeof(errmsg)); } senderrmsgstderr(errmsg); - syslog(LOG_DEBUG,"service failed (%s)",errmsg); + syslog(LOG_INFO,"service failed (%s)",errmsg); disconnect(12); } @@ -399,6 +405,7 @@ static void send_opening(void) { memset(&opening_mbuf,0,sizeof(opening_mbuf)); opening_mbuf.magic= OPENING_MAGIC; memcpy(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE); + opening_mbuf.overlordpid= overlordpid; opening_mbuf.serverpid= mypid; xfwrite(&opening_mbuf,sizeof(opening_mbuf),swfile); xfflush(swfile); @@ -411,7 +418,8 @@ static void receive_request(void) { xfread(&request_mbuf,sizeof(request_mbuf)); serviceuser= xfreadsetstring(request_mbuf.serviceuserlen); service= xfreadsetstring(request_mbuf.servicelen); - logname= xfreadsetstring(request_mbuf.lognamelen); + assert(request_mbuf.spoofed==0 || request_mbuf.spoofed==1); + loginname= xfreadsetstring(request_mbuf.loginnamelen); cwd= xfreadsetstring(request_mbuf.cwdlen); if (request_mbuf.overridelen >= 0) { assert(request_mbuf.overridelen <= MAX_OVERRIDE_LEN); @@ -493,9 +501,9 @@ static void groupnames(int ngids, gid_t *gids, const char ***names_r) { static void lookup_uidsgids(void) { struct passwd *pw; - pw= getpwnam(logname); + pw= getpwnam(loginname); if (!pw) miscerror("look up calling user"); - assert(!strcmp(pw->pw_name,logname)); + assert(!strcmp(pw->pw_name,loginname)); callinguser_shell= xstrsave(pw->pw_shell); pw= getpwnam(serviceuser); @@ -505,12 +513,15 @@ static void lookup_uidsgids(void) { serviceuser_shell= xstrsave(pw->pw_shell); serviceuser_uid= pw->pw_uid; + if (setregid(pw->pw_gid,pw->pw_gid)) syscallerror("setregid 1"); 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 (pw->pw_uid) { if (!setreuid(pw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded"); - if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way"); + if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way"); + } + if (setregid(pw->pw_gid,pw->pw_gid)) syscallerror("setregid 2"); service_ngids= getgroups(0,0); if (service_ngids == -1) syscallerror("getgroups(0,0)"); if (service_ngids > MAX_GIDS) miscerror("service user is in far too many groups"); @@ -594,6 +605,7 @@ static void makenonexistentfd(int fd) { if (fdarray[fd].holdfd != -1) { if (close(fdarray[fd].holdfd)) syscallfailure("close unwanted hold descriptor for %d",fd); + fdarray[fd].holdfd= -1; } } } @@ -710,9 +722,13 @@ void servicerequest(int sfd) { setup_comms(sfd); send_opening(); receive_request(); + if (request_mbuf.clientpid == (pid_t)-1) _exit(2); establish_pipes(); lookup_uidsgids(); debug_dumprequest(mypid); + syslog(LOG_INFO,"%s %s -> %s %c %s", + request_mbuf.spoofed ? "spoof" : "user", + loginname, serviceuser, overridedata?'!':':', service); if (overridedata) r= parse_string(TOPLEVEL_OVERRIDDEN_CONFIGURATION, @@ -734,6 +750,18 @@ void servicerequest(int sfd) { getevent(&event_mbuf); assert(event_mbuf.type == et_confirm); + if (execbuiltin == bisexec_shutdown && !serviceuser_uid) { + /* The check for the uid is just so we can give a nice + * error message (in the actual code for bisexec_shutdown). + * If this is spoofed somehow then the unlink() will simply fail. + */ + r= unlink(RENDEZVOUSPATH); + if (r) syscallfailure("remove rendezvous socket %s",RENDEZVOUSPATH); + syslog(LOG_NOTICE,"arranging for termination, due to client request"); + reporttermination(0); + _exit(10); + } + fork_service_synch(); getevent(&event_mbuf);