Back to index

courier  0.68.2
proxy.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2004-2005 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <errno.h>
00013 #include      <ctype.h>
00014 #include      <fcntl.h>
00015 #include      <time.h>
00016 #if    HAVE_UNISTD_H
00017 #include      <unistd.h>
00018 #endif
00019 #if    HAVE_SYS_WAIT_H
00020 #include      <sys/wait.h>
00021 #endif
00022 #include      <sys/socket.h>
00023 #include      <netinet/in.h>
00024 #include      <arpa/inet.h>
00025 #include      <netdb.h>
00026 #if HAVE_SYS_SELECT_H
00027 #include      <sys/select.h>
00028 #endif
00029 #include      <sys/time.h>
00030 #if HAVE_POLL
00031 #include      <sys/poll.h>
00032 #endif
00033 #include      <courierauthdebug.h>
00034 #include      "proxy.h"
00035 
00036 
00037 static int checkhostname(const char *host)
00038 {
00039        char hostbuf[256];
00040        const char *proxyhostname;
00041 
00042        if ((proxyhostname=getenv("PROXY_HOSTNAME")) != NULL)
00043        {
00044               if (strcmp(proxyhostname, host) == 0)
00045               {
00046                      courier_authdebug_printf("Proxy host %s is me, normal login.",
00047                                            host);
00048                      return -1;
00049               }
00050        }
00051 
00052        if (gethostname(hostbuf, sizeof(hostbuf)))
00053        {
00054               courier_authdebug_printf
00055                      ("gethostname failed: %s",
00056                       strerror(errno));
00057               return -1;
00058        }
00059 
00060        if (strcmp(hostbuf, host) == 0)
00061        {
00062               courier_authdebug_printf("Proxy host %s is me, normal login.",
00063                                     host);
00064               return -1;
00065        }
00066        return 0;
00067 }
00068 
00069 static int connect_host(struct proxyinfo *pi, const char *host);
00070 
00071 int connect_proxy(struct proxyinfo *pi)
00072 {
00073        char *h=strdup(pi->host);
00074        char *p, *q;
00075        int fd;
00076 
00077        if (!h)
00078        {
00079               courier_authdebug_printf("%s", strerror(errno));
00080               return -1;
00081        }
00082 
00083        for (p=h; *p;)
00084        {
00085               if (*p == ',')
00086               {
00087                      ++p;
00088                      continue;
00089               }
00090 
00091               for (q=p; *q; q++)
00092                      if (*q == ',')
00093                             break;
00094               if (*q)
00095                      *q++=0;
00096 
00097               fd=connect_host(pi, p);
00098               if (fd >= 0)
00099               {
00100                      free(h);
00101                      return fd;
00102               }
00103               p=q;
00104        }
00105        free(h);
00106        return -1;
00107 }
00108 
00109 
00110 static int proxyconnect(struct proxyinfo *pi,
00111                      int aftype,
00112                      void *addr,
00113                      size_t);
00114 
00115 #if HAVE_GETADDRINFO
00116 
00117 static int connect_host(struct proxyinfo *pi, const char *host)
00118 {
00119        int fd;
00120        char portbuf[40];
00121        int errcode;
00122        struct addrinfo hints, *res, *p;
00123 
00124        if (checkhostname(host))
00125               return (0);
00126 
00127        sprintf(portbuf, "%d", pi->port);
00128        memset(&hints, 0, sizeof(hints));
00129        hints.ai_family=PF_UNSPEC;
00130        hints.ai_socktype=SOCK_STREAM;
00131 
00132        errcode=getaddrinfo(host, portbuf, &hints, &res);
00133 
00134        if (errcode)
00135        {
00136               courier_authdebug_printf
00137                      ("getaddrinfo on proxyhost %s failed: %s",
00138                       pi->host, gai_strerror(errcode));
00139               return (-1);
00140        }
00141 
00142        for (p=res; p; p=p->ai_next)
00143        {
00144               if ((fd=proxyconnect(pi, p->ai_family,
00145                                  p->ai_addr,
00146                                  p->ai_addrlen))
00147                   >= 0)
00148               {
00149                      if ((*pi->connected_func)(fd, host,
00150                                             pi->void_arg))
00151                      {
00152                             close(fd);
00153                             courier_authdebug_printf
00154                                    ("Failed: %s.", strerror(errno));
00155                             continue;
00156                      }
00157                      freeaddrinfo(res);
00158                      return fd;
00159               }
00160        }
00161        freeaddrinfo(res);
00162        courier_authdebug_printf
00163               ("Connection to proxyhost %s failed.", host);
00164        return (-1);
00165 }
00166 
00167 #else
00168 static int connect_host(struct proxyinfo *pi, const char *host)
00169 {
00170        struct hostent *he;
00171        int i;
00172        int fd;
00173 
00174        if (checkhostname(host))
00175               return (0);
00176 
00177        he=gethostbyname(host);
00178 
00179        if (he == NULL)
00180        {
00181               courier_authdebug_printf
00182                      ("gethostbyname on proxyhost %s failed.",
00183                       host);
00184               return (-1);
00185        }
00186 
00187        for (i=0; he->h_addr_list[i]; i++)
00188        {
00189               switch (he->h_addrtype) {
00190               case AF_INET:
00191                      {
00192                             struct sockaddr_in sin;
00193 
00194                             memset(&sin, 0, sizeof(sin));
00195 
00196                             sin.sin_family=AF_INET;
00197 
00198                             memcpy(&sin.sin_addr, he->h_addr_list[i],
00199                                    sizeof(sin.sin_addr));
00200                             sin.sin_port=htons(pi->port);
00201 
00202                             fd=proxyconnect(pi, PF_INET, &sin,
00203                                           sizeof(sin));
00204                      }
00205                      break;
00206 #ifdef AF_INET6
00207               case AF_INET6:
00208                      {
00209                             struct sockaddr_in6 sin6;
00210 
00211                             memset(&sin6, 0, sizeof(sin6));
00212 
00213                             sin6.sin6_family=AF_INET6;
00214 
00215                             memcpy(&sin6.sin6_addr, he->h_addr_list[i],
00216                                    sizeof(sin6.sin6_addr));
00217 
00218                             sin6.sin6_port=htons(pi->port);
00219                             fd=proxyconnect(pi, PF_INET6, &sin6,
00220                                           sizeof(sin6));
00221                      }
00222                      break;
00223 #endif
00224               default:
00225                      courier_authdebug_printf
00226                             ("Unknown address family type %d",
00227                              he->h_addrtype);
00228                      continue;
00229               }
00230 
00231               if (fd >= 0)
00232               {
00233                      if ((*pi->connected_func)(fd, host,
00234                                             pi->void_arg))
00235                      {
00236                             close(fd);
00237                             courier_authdebug_printf
00238                                    ("Failed: %s.", strerror(errno));
00239                             continue;
00240                      }
00241                      return fd;
00242               }
00243        }
00244        courier_authdebug_printf
00245               ("Connection to proxyhost %s failed.", host);
00246        return (-1);
00247 }
00248 #endif
00249 
00250 #if HAVE_POLL
00251 
00252 static int proxy_waitfd(int fd, int waitWrite, const char *hostnamebuf)
00253 {
00254        struct pollfd pfd;
00255 
00256        memset(&pfd, 0, sizeof(pfd));
00257 
00258        pfd.fd=fd;
00259        pfd.events= waitWrite ? POLLOUT:POLLIN;
00260 
00261        if (poll(&pfd, 1, 30 * 1000) < 0)
00262        {
00263               courier_authdebug_printf
00264                      ("Poll failed while waiting to connect to %s: %s",
00265                       hostnamebuf, strerror(errno));
00266               return -1;
00267        }
00268 
00269        if (pfd.revents & (POLLOUT|POLLIN))
00270               return 0;
00271 
00272        courier_authdebug_printf
00273               ("Timeout/error connecting to %s", hostnamebuf);
00274        return -1;
00275 }
00276 
00277 #else
00278 static int proxy_waitfd(int fd, int waitWrite, const char *hostnamebuf)
00279 {
00280        fd_set fds;
00281        struct timeval tv;
00282 
00283        FD_ZERO(&fds);
00284        FD_SET(fd, &fds);
00285        tv.tv_sec=30;
00286        tv.tv_usec=0;
00287 
00288        if (select(fd+1, waitWrite ? NULL:&fds,
00289                  waitWrite ? &fds:NULL, NULL, &tv) < 0)
00290        {
00291               courier_authdebug_printf
00292                      ("Select failed while waiting to connect to %s: %s",
00293                       hostnamebuf, strerror(errno));
00294 
00295               return -1;
00296        }
00297 
00298        if (!FD_ISSET(fd, &fds))
00299        {
00300               courier_authdebug_printf
00301                      ("Timeout connecting to %s", hostnamebuf);
00302               return -1;
00303        }
00304 
00305        return 0;
00306 }
00307 #endif
00308 
00309 static int proxyconnect(struct proxyinfo *pi,
00310                      int pf,
00311                      void *addr,
00312                      size_t addrLen)
00313 {
00314        int fd;
00315        char hostnamebuf[256];
00316        int errcode;
00317        socklen_t errcode_l;
00318 
00319        struct sockaddr *sa=(struct sockaddr *)addr;
00320 
00321        switch (sa->sa_family) {
00322        case AF_INET:
00323               {
00324                      struct sockaddr_in *sin=(struct sockaddr_in *)sa;
00325 
00326                      strcpy(hostnamebuf, inet_ntoa(sin->sin_addr));
00327               }
00328               break;
00329 
00330 #ifdef AF_INET6
00331        case AF_INET6:
00332               {
00333                      struct sockaddr_in6 *sin6=
00334                             (struct sockaddr_in6 *)sa;
00335 
00336                      if (inet_ntop(AF_INET6, &sin6->sin6_addr,
00337                                   hostnamebuf,
00338                                   sizeof(hostnamebuf)) == NULL)
00339                             strcpy(hostnamebuf, "inet_ntop() failed");
00340               }
00341               break;
00342 #endif
00343        }
00344 
00345 
00346        fd=socket(pf, SOCK_STREAM, 0);
00347 
00348        if (fd < 0)
00349        {
00350               courier_authdebug_printf("socket: %s", strerror(errno));
00351               return (-1);
00352        }
00353 
00354        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0 ||
00355            fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
00356        {
00357               close(fd);
00358               courier_authdebug_printf("fcntl(socket): %s", strerror(errno));
00359        }
00360 
00361        if (connect(fd, addr, addrLen) == 0)
00362               return fd;
00363 
00364        if (errno != EINPROGRESS)
00365        {
00366               courier_authdebug_printf
00367                      ("Proxy connection to %s failed: %s",
00368                       hostnamebuf, strerror(errno));
00369               close(fd);
00370               return -1;
00371        }
00372 
00373        if (proxy_waitfd(fd, 1, hostnamebuf))
00374        {
00375               close(fd);
00376               return -1;
00377        }
00378 
00379        errcode_l=sizeof(errcode);
00380 
00381        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &errcode_l) < 0)
00382        {
00383               courier_authdebug_printf
00384                      ("getsockopt failed: %s", strerror(errno));
00385               close(fd);
00386               return -1;
00387        }
00388 
00389        if (errcode)
00390        {
00391               courier_authdebug_printf
00392                      ("Proxy connection to %s failed: %s", hostnamebuf,
00393                       strerror(errcode));
00394               close(fd);
00395               return -1;
00396        }
00397 
00398        return fd;
00399 }
00400 
00401 static int proxy_getch(int fd, struct proxybuf *pb)
00402 {
00403        if (pb->bufleft == 0)
00404        {
00405               int n;
00406 
00407               if (proxy_waitfd(fd, 0, "server"))
00408                      return -1;
00409 
00410               pb->bufptr=pb->buffer;
00411 
00412               n=read(fd, pb->buffer, sizeof(pb->buffer));
00413 
00414               if (n < 0)
00415               {
00416                      courier_authdebug_printf
00417                             ("Connection error: %s",
00418                              strerror(errno));
00419                      return -1;
00420               }
00421 
00422               if (n == 0)
00423               {
00424                      courier_authdebug_printf
00425                             ("Connection closed by remote host");
00426                      return -1;
00427               }
00428 
00429               pb->bufleft=(size_t)n;
00430        }
00431        --pb->bufleft;
00432        return ((int)(unsigned char)*pb->bufptr++);
00433 }
00434 
00435 int proxy_readline(int fd, struct proxybuf *pb,
00436                  char *linebuf,
00437                  size_t linebuflen,
00438                  int imapmode)
00439 {
00440        size_t i;
00441        int ch;
00442        int prevch;
00443 
00444        i=0;
00445 
00446        ch=0;
00447 
00448        do
00449        {
00450               prevch=ch;
00451 
00452               ch=proxy_getch(fd, pb);
00453 
00454               if (ch < 0)
00455                      return -1;
00456 
00457               if (i < linebuflen)
00458                      linebuf[i++]=(char)ch;
00459        } while (ch != '\n' || (imapmode && prevch != '\r'));
00460 
00461        if (i)
00462               linebuf[--i]=0;
00463 
00464        if (i && linebuf[i-1] == '\r')
00465               linebuf[--i]=0;
00466 
00467        DPRINTF("Received: %s", linebuf);
00468 
00469        return 0;
00470 }
00471 
00472 int proxy_write(int fd, const char *hostname,
00473               const char *buf, size_t buf_len)
00474 {
00475        DPRINTF("Sending: %s", buf);
00476 
00477        while (buf_len)
00478        {
00479               int n;
00480 
00481               if (proxy_waitfd(fd, 1, hostname))
00482                      return -1;
00483 
00484               n=write(fd, buf, buf_len);
00485 
00486               if (n < 0)
00487               {
00488                      courier_authdebug_printf
00489                             ("Error sending to %s: %s",
00490                              hostname, strerror(errno));
00491                      return -1;
00492               }
00493 
00494               if (n == 0)
00495               {
00496                      courier_authdebug_printf
00497                             ("Connection close by %s", hostname);
00498                      return -1;
00499               }
00500 
00501               buf_len -= n;
00502               buf += n;
00503        }
00504        return 0;
00505 }
00506 
00507 #if HAVE_POLL
00508 void proxyloop(int fd)
00509 {
00510        char stdin_buf[BUFSIZ];
00511        char stdout_buf[BUFSIZ];
00512 
00513        char *stdin_ptr=NULL;
00514        char *stdout_ptr=NULL;
00515        size_t stdin_left=0;
00516        size_t stdout_left=0;
00517        int n;
00518 
00519        struct pollfd pfd[2];
00520 
00521        if (fcntl(0, F_SETFL, O_NONBLOCK) ||
00522            fcntl(1, F_SETFL, O_NONBLOCK))
00523        {
00524               courier_authdebug_printf("fcntl: %s",
00525                                     strerror(errno));
00526               return;
00527        }
00528 
00529        do
00530        {
00531               memset(&pfd, 0, sizeof(pfd));
00532 
00533               if (stdin_left == 0)
00534               {
00535                      pfd[0].fd=0;
00536                      pfd[0].events=POLLIN;
00537               }
00538               else
00539               {
00540                      pfd[0].fd=fd;
00541                      pfd[0].events=POLLOUT;
00542               }
00543 
00544               if (stdout_left == 0)
00545               {
00546                      pfd[1].fd=fd;
00547                      pfd[1].events=POLLIN;
00548               }
00549               else
00550               {
00551                      pfd[1].fd=1;
00552                      pfd[1].events=POLLOUT;
00553               }
00554 
00555               n=1;
00556 
00557               if (poll(pfd, 2, -1) < 0)
00558               {
00559                      courier_authdebug_printf("poll: %s",
00560                                            strerror(errno));
00561                      continue;
00562               }
00563 
00564               if (stdin_left == 0)
00565               {
00566                      if (pfd[0].revents)
00567                      {
00568                             n=read(0, stdin_buf, sizeof(stdin_buf));
00569 
00570                             if (n > 0)
00571                             {
00572                                    stdin_ptr=stdin_buf;
00573                                    stdin_left=(size_t)n;
00574                             }
00575                      }
00576               }
00577               else if (pfd[0].revents)
00578               {
00579                      n=write(fd, stdin_ptr, stdin_left);
00580 
00581                      if (n > 0)
00582                      {
00583                             stdin_ptr += n;
00584                             stdin_left -= n;
00585                      }
00586               }
00587 
00588               if (n > 0)
00589               {
00590                      if (stdout_left == 0)
00591                      {
00592                             if (pfd[1].revents)
00593                             {
00594                                    n=read(fd, stdout_buf,
00595                                           sizeof(stdout_buf));
00596                             
00597                                    if (n > 0)
00598                                    {
00599                                           stdout_ptr=stdout_buf;
00600                                           stdout_left=(size_t)n;
00601                                    }
00602                             }
00603                      } else if (pfd[1].revents)
00604                      {
00605                             n=write(1, stdout_ptr, stdout_left);
00606 
00607                             if (n > 0)
00608                             {
00609                                    stdout_ptr += n;
00610                                    stdout_left -= n;
00611                             }
00612                      }
00613               }
00614        } while (n > 0);
00615 
00616        if (n < 0)
00617               courier_authdebug_printf("%s", strerror(errno));
00618 }
00619 
00620 #else
00621 void proxyloop(int fd)
00622 {
00623        char stdin_buf[BUFSIZ];
00624        char stdout_buf[BUFSIZ];
00625 
00626        char *stdin_ptr=NULL;
00627        char *stdout_ptr=NULL;
00628        size_t stdin_left=0;
00629        size_t stdout_left=0;
00630        int n;
00631 
00632        fd_set fdr, fdw;
00633 
00634        if (fcntl(0, F_SETFL, O_NONBLOCK) ||
00635            fcntl(1, F_SETFL, O_NONBLOCK))
00636        {
00637               courier_authdebug_printf("fcntl: %s",
00638                                     strerror(errno));
00639               return;
00640        }
00641 
00642        do
00643        {
00644               FD_ZERO(&fdr);
00645               FD_ZERO(&fdw);
00646 
00647               if (stdin_left == 0)
00648                      FD_SET(0, &fdr);
00649               else
00650                      FD_SET(fd, &fdw);
00651 
00652               if (stdout_left == 0)
00653                      FD_SET(fd, &fdr);
00654               else
00655                      FD_SET(1, &fdw);
00656 
00657               n=1;
00658 
00659               if (select(fd+1, &fdr, &fdw, NULL, NULL) < 0)
00660               {
00661                      courier_authdebug_printf("select: %s",
00662                                            strerror(errno));
00663                      continue;
00664               }
00665 
00666               if (stdin_left == 0)
00667               {
00668                      if (FD_ISSET(0, &fdr))
00669                      {
00670                             n=read(0, stdin_buf, sizeof(stdin_buf));
00671 
00672                             if (n > 0)
00673                             {
00674                                    stdin_ptr=stdin_buf;
00675                                    stdin_left=(size_t)n;
00676                             }
00677                      }
00678               }
00679               else if (FD_ISSET(fd, &fdw))
00680               {
00681                      n=write(fd, stdin_ptr, stdin_left);
00682 
00683                      if (n > 0)
00684                      {
00685                             stdin_ptr += n;
00686                             stdin_left -= n;
00687                      }
00688               }
00689 
00690               if (n > 0)
00691               {
00692                      if (stdout_left == 0)
00693                      {
00694                             if (FD_ISSET(fd, &fdr))
00695                             {
00696                                    n=read(fd, stdout_buf,
00697                                           sizeof(stdout_buf));
00698                             
00699                                    if (n > 0)
00700                                    {
00701                                           stdout_ptr=stdout_buf;
00702                                           stdout_left=(size_t)n;
00703                                    }
00704                             }
00705                      } else if (FD_ISSET(1, &fdw))
00706                      {
00707                             n=write(1, stdout_ptr, stdout_left);
00708 
00709                             if (n > 0)
00710                             {
00711                                    stdout_ptr += n;
00712                                    stdout_left -= n;
00713                             }
00714                      }
00715               }
00716        } while (n > 0);
00717 
00718        if (n < 0)
00719               courier_authdebug_printf("%s", strerror(errno));
00720 }
00721 #endif