Back to index

courier  0.68.2
uucp.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2000-2012 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 
00010 #include      "courier.h"
00011 #include      "rw.h"
00012 #include      "moduledel.h"
00013 #include      "rfc822/rfc822.h"
00014 #include      "numlib/numlib.h"
00015 #include      <stdlib.h>
00016 #include      <string.h>
00017 #include      <ctype.h>
00018 #include      <signal.h>
00019 #include      <errno.h>
00020 #if    HAVE_UNISTD_H
00021 #include      <unistd.h>
00022 #endif
00023 #if    HAVE_FCNTL_H
00024 #include      <fcntl.h>
00025 #endif
00026 #include      <pwd.h>
00027 #include      <sys/wait.h>
00028 #include      <sys/time.h>
00029 #include      "comctlfile.h"
00030 #include      "comqueuename.h"
00031 #include      "comstrtotime.h"
00032 #include      "comstrtimestamp.h"
00033 #include      "comverp.h"
00034 #include      <sys/stat.h>
00035 
00036 static void uux(struct moduledel *);
00037 
00038 static void (*rewrite_func)(struct rw_info *, void (*)(struct rw_info *));
00039 
00040 static const char *uucp_is_disabled=0;
00041 
00042 int main(int argc, char **argv)
00043 {
00044 struct moduledel *p;
00045 struct passwd *pwd;
00046 
00047        clog_open_syslog("courieruucp");
00048        if (chdir(getenv("COURIER_HOME")))
00049               clog_msg_errno();
00050 
00051        pwd=getpwnam("uucp");
00052        if (!pwd)
00053        {
00054               uucp_is_disabled=
00055                      "ERROR: no uucp user found, outbound UUCP is DISABLED!",
00056               clog_msg_start_err();
00057               clog_msg_str(uucp_is_disabled);
00058               clog_msg_send();
00059 
00060               libmail_changeuidgid(MAILUID, MAILGID);
00061        }
00062        else
00063               libmail_changeuidgid(pwd->pw_uid, MAILGID);
00064 
00065 
00066        rw_init_courier("uucp");
00067         rewrite_func=rw_search_transport("uucp")->rw_ptr->rewrite;
00068 
00069        /* Loop to receive messages from Courier */
00070 
00071        module_init(0);
00072        while ((p=module_getdel()) != NULL)
00073        {
00074        pid_t  pid;
00075        unsigned delid;
00076 
00077               delid=atol(p->delid);
00078 
00079               if ((pid=module_fork(delid, 0)) == -1)
00080               {
00081                      clog_msg_prerrno();
00082                      module_completed(delid, delid);
00083                      continue;
00084               }
00085 
00086               if (pid == 0)
00087               {
00088                      uux(p);
00089                      exit(0);
00090               }
00091        }
00092        return (0);
00093 }
00094 
00095 static char   errbuf[512];
00096 static char   *errbufptr;
00097 static unsigned errbufleft;
00098 static int    pid;
00099 static int    uuxpipe;
00100 static int    uuxerr;
00101 
00102 static struct rfc822token *delhostt;
00103 
00104 struct uucprwinfo {
00105        struct rfc822token *delhostt;
00106        void (*rewrite_func)(struct rw_info *, void (*)(struct rw_info *));
00107        } ;
00108 
00109 static void call_rewrite_func(struct rw_info *i,
00110               void (*func)(struct rw_info *),
00111               void *voidarg)
00112 {
00113 struct uucprwinfo *arg= (struct uucprwinfo *)voidarg;
00114 
00115        i->host=arg->delhostt;
00116        (*arg->rewrite_func)(i, func);
00117 }
00118 
00119 static RETSIGTYPE alarm_sig(int n)
00120 {
00121        n=n;
00122        kill(pid, SIGKILL);
00123 #if    RETSIGTYPE != void
00124        return (0)
00125 #endif
00126 }
00127 
00128 static void adderrbuf(const char *msg, unsigned l)
00129 {
00130        if (l == 0)   l=strlen(msg);
00131        if (l > errbufleft)  l=errbufleft;
00132        if (l)
00133        {
00134               memcpy(errbufptr, msg, l);
00135               errbufptr += l;
00136               errbufleft -= l;
00137        }
00138 }
00139 
00140 static int readuuxerr()
00141 {
00142 char   buf[256];
00143 int    n;
00144 
00145        while ((n=read(uuxerr, buf, sizeof(buf))) < 0 && errno == EINTR)
00146               ;
00147 
00148        if (n <= 0)
00149               return (-1);
00150 
00151        adderrbuf(buf, n);
00152        return (0);
00153 }
00154 
00155 static void uux2(struct moduledel *, struct ctlfile *, unsigned *, unsigned);
00156 
00157 static void uux(struct moduledel *p)
00158 {
00159 struct ctlfile ctf;
00160 unsigned *reciparray;
00161 unsigned nreceipients=p->nreceipients;
00162 struct rfc822t *hostt;
00163 unsigned i;
00164 
00165        if ((reciparray=malloc(sizeof(unsigned)*nreceipients)) == 0)
00166               clog_msg_errno();
00167 
00168        for (i=0; i<nreceipients; i++)
00169               reciparray[i]=i;
00170 
00171        if (ctlfile_openi(p->inum, &ctf, 0))
00172               clog_msg_errno();
00173        ctlfile_setvhost(&ctf);
00174 
00175        /* Save host we will be contacting, for rewriting */
00176 
00177        hostt=rw_rewrite_tokenize(p->host);
00178        delhostt=hostt->tokens;
00179 
00180        if (ctlfile_searchfirst(&ctf, COMCTLFILE_VERP) < 0 ||
00181               *p->sender == 0)
00182               /* No VERP */
00183               uux2(p, &ctf, reciparray, nreceipients);
00184        else
00185        {
00186        const char *save_sender=p->sender;
00187 
00188               for (i=0; i<nreceipients; i++)
00189               {
00190               /* The real recipient is host!recipient */
00191 
00192               const char *receipient=p->receipients[reciparray[i]*2+1];
00193               char   *recip=courier_malloc(strlen(p->host)
00194                             +strlen(receipient)+2);
00195               char   *verp_sender=0;
00196 
00197                      strcat(strcat(strcpy(recip, p->host), "!"), receipient);
00198 
00199                      verp_sender=courier_malloc(strlen(save_sender)+
00200                             verp_encode(recip, 0)+1);
00201 
00202                      strcat(strcpy(verp_sender, save_sender), "-");
00203                      verp_encode(recip, verp_sender+strlen(verp_sender));
00204 
00205                      p->sender=verp_sender;
00206                      uux2(p, &ctf, reciparray+i, 1);
00207                      free(verp_sender);
00208               }
00209               p->sender=save_sender;
00210        }
00211        ctlfile_close(&ctf);
00212        free(reciparray);
00213 }
00214 
00215 static int dowrite(const char *, unsigned, void *);
00216 
00217 /*
00218 **     In order to properly quote a non-file argument to uux:
00219 **
00220 **     Surround the argument with ().
00221 **
00222 **     This sux.
00223 */
00224 
00225 static char *uucp_quote(const char *arg)
00226 {
00227 char   *s;
00228 
00229        s=courier_malloc(strlen(arg)+3);
00230        strcat(strcat(strcpy(s, "("), arg), ")");
00231        return (s);
00232 }
00233 
00234 /*
00235 ** Now, for those recipients that have NOTIFY=NEVER, we fudge the envelope
00236 ** sender to <>
00237 */
00238 
00239 static void uux3(struct moduledel *p, struct ctlfile *ctf,
00240        unsigned *reciparray, unsigned nreceipients);
00241 
00242 static void uux2(struct moduledel *p, struct ctlfile *ctf,
00243        unsigned *reciparray, unsigned nreceipients)
00244 {
00245 int    pass;
00246 const char *sender=p->sender;
00247 unsigned *savearray;
00248 unsigned i, j;
00249 
00250        if (nreceipients == 0)      return;
00251 
00252        savearray=courier_malloc(nreceipients * sizeof(*reciparray));
00253 
00254         for (pass=0; pass<2; pass++)
00255         {
00256                 if (pass)       p->sender="";
00257 
00258               j=0;
00259 
00260                 for (i=0; i<nreceipients; i++)
00261                 {
00262                 const char *dsnptr=ctf->dsnreceipients[
00263                      atoi(p->receipients[reciparray[i]*2])];
00264 
00265                         if (dsnptr && strchr(dsnptr, 'N'))
00266                         {
00267                                 if (pass == 0)  continue;
00268                         }
00269                         else
00270                         {
00271                                 if (pass == 1)  continue;
00272                         }
00273                      savearray[j++]= reciparray[i];
00274               }
00275 
00276               if (j)
00277                      uux3(p, ctf, savearray, j);
00278        }
00279        p->sender=sender;
00280        free(savearray);
00281 }
00282 
00283 
00284 
00285 static void uux3(struct moduledel *p, struct ctlfile *ctf,
00286        unsigned *reciparray, unsigned nreceipients)
00287 {
00288 char   *s, *last;
00289 int    pipefd[2];
00290 int    pipefd2[2];
00291 int    fp;
00292 int    j;
00293 int    waitstat;
00294 pid_t  pid2;
00295 char   *saveerrbuf;
00296 unsigned i;
00297 struct uucprwinfo uucprwinfo_s;
00298 struct stat stat_buf;
00299 const char *sec;
00300 
00301        if (p->nreceipients == 0)   return;
00302 
00303        if (uucp_is_disabled)
00304        {
00305               for (i=0; i<nreceipients; i++)
00306               {
00307                      ctlfile_append_reply(ctf,
00308                             (unsigned)atol(p->receipients[reciparray[i]*2]),
00309                             uucp_is_disabled,
00310                             COMCTLFILE_DELDEFERRED, 0);
00311               }
00312               ctlfile_close(ctf);
00313               exit(0);
00314               return;
00315        }
00316 
00317        sec=ctlfile_security(ctf);
00318        if (strncmp(sec, "STARTTLS", 8) == 0)
00319        {
00320               for (i=0; i<nreceipients; i++)
00321               {
00322                      ctlfile_append_reply(ctf,
00323                             (unsigned)atol(p->receipients[reciparray[i]*2]),
00324                             "Unable to set minimum security level.",
00325                             COMCTLFILE_DELFAIL_NOTRACK, 0);
00326               }
00327               ctlfile_close(ctf);
00328               exit(0);
00329               return;
00330        }
00331 
00332        if (pipe(pipefd) || pipe(pipefd2))
00333               clog_msg_errno();
00334 
00335        if ((fp=open(qmsgsdatname(p->inum), O_RDONLY)) < 0)
00336        {
00337               for (i=0; i<nreceipients; i++)
00338               {
00339                      ctlfile_append_reply(ctf,
00340                             (unsigned)atol(p->receipients[reciparray[i]*2]),
00341                             "Cannot open message file.",
00342                             COMCTLFILE_DELFAIL_NOTRACK, 0);
00343               }
00344               ctlfile_close(ctf);
00345               exit(0);
00346               return;
00347        }
00348 
00349        if (fstat(fp, &stat_buf) == 0)
00350               ctf->msgsize=stat_buf.st_size;
00351 
00352        pid=fork();
00353        if (pid == -1)
00354               clog_msg_errno();
00355 
00356        if (pid == 0)
00357        {
00358        char *argenv, *argenvcopy, *s;
00359        unsigned      nargs_needed;
00360        const char **argvec;
00361 
00362               close(fp);
00363               close(pipefd[1]);
00364               dup2(pipefd[0], 0);
00365               close(pipefd[0]);
00366               close(pipefd2[0]);
00367               dup2(pipefd2[1], 1);
00368               dup2(pipefd2[1], 2);
00369               close(pipefd2[1]);
00370 
00371               argenv=getenv("UUXFLAGS");
00372               if (!argenv)  argenv="";
00373               argenvcopy=courier_malloc(strlen(argenv)+1);
00374               strcpy(argenvcopy, argenv);
00375               nargs_needed=9+nreceipients;
00376                      /* uux -p -z -a sender path!rmail -f sender (null) */
00377 
00378               for (s=argenvcopy; (s=strtok(s, " \t")) != 0; s=0)
00379                      ++nargs_needed;
00380 
00381               argvec=courier_malloc(nargs_needed * sizeof(char *));
00382               argvec[0]=UUX;
00383               argvec[1]="-p";
00384               nargs_needed=2;
00385 
00386               if (*p->sender)
00387               {
00388                      argvec[nargs_needed++]="-z";
00389                      argvec[nargs_needed++]="-a";
00390                      argvec[nargs_needed++]=p->sender;
00391               }
00392               else
00393               {
00394                      argvec[nargs_needed++]="-n";
00395               }
00396 
00397               strcpy(argenvcopy, argenv);
00398               for (s=argenvcopy; (s=strtok(s, " \t")) != 0; s=0)
00399                      argvec[nargs_needed++]=s;
00400 
00401               s=malloc(strlen(p->host)+sizeof("!rmail"));
00402 
00403               if (!s)       clog_msg_errno();
00404               strcat(strcpy(s, p->host), "!rmail");
00405               argvec[nargs_needed++]=s;
00406 
00407               if (*p->sender)
00408               {
00409                      argvec[nargs_needed++]="-f";
00410                      argvec[nargs_needed++]=uucp_quote(p->sender);
00411               }
00412 
00413               for (i=0; i<nreceipients; i++)
00414               {
00415               const char *s=p->receipients[reciparray[i]*2+1];
00416 
00417                      argvec[nargs_needed++]=uucp_quote(s);
00418               }
00419               argvec[nargs_needed]=0;
00420 
00421               execv(UUX, (char **)argvec);
00422               perror("exec");
00423               exit(1);
00424               return;
00425        }
00426        close(pipefd2[1]);
00427        close(pipefd[0]);
00428 
00429        uuxpipe=pipefd[1];
00430        uuxerr=pipefd2[0];
00431 
00432        errbufptr=errbuf;
00433        errbufleft=sizeof(errbuf)-1;
00434 
00435        adderrbuf("uux: ", 0);
00436        saveerrbuf=errbufptr;
00437 
00438        signal(SIGPIPE, SIG_IGN);
00439 
00440        uucprwinfo_s.delhostt=delhostt;
00441        uucprwinfo_s.rewrite_func= rewrite_func;
00442 
00443        j=rw_rewrite_msg(fp, &dowrite, &call_rewrite_func, &uucprwinfo_s);
00444 
00445        if (j < 0)
00446        {
00447               clog_msg_prerrno();
00448               kill(pid, SIGTERM);
00449               signal(SIGALRM, alarm_sig);
00450               while (readuuxerr() == 0)
00451                      ;
00452               while ((pid2=wait(&waitstat)) != pid)
00453                      ;
00454 
00455               close(uuxpipe);
00456               waitstat=1;
00457        }
00458        else
00459        {
00460               close(uuxpipe);
00461 
00462               while (readuuxerr() == 0)
00463                      ;
00464 
00465               while ((pid2=wait(&waitstat)) != pid)
00466                      ;
00467        }
00468        close(uuxerr);
00469        close(fp);
00470 
00471        *errbufptr=0;
00472        if (waitstat)
00473        {
00474               if (saveerrbuf == errbufptr)
00475                      strcpy(errbuf,
00476                             "uux terminated with a non-0 exit code.");
00477        }
00478        else
00479        {
00480               if (saveerrbuf == errbufptr)
00481                      strcat(errbuf, " message accepted.");
00482        }
00483 
00484        last="";
00485        for (s=errbuf; (s=strtok(s, "\n")) != 0; s=0)
00486        {
00487               if (*last)
00488                      for (i=0; i<nreceipients; i++)
00489                      {
00490                             ctlfile_append_info(ctf,
00491                                    (unsigned)atol(p->receipients[
00492                                    reciparray[i]*2]), last);
00493                      }
00494               last=s;
00495        }
00496 
00497        for (i=0; i<nreceipients; i++)
00498        {
00499               ctlfile_append_reply(ctf,
00500                      (unsigned)atol(p->receipients[reciparray[i]*2]),
00501                      last,
00502                      waitstat ? COMCTLFILE_DELFAIL_NOTRACK:
00503                                  COMCTLFILE_DELSUCCESS,
00504                      waitstat == 0 ? "r":0);
00505        }
00506 }
00507 
00508 static int dowrite(const char *p, unsigned l, void *arg)
00509 {
00510        while (l)
00511        {
00512        fd_set fdr, fdw;
00513        int    m;
00514 
00515               FD_ZERO(&fdr);
00516               FD_ZERO(&fdw);
00517               FD_SET(uuxerr, &fdr);
00518               FD_SET(uuxpipe, &fdw);
00519 
00520               m=uuxerr;
00521               if (uuxpipe > m)     m=uuxpipe;
00522               if (select(m, &fdr, &fdw, 0, 0) <= 0)
00523               {
00524                      clog_msg_prerrno();
00525                      continue;
00526               }
00527 
00528               if (FD_ISSET(uuxerr, &fdr))
00529                      readuuxerr();
00530               if (FD_ISSET(uuxpipe, &fdw))
00531               {
00532               int    n;
00533 
00534                      n=write(uuxpipe, p, l);
00535                      if (n <= 0)   return (-1);
00536                      p += n;
00537                      l -= n;
00538               }
00539        }
00540        return (0);
00541 }