Back to index

courier  0.68.2
pop3login.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2008 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #undef PACKAGE
00008 #undef VERSION
00009 #include      "config.h"
00010 #endif
00011 #include      <stdio.h>
00012 #include      <string.h>
00013 #include      <stdlib.h>
00014 #include      <signal.h>
00015 #include      <ctype.h>
00016 #include      <fcntl.h>
00017 #if    HAVE_UNISTD_H
00018 #include      <unistd.h>
00019 #endif
00020 #include      <netinet/in.h>
00021 #include      <netdb.h>
00022 #include      "waitlib/waitlib.h"
00023 #include      "proxy.h"
00024 
00025 #include      <courierauth.h>
00026 #include      <courierauthdebug.h>
00027 #include      <courierauthsasl.h>
00028 #include      "tcpd/spipe.h"
00029 #include      "numlib/numlib.h"
00030 #include      "tcpd/tlsclient.h"
00031 
00032 
00033 extern void pop3dcapa();
00034 extern int have_starttls();
00035 extern int tls_required();
00036 extern const char *pop3_externalauth();
00037 
00038 static const char *pop3d;
00039 static const char *defaultmaildir;
00040 
00041 static int    starttls()
00042 {
00043        char *argvec[4];
00044 
00045        char localfd_buf[NUMBUFSIZE+40];
00046        char buf2[NUMBUFSIZE];
00047        struct couriertls_info cinfo;
00048        int pipefd[2];
00049 
00050        if (libmail_streampipe(pipefd))
00051        {
00052               printf("-ERR libmail_streampipe() failed.\r\n");
00053               return (-1);
00054        }
00055 
00056        couriertls_init(&cinfo);
00057        fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
00058 
00059        strcat(strcpy(localfd_buf, "-localfd="),
00060               libmail_str_size_t(pipefd[1], buf2));
00061 
00062        argvec[0]=localfd_buf;
00063        argvec[1]="-tcpd";
00064        argvec[2]="-server";
00065        argvec[3]=NULL;
00066 
00067        printf("+OK Begin SSL/TLS negotiation now.\r\n");
00068        fflush(stdout);
00069 
00070        if (couriertls_start(argvec, &cinfo))
00071        {
00072               close(pipefd[0]);
00073               close(pipefd[1]);
00074               printf("-ERR STARTTLS failed: %s\r\n",
00075                      cinfo.errmsg);
00076               couriertls_destroy(&cinfo);
00077               return (-1);
00078        }
00079 
00080        couriertls_export_subject_environment(&cinfo);
00081        couriertls_destroy(&cinfo);
00082 
00083        close(pipefd[1]);
00084        close(0);
00085        close(1);
00086        if (dup(pipefd[0]) != 0 || dup(pipefd[0]) != 1)
00087        {
00088               perror("dup");
00089               exit(1);
00090        }
00091        close(pipefd[0]);
00092 
00093        putenv("POP3_STARTTLS=NO");
00094        putenv("POP3_TLS_REQUIRED=0");
00095        putenv("POP3_TLS=1");
00096        return (0);
00097 }
00098 
00099 static char *authresp(const char *s, void *dummy)
00100 {
00101 char   *p;
00102 char   buf[BUFSIZ];
00103 
00104        printf("+ %s\r\n", s);
00105        fflush(stdout);
00106 
00107        if (fgets(buf, sizeof(buf), stdin) == 0)  return (0);
00108        if ((p=strchr(buf, '\n')) == 0)    return (0);
00109        if (p > buf && p[-1] == '\r')      --p;
00110        *p=0;
00111 
00112        p=strdup(buf);
00113        if (!p)
00114        {
00115               perror("malloc");
00116               return (0);
00117        }
00118        return (p);
00119 }
00120 
00121 struct pop3proxyinfo {
00122        const char *uid;
00123        const char *pwd;
00124 };
00125 
00126 static int login_pop3(int, const char *, void *);
00127 
00128 static int login_callback(struct authinfo *ainfo, void *dummy)
00129 {
00130        int rc;
00131        char *p;
00132 
00133        p=getenv("POP3_PROXY");
00134 
00135        if (p && atoi(p))
00136        {
00137               if (ainfo->options == NULL ||
00138                   (p=auth_getoption(ainfo->options,
00139                                   "mailhost")) == NULL)
00140               {
00141                      fprintf(stderr,"WARN: proxy enabled, but no proxy"
00142                              " host defined for %s\n",
00143                              ainfo->address);
00144 
00145                      /* Fallthru to account login */
00146 
00147               }
00148               else if (ainfo->clearpasswd == NULL)
00149               {
00150                      free(p);
00151                      fprintf(stderr, "WARN: proxy enabled, but no password"
00152                              " for %s\n", ainfo->address);
00153                      return -1;
00154               }
00155               else
00156               {
00157                      struct proxyinfo pi;
00158                      struct pop3proxyinfo ppi;
00159                      struct servent *se;
00160                      int fd;
00161 
00162                      se=getservbyname("pop3", NULL);
00163 
00164                      pi.host=p;
00165                      pi.port=se ? ntohs(se->s_port):110;
00166 
00167                      ppi.uid=ainfo->address;
00168                      ppi.pwd=ainfo->clearpasswd;
00169 
00170                      pi.connected_func=login_pop3;
00171                      pi.void_arg=&ppi;
00172 
00173                      if ((fd=connect_proxy(&pi)) < 0)
00174                      {
00175                             free(p);
00176                             return -1;
00177                      }
00178                      free(p);
00179                      if (fd > 0)
00180                      {
00181                             alarm(0);
00182                             proxyloop(fd);
00183                             exit(0);
00184                      }
00185 
00186                      /* FALLTHRU */
00187               }
00188        }
00189 
00190        rc=auth_callback_default(ainfo);
00191 
00192        if (rc == 0)
00193        {
00194               char *p=malloc(sizeof("OPTIONS=") + strlen(ainfo->options ?
00195                                                     ainfo->options:""));
00196 
00197               if (p)
00198               {
00199                      strcat(strcpy(p, "OPTIONS="),
00200                             ainfo->options ? ainfo->options:"");
00201                      putenv(p);
00202 
00203                      p=malloc(sizeof("AUTHENTICATED=")+
00204                              strlen(ainfo->address));
00205                      if (p)
00206                      {
00207                             strcat(strcpy(p, "AUTHENTICATED="),
00208                                    ainfo->address);
00209                             putenv(p);
00210 
00211                             alarm(0);
00212                             execl(pop3d, pop3d,
00213                                   ainfo->maildir ?
00214                                   ainfo->maildir:defaultmaildir,
00215                                   NULL);
00216                             fprintf(stderr, "ERR: exec(%s) failed!!\n",
00217                                                   pop3d);
00218                      }
00219               }
00220        }
00221 
00222        return (rc);
00223 }
00224 
00225 int main(int argc, char **argv)
00226 {
00227 char   *user=0;
00228 char   *p;
00229 char   buf[BUFSIZ];
00230 int    c;
00231 const  char *ip=getenv("TCPREMOTEIP");
00232 char authservice[40];
00233 char *q ;
00234 
00235 #ifdef HAVE_SETVBUF_IOLBF
00236        setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
00237 #endif
00238 
00239        if (!ip || !*ip)
00240        {
00241               ip="127.0.0.1";
00242        }
00243 
00244        if (argc != 3)
00245        {
00246               printf("-ERR pop3login requires exactly two arguments.\r\n");
00247               fflush(stdout);
00248               exit(1);
00249        }
00250 
00251        pop3d=argv[1];
00252        defaultmaildir=argv[2];
00253 
00254        courier_authdebug_login_init();
00255 
00256        fprintf(stderr, "DEBUG: Connection, ip=[%s]\n", ip);
00257        printf("+OK Hello there.\r\n");
00258 
00259        fflush(stdout);
00260        fflush(stderr);
00261        alarm(60);
00262        while (fgets(buf, sizeof(buf), stdin))
00263        {
00264               c=1;
00265               for (p=buf; *p; p++)
00266               {
00267                      if (*p == '\n')
00268                             break;
00269 
00270                      if (*p == ' ' || *p == '\t')       c=0;
00271                      if (c)
00272                             *p=toupper((int)(unsigned char)*p);
00273               }
00274 
00275               if (*p)
00276                      *p=0;
00277               else while ((c=getchar()) != EOF && c != '\n')
00278                      ;
00279               p=strtok(buf, " \t\r");
00280               if (p)
00281               {
00282                      courier_authdebug_login( 1, "command=%s", p );
00283 
00284                      if ( strcmp(p, "QUIT") == 0)
00285                      {
00286                             fprintf(stderr, "INFO: LOGOUT, ip=[%s]\n",
00287                                    ip);
00288                             fflush(stderr);
00289                             printf("+OK Better luck next time.\r\n");
00290                             fflush(stdout);
00291                             break;
00292                      }
00293 
00294                      if ( strcmp(p, "USER") == 0)
00295                      {
00296                             if (tls_required())
00297                             {
00298                                    printf("-ERR TLS required to log in.\r\n");
00299                                    fflush(stdout);
00300                                    continue;
00301                             }
00302 
00303                             p=strtok(0, "\r\n");
00304                             if (p)
00305                             {
00306                                    if (user)     free(user);
00307                                    if ((user=malloc(strlen(p)+1)) == 0)
00308                                    {
00309                                           printf("-ERR Server out of memory, aborting connection.\r\n");
00310                                           fflush(stdout);
00311                                           perror("malloc");
00312                                           exit(1);
00313                                    }
00314                                    strcpy(user, p);
00315                                    printf("+OK Password required.\r\n");
00316                                    fflush(stdout);
00317                                    continue;
00318                             }
00319                      } else if (strcmp(p, "CAPA") == 0)
00320                      {
00321                             pop3dcapa();
00322                             continue;
00323                      } else if (strcmp(p, "STLS") == 0)
00324                      {
00325                             if (!have_starttls())
00326                             {
00327                                    printf("-ERR TLS support not available.\r\n");
00328                                    fflush(stdout);
00329                                    continue;
00330                             }
00331                             starttls();
00332                             fflush(stdout);
00333                             continue;
00334                      } else if (strcmp(p, "AUTH") == 0)
00335                      {
00336                             char *authtype, *authdata;
00337                             char   *method=strtok(0, " \t\r");
00338 
00339                             if (tls_required())
00340                             {
00341                                    printf("-ERR TLS required to log in.\r\n");
00342                                    fflush(stdout);
00343                                    continue;
00344                             }
00345 
00346                             if (method)
00347                             {
00348                                    char *initreply=strtok(0, " \t\r");
00349                                    int    rc;
00350                                    char *p;
00351 
00352                                    for (p=method; *p; p++)
00353                                           *p=toupper(*p);
00354 
00355                                    if (initreply &&
00356                                        strcmp(initreply, "=") == 0)
00357                                           initreply="";
00358 
00359                                    rc=auth_sasl_ex(method, initreply,
00360                                                  pop3_externalauth(),
00361                                                  authresp,
00362                                                  NULL,
00363                                                  &authtype,
00364                                                  &authdata);
00365 
00366                                    if (rc == 0)
00367                                    {
00368                                           strcat(strcpy(authservice, "AUTHSERVICE"),getenv("TCPLOCALPORT"));
00369                                           q=getenv(authservice);
00370                                           if (!q || !*q)
00371                                                  q="pop3";
00372 
00373                                           rc=auth_generic(q,
00374                                                       authtype,
00375                                                       authdata,
00376                                                       login_callback,
00377                                                       NULL);
00378                                           free(authtype);
00379                                           free(authdata);
00380                                    }
00381 
00382                                    courier_safe_printf("INFO: LOGIN "
00383                                           "FAILED, method=%s, ip=[%s]",
00384                                           method, ip);
00385                                    if (rc == AUTHSASL_ABORTED)
00386                                        printf("-ERR Authentication aborted.\r\n");
00387                                    else if (rc > 0)
00388                                    {
00389                                        perror("ERR: authentication error");
00390                                        printf("-ERR Temporary problem, please try again later\r\n");
00391                                        fflush(stdout);
00392                                        exit(1);
00393                                    }                                  
00394                                    else
00395                                    {
00396                                        sleep(5);
00397                                        printf("-ERR Authentication failed.\r\n");
00398                                    }
00399 
00400                                    fflush(stdout);
00401                                    continue;
00402                             }
00403                      } else if (strcmp(p, "PASS") == 0)
00404                      {
00405                             int rc;
00406 
00407                             p=strtok(0, "\r\n");
00408 
00409                             if (!user || p == 0)
00410                             {
00411                                    printf("-ERR USER/PASS required.\r\n");
00412                                    fflush(stdout);
00413                                    continue;
00414                             }
00415 
00416                             strcat(strcpy(authservice, "AUTHSERVICE"),getenv("TCPLOCALPORT"));
00417                             q=getenv(authservice);
00418                             if (!q || !*q)
00419                                    q="pop3";
00420 
00421                             rc=auth_login(q, user, p, login_callback, NULL);
00422                             courier_safe_printf("INFO: LOGIN "
00423                                    "FAILED, user=%s, ip=[%s]",
00424                                    user, ip);
00425                             if (rc > 0)
00426                             {
00427                                    perror("ERR: authentication error");
00428                                    printf("-ERR Temporary problem, please try again later\r\n");
00429                                    fflush(stdout);
00430                                    exit(1);
00431                             }
00432                             sleep(5);
00433                             printf("-ERR Login failed.\r\n");
00434                             fflush(stdout);
00435                             continue;
00436                      }
00437               }
00438               printf("-ERR Invalid command.\r\n");
00439               fflush(stdout);
00440        }
00441        fprintf(stderr, "DEBUG: Disconnected, ip=[%s]\n", ip);
00442        exit(0);
00443        return (0);
00444 }
00445 
00446 static int login_pop3(int fd, const char *hostname, void *void_arg)
00447 {
00448        struct pop3proxyinfo *ppi=(struct pop3proxyinfo *)void_arg;
00449        struct proxybuf pb;
00450        char linebuf[256];
00451        char *cmd;
00452 
00453        DPRINTF("Proxy connected to %s", hostname);
00454 
00455        memset(&pb, 0, sizeof(pb));
00456 
00457        if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
00458               return -1;
00459 
00460        DPRINTF("%s: %s", hostname, linebuf);
00461 
00462        if (linebuf[0] != '+')
00463        {
00464               fprintf(stderr, "WARN: Did not receive greeting from %s\n",
00465                      hostname);
00466               return -1;
00467        }
00468 
00469        cmd=malloc(strlen(ppi->uid) + strlen(ppi->pwd)+100);
00470        /* Should be enough */
00471 
00472        if (!cmd)
00473               return -1;
00474 
00475        sprintf(cmd, "USER %s\r\n", ppi->uid);
00476 
00477        if (proxy_write(fd, hostname, cmd, strlen(cmd)))
00478        {
00479               free(cmd);
00480               return -1;
00481        }
00482 
00483        if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
00484        {
00485               free(cmd);
00486               return -1;
00487        }
00488 
00489        DPRINTF("%s: %s", hostname, linebuf);
00490 
00491        if (linebuf[0] != '+')
00492        {
00493               free(cmd);
00494               fprintf(stderr, "WARN: Login userid rejected by %s\n",
00495                      hostname);
00496               return -1;
00497        }
00498 
00499        sprintf(cmd, "PASS %s\r\n", ppi->pwd);
00500 
00501        if (proxy_write(fd, hostname, cmd, strlen(cmd)))
00502        {
00503               free(cmd);
00504               return -1;
00505        }
00506 
00507        if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
00508        {
00509               free(cmd);
00510               return -1;
00511        }
00512 
00513        DPRINTF("%s: %s", hostname, linebuf);
00514 
00515        if (linebuf[0] != '+')
00516        {
00517               free(cmd);
00518               fprintf(stderr, "WARN: Login password rejected by %s\n",
00519                      hostname);
00520               return -1;
00521        }
00522 
00523        free(cmd);
00524        if (fcntl(1, F_SETFL, 0) < 0 ||
00525            (printf("+OK Connected to proxy server.\r\n"), fflush(stdout)) < 0)
00526               return -1;
00527 
00528        return 0;
00529 }