home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / cknssl.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  37KB  |  972 lines

  1. /*
  2.   Author: Jeffrey E Altman (jaltman@secure-endpoints.com),
  3.             Secure Endpoints Inc., New York City.
  4.  
  5.   Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New
  6.   York.  All rights reserved.
  7. */
  8.  
  9. #define SECURITY_WIN32
  10. #include <sspi.h>
  11. #if(_WIN32_WINNT < 0x0400)
  12. #define UNISP_NAME    "Microsoft Unified Security Protocol Provider"
  13. #else
  14. #include <wincrypt.h>
  15. ALGIDDEF
  16. #include <schnlsp.h>
  17. #endif
  18. #include <issperr.h>
  19.  
  20. #define SSLBUFLEN 8192
  21.  
  22.  
  23. /* SSL I/O stream */
  24.  
  25. typedef struct ssl_stream {
  26.   TCPSTREAM *tcpstream;         /* TCP stream */
  27.   CredHandle cred;              /* SSL credentials */
  28.   CtxtHandle context;           /* SSL context */
  29.                                 /* stream encryption sizes */
  30.   SecPkgContext_StreamSizes sizes;
  31.   int ictr;                     /* input counter */
  32.   char *iptr;                   /* input pointer */
  33.   int iextractr;                /* extra input counter */
  34.   char *iextraptr;              /* extra input pointer */
  35.   char *ibuf;                   /* input buffer */
  36.   char *obuf;                   /* output buffer */
  37. } SSLSTREAM;
  38.  
  39.  
  40. /* SSL stdio stream */
  41.  
  42. typedef struct ssl_stdiostream {
  43.   SSLSTREAM *sslstream;         /* SSL stream */
  44.   int octr;                     /* output counter */
  45.   char *optr;                   /* output pointer */
  46.   char obuf[SSLBUFLEN];         /* output buffer */
  47. } SSLSTDIOSTREAM;
  48.  
  49.  
  50. /* SSL driver */
  51.  
  52. struct ssl_driver {             /* must parallel NETDRIVER in mail.h */
  53.   SSLSTREAM *(*open) (char *host,char *service,unsigned long port);
  54.   SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
  55.   char *(*getline) (SSLSTREAM *stream);
  56.   long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer);
  57.   long (*soutr) (SSLSTREAM *stream,char *string);
  58.   long (*sout) (SSLSTREAM *stream,char *string,unsigned long size);
  59.   void (*close) (SSLSTREAM *stream);
  60.   char *(*host) (SSLSTREAM *stream);
  61.   char *(*remotehost) (SSLSTREAM *stream);
  62.   unsigned long (*port) (SSLSTREAM *stream);
  63.   char *(*localhost) (SSLSTREAM *stream);
  64. };
  65.  
  66. /* Function prototypes */
  67.  
  68. void ssl_onceonlyinit (void);
  69. SSLSTREAM *ssl_open (char *host,char *service,unsigned long port);
  70. SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf);
  71. char *ssl_getline (SSLSTREAM *stream);
  72. long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer);
  73. long ssl_getdata (SSLSTREAM *stream);
  74. long ssl_soutr (SSLSTREAM *stream,char *string);
  75. long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size);
  76. void ssl_close (SSLSTREAM *stream);
  77. long ssl_abort (SSLSTREAM *stream);
  78. char *ssl_host (SSLSTREAM *stream);
  79. char *ssl_remotehost (SSLSTREAM *stream);
  80. unsigned long ssl_port (SSLSTREAM *stream);
  81. char *ssl_localhost (SSLSTREAM *stream);
  82. long auth_plain_valid (void);
  83. long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
  84.                         NETMBX *mb,void *stream,unsigned long *trial,
  85.                         char *user);
  86. char *auth_plain_server (authresponse_t responder,int argc,char *argv[]);
  87. void Server_init (char *server,char *service,char *altservice,char *sasl,
  88.                   void *clkint,void *kodint,void *hupint,void *trmint);
  89. long Server_input_wait (long seconds);
  90. SSLSTDIOSTREAM *ssl_server_init (char *server);
  91. int ssl_getchar (void);
  92. char *ssl_gets (char *s,int n);
  93. int ssl_putchar (int c);
  94. int ssl_puts (char *s);
  95. int ssl_flush (void);
  96.  
  97. /* Secure Sockets Layer network driver dispatch */
  98.  
  99. static struct ssl_driver ssldriver = {
  100.   ssl_open,                     /* open connection */
  101.   ssl_aopen,                    /* open preauthenticated connection */
  102.   ssl_getline,                  /* get a line */
  103.   ssl_getbuffer,                /* get a buffer */
  104.   ssl_soutr,                    /* output pushed data */
  105.   ssl_sout,                     /* output string */
  106.   ssl_close,                    /* close connection */
  107.   ssl_host,                     /* return host name */
  108.   ssl_remotehost,               /* return remote host name */
  109.   ssl_port,                     /* return port number */
  110.   ssl_localhost                 /* return local host name */
  111. };
  112.  
  113.                                 /* security function table */
  114. static SecurityFunctionTable *sslfunc = NIL;
  115.                                 /* message encryption */
  116. static ENCRYPT_MESSAGE_FN sslencrypt = NIL;
  117.                                 /* message decryption */
  118. static DECRYPT_MESSAGE_FN ssldecrypt = NIL;
  119. static char *sslpnm = NIL;      /* SSL package name */
  120. static unsigned long ssltsz = 0;/* SSL maximum token length */
  121.                                 /* non-NIL if doing SSL primary I/O */
  122. static SSLSTDIOSTREAM *sslstdio = NIL;
  123.  
  124.  
  125. /* Secure sockets layer authenticator */
  126.  
  127. AUTHENTICATOR auth_ssl = {
  128.   NIL,                          /* insecure authenticator */
  129.   "PLAIN",                      /* authenticator name */
  130.   auth_plain_valid,             /* check if valid */
  131.   auth_plain_client,            /* client method */
  132.   auth_plain_server,            /* server method */
  133.   NIL                           /* next authenticator */
  134. };
  135.  
  136. /* One-time SSL initialization */
  137.  
  138. static int sslonceonly = 0;
  139.  
  140. void ssl_onceonlyinit (void)
  141. {
  142.     if (!sslonceonly++) {               /* only need to call it once */
  143.         HINSTANCE lib;
  144.         FARPROC pi;
  145.         ULONG np;
  146.         SecPkgInfo *pp;
  147.         int i;
  148.                                 /* get security library */
  149.         if (((lib = LoadLibrary ("schannel.dll")) ||
  150.               (lib = LoadLibrary ("security.dll"))) &&
  151.              (pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
  152.              (sslfunc = (SecurityFunctionTable *) pi ()) &&
  153.              !(sslfunc->EnumerateSecurityPackages (&np,&pp)))
  154.         {
  155.                                 /* look for an SSL package */
  156.             for (i = 0; (i < (int) np) && !sslpnm; i++)
  157.                 if (!strcmp (pp[i].Name,UNISP_NAME)) {
  158.                     /* note maximum token size and name */
  159.                     ssltsz = pp[i].cbMaxToken;
  160.                     sslpnm = cpystr (pp[i].Name);
  161.                     /* Shh!  It's a military secret!! */
  162.                     sslencrypt = sslfunc->Reserved3;
  163.                     /* so is this!!! */
  164.                     ssldecrypt = sslfunc->Reserved4;
  165.                 }
  166.         }
  167.     }
  168. }
  169.  
  170. /* SSL open
  171.  * Accepts: host name
  172.  *          contact service name
  173.  *          contact port number
  174.  * Returns: SSL stream if success else NIL
  175.  */
  176.  
  177. SSLSTREAM *
  178. ssl_open (char *host,char *service,unsigned long port)
  179. {
  180.     SECURITY_STATUS e;
  181.     ULONG a;
  182.     TimeStamp t;
  183.     SecBuffer ibuf[2],obuf[1];
  184.     SecBufferDesc ibufs,obufs;
  185.     SSLSTREAM *stream = NIL;
  186.     ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
  187.         ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
  188.             ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR;
  189.     int done = 0;
  190.     TCPSTREAM *ts = tcp_open (host,service,port);
  191.     int failed = T;
  192.     if (ts) {                   /* got a TCPSTREAM? */
  193.         char *buf = (char *) fs_get (ssltsz);
  194.         unsigned long size = 0;
  195.                                 /* instantiate SSLSTREAM */
  196.         (stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
  197.                                          sizeof (SSLSTREAM)))->tcpstream = ts;
  198.  
  199.         if (sslfunc->AcquireCredentialsHandle
  200.              (NIL,sslpnm,SECPKG_CRED_OUTBOUND,NIL,NIL,NIL,NIL,&stream->cred,&t) ==
  201.              SEC_E_OK) {                /* acquire credentials */
  202.             while (!done) {             /* negotiate negotiate security context */
  203.                 /* initialize buffers */
  204.                 ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
  205.                 ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
  206.                 obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
  207.                 ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
  208.                 ibuf[1].BufferType = SECBUFFER_EMPTY;
  209.                                 /* initialize buffer descriptors */
  210.                 ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
  211.                 ibufs.cBuffers = 2; obufs.cBuffers = 1;
  212.                 ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
  213.                                 /* negotiate security */
  214.                 e = sslfunc->InitializeSecurityContext
  215.                     (&stream->cred,size ? &stream->context : NIL,0,req,0,
  216.                       SECURITY_NETWORK_DREP,size ? &ibufs : NIL,0,
  217.                       &stream->context,&obufs,&a,&t);
  218.                                 /* have an output buffer we need to send? */
  219.                 if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
  220.                     if ((done >= 0) &&  /* do so if in good state */
  221.                          !tcp_sout (stream->tcpstream,obuf[0].pvBuffer,
  222.                                      obuf[0].cbBuffer)) done = -1;
  223.                                 /* free the buffer */
  224.                     sslfunc->FreeContextBuffer (obuf[0].pvBuffer);
  225.                 }
  226.  
  227.                 switch (e) {            /* negotiation state */
  228.                 case SEC_I_INCOMPLETE_CREDENTIALS:
  229.                     break;              /* server wants client auth */
  230.                 case SEC_E_OK:
  231.                     done = T;           /* got security context, all done */
  232.                     /* any data to be regurgitated? */
  233.                     if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
  234.                         /* yes, set this as the new data */
  235.                         memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
  236.                                   buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
  237.                         stream->tcpstream->ictr = ibuf[1].cbBuffer;
  238.                     }
  239.                     if (sslfunc->QueryContextAttributes
  240.                          (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes) ==
  241.                          SEC_E_OK) {    /* get stream sizes */
  242.                         /* maximum SSL buffer size */
  243.                         size_t i = stream->sizes.cbHeader +
  244.                             stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
  245.                         /* make buffers */
  246.                         stream->ibuf = (char *) fs_get (i);
  247.                         stream->obuf = (char *) fs_get (i);
  248.                         failed = NIL;   /* mark success */
  249.                     }
  250.                     break;
  251.                 case SEC_I_CONTINUE_NEEDED:
  252.                     if (size) {         /* continue, read any data? */
  253.                         /* yes, anything regurgiated back to us? */
  254.                         if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
  255.                             /* yes, set this as the new data */
  256.                             memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
  257.                             size = ibuf[1].cbBuffer;
  258.                             break;
  259.                         }
  260.                         size = 0;               /* otherwise, read more stuff from server */
  261.                     }
  262.                 case SEC_E_INCOMPLETE_MESSAGE:
  263.                     /* need to read more data from server */
  264.                     if (tcp_getdata (stream->tcpstream)) {
  265.                         memcpy(buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
  266.                         size += stream->tcpstream->ictr;
  267.                         /* empty it from TCP's buffers */
  268.                         stream->tcpstream->iptr += stream->tcpstream->ictr;
  269.                         stream->tcpstream->ictr = 0;
  270.                         break;
  271.                     }
  272.                 default:                /* anything else is an error */
  273.                     done = -1;
  274.                     break;
  275.                 }
  276.             }
  277.         }
  278.  
  279.         if (failed) {           /* failed to negotiate SSL */
  280.             /* only give error if not silent */
  281.             if (!(port & 0x80000000)) {
  282.                 sprintf (buf,"Can't establish SSL session to %.80s/%.80s,%ld",
  283.                           host,service ? service + 1 : "SSL",port);
  284.                 mm_log (buf,ERROR);
  285.             }
  286.             ssl_close (stream); /* failed to do SSL */
  287.         }
  288.         fs_give ((void **) &buf);       /* flush temporary buffer */
  289.     }
  290.     return failed ? NIL :  stream;
  291. }
  292.  
  293.  
  294. /* SSL authenticated open
  295.  * Accepts: host name
  296.  *          service name
  297.  *          returned user name buffer
  298.  * Returns: SSL stream if success else NIL
  299.  */
  300.  
  301. SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
  302. {
  303.   return NIL;                   /* don't use this mechanism with SSL */
  304. }
  305.  
  306. /* SSL receive line
  307.  * Accepts: SSL stream
  308.  * Returns: text line string or NIL if failure
  309.  */
  310.  
  311. char *ssl_getline (SSLSTREAM *stream)
  312. {
  313.   int n,m;
  314.   char *st,*ret,*stp;
  315.   char c = '\0';
  316.   char d;
  317.                                 /* make sure have data */
  318.   if (!ssl_getdata (stream)) return NIL;
  319.   st = stream->iptr;            /* save start of string */
  320.   n = 0;                        /* init string count */
  321.   while (stream->ictr--) {      /* look for end of line */
  322.     d = *stream->iptr++;        /* slurp another character */
  323.     if ((c == '\015') && (d == '\012')) {
  324.       ret = (char *) fs_get (n--);
  325.       memcpy (ret,st,n);        /* copy into a free storage string */
  326.       ret[n] = '\0';            /* tie off string with null */
  327.       return ret;
  328.     }
  329.     n++;                        /* count another character searched */
  330.     c = d;                      /* remember previous character */
  331.   }
  332.                                 /* copy partial string from buffer */
  333.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  334.                                 /* get more data from the net */
  335.   if (!ssl_getdata (stream)) fs_give ((void **) &ret);
  336.                                 /* special case of newline broken by buffer */
  337.   else if ((c == '\015') && (*stream->iptr == '\012')) {
  338.     stream->iptr++;             /* eat the line feed */
  339.     stream->ictr--;
  340.     ret[n - 1] = '\0';          /* tie off string with null */
  341.   }
  342.                                 /* else recurse to get remainder */
  343.   else if (st = ssl_getline (stream)) {
  344.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  345.     memcpy (ret,stp,n);         /* copy first part */
  346.     memcpy (ret + n,st,m);      /* and second part */
  347.     fs_give ((void **) &stp);   /* flush first part */
  348.     fs_give ((void **) &st);    /* flush second part */
  349.     ret[n + m] = '\0';          /* tie off string with null */
  350.   }
  351.   return ret;
  352. }
  353.  
  354. /* SSL receive buffer
  355.  * Accepts: SSL stream
  356.  *          size in bytes
  357.  *          buffer to read into
  358.  * Returns: T if success, NIL otherwise
  359.  */
  360.  
  361. long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
  362. {
  363.   unsigned long n;
  364.   while (size > 0) {            /* until request satisfied */
  365.     if (!ssl_getdata (stream)) return NIL;
  366.     n = min (size,stream->ictr);/* number of bytes to transfer */
  367.                                 /* do the copy */
  368.     memcpy (buffer,stream->iptr,n);
  369.     buffer += n;                /* update pointer */
  370.     stream->iptr += n;
  371.     size -= n;                  /* update # of bytes to do */
  372.     stream->ictr -= n;
  373.   }
  374.   buffer[0] = '\0';             /* tie off string */
  375.   return T;
  376. }
  377.  
  378. /* SSL receive data
  379.  * Accepts: TCP/IP stream
  380.  * Returns: T if success, NIL otherwise
  381.  */
  382.  
  383. long ssl_getdata (SSLSTREAM *stream)
  384. {
  385.   SECURITY_STATUS status;
  386.   SecBuffer buf[4];
  387.   SecBufferDesc msg;
  388.   size_t n = 0;
  389.   size_t i;
  390.   while (stream->ictr < 1) {    /* decrypted buffer empty? */
  391.     do {                        /* yes, make sure have data from TCP */
  392.       if (stream->iextractr) {  /* have previous unread data? */
  393.         memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
  394.         n += stream->iextractr; /* update number of bytes read */
  395.         stream->iextractr = 0;  /* no more extra data */
  396.       }
  397.       else {                    /* read from TCP */
  398.         if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
  399.                                 /* maximum amount of data to copy */
  400.         if (!(i = min (stream->sizes.cbMaximumMessage - n,
  401.                        stream->tcpstream->ictr)))
  402.           fatal ("incomplete SecBuffer already cbMaximumMessage");
  403.                                 /* do the copy */
  404.         memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
  405.         stream->tcpstream->iptr += i;
  406.         stream->tcpstream->ictr -= i;
  407.         n += i;                 /* update number of bytes to decrypt */
  408.       }
  409.       buf[0].cbBuffer = n;      /* first SecBuffer gets data */
  410.       buf[0].pvBuffer = stream->ibuf;
  411.       buf[0].BufferType = SECBUFFER_DATA;
  412.                                 /* subsequent ones are for spares */
  413.       buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
  414.         SECBUFFER_EMPTY;
  415.       msg.ulVersion = SECBUFFER_VERSION;
  416.       msg.cBuffers = 4;         /* number of SecBuffers */
  417.       msg.pBuffers = buf;       /* first SecBuffer */
  418.     } while ((status = ssldecrypt (&stream->context,&msg,0,NIL)) ==
  419.              SEC_E_INCOMPLETE_MESSAGE);
  420.     switch (status) {
  421.     case SEC_E_OK:              /* won */
  422.     case SEC_I_RENEGOTIATE:     /* won but lost it after this buffer */
  423.                                 /* hunt for a buffer */
  424.       for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
  425.       if (i < 4) {              /* found a buffer? */
  426.                                 /* yes, set up pointer and counter */
  427.         stream->iptr = buf[i].pvBuffer;
  428.         stream->ictr = buf[i].cbBuffer;
  429.                                 /* any unprocessed data? */
  430.         while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
  431.                                 /* yes, note for next time around */
  432.           stream->iextraptr = buf[i].pvBuffer;
  433.           stream->iextractr = buf[i].cbBuffer;
  434.         }
  435.       }
  436.       break;
  437.     default:                    /* anything else means we've lost */
  438.       return ssl_abort (stream);
  439.     }
  440.   }
  441.   return LONGT;
  442. }
  443.  
  444. /* SSL send string as record
  445.  * Accepts: SSL stream
  446.  *          string pointer
  447.  * Returns: T if success else NIL
  448.  */
  449.  
  450. long ssl_soutr (SSLSTREAM *stream,char *string)
  451. {
  452.   return ssl_sout (stream,string,(unsigned long) strlen (string));
  453. }
  454.  
  455.  
  456. /* SSL send string
  457.  * Accepts: SSL stream
  458.  *          string pointer
  459.  *          byte count
  460.  * Returns: T if success else NIL
  461.  */
  462.  
  463. long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
  464. {
  465.   SecBuffer buf[4];
  466.   SecBufferDesc msg;
  467.   char *s = stream->ibuf;
  468.   size_t n = 0;
  469.   while (size) {                /* until satisfied request */
  470.                                 /* header */
  471.     buf[0].BufferType = SECBUFFER_STREAM_HEADER;
  472.     memset (buf[0].pvBuffer = stream->obuf,0,
  473.             buf[0].cbBuffer = stream->sizes.cbHeader);
  474.                                 /* message (up to maximum size) */
  475.     buf[1].BufferType = SECBUFFER_DATA;
  476.     memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
  477.             buf[1].cbBuffer = min (size,stream->sizes.cbMaximumMessage));
  478.                                 /* trailer */
  479.     buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
  480.     memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
  481.             buf[2].cbBuffer = stream->sizes.cbTrailer);
  482.                                 /* spare */
  483.     buf[3].BufferType = SECBUFFER_EMPTY;
  484.     msg.ulVersion = SECBUFFER_VERSION;
  485.     msg.cBuffers = 4;           /* number of SecBuffers */
  486.     msg.pBuffers = buf;         /* first SecBuffer */
  487.     string += buf[1].cbBuffer;
  488.     size -= buf[1].cbBuffer;    /* this many bytes processed */
  489.                                 /* encrypt and send message */
  490.     if ((sslencrypt (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
  491.         !tcp_sout (stream->tcpstream,stream->obuf,
  492.                    buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
  493.       return ssl_abort (stream);/* encryption or sending failed */
  494.   }
  495.   return LONGT;
  496. }
  497.  
  498. /* SSL close
  499.  * Accepts: SSL stream
  500.  */
  501.  
  502. void ssl_close (SSLSTREAM *stream)
  503. {
  504.   ssl_abort (stream);           /* nuke the stream */
  505.   fs_give ((void **) &stream);  /* flush the stream */
  506. }
  507.  
  508.  
  509. /* SSL abort stream
  510.  * Accepts: SSL stream
  511.  * Returns: NIL always
  512.  */
  513.  
  514. long ssl_abort (SSLSTREAM *stream)
  515. {
  516.   if (stream->tcpstream) {      /* close TCP stream */
  517.     sslfunc->DeleteSecurityContext (&stream->context);
  518.     sslfunc->FreeCredentialHandle (&stream->cred);
  519.     tcp_close (stream->tcpstream);
  520.     stream->tcpstream = NIL;
  521.   }
  522.   if (stream->ibuf) fs_give ((void **) &stream->ibuf);
  523.   if (stream->obuf) fs_give ((void **) &stream->obuf);
  524.   return NIL;
  525. }
  526.  
  527. /* SSL get host name
  528.  * Accepts: SSL stream
  529.  * Returns: host name for this stream
  530.  */
  531.  
  532. char *ssl_host (SSLSTREAM *stream)
  533. {
  534.   return tcp_host (stream->tcpstream);
  535. }
  536.  
  537.  
  538. /* SSL get remote host name
  539.  * Accepts: SSL stream
  540.  * Returns: host name for this stream
  541.  */
  542.  
  543. char *ssl_remotehost (SSLSTREAM *stream)
  544. {
  545.   return tcp_remotehost (stream->tcpstream);
  546. }
  547.  
  548.  
  549. /* SSL return port for this stream
  550.  * Accepts: SSL stream
  551.  * Returns: port number for this stream
  552.  */
  553.  
  554. unsigned long ssl_port (SSLSTREAM *stream)
  555. {
  556.   return tcp_port (stream->tcpstream);
  557. }
  558.  
  559.  
  560. /* SSL get local host name
  561.  * Accepts: SSL stream
  562.  * Returns: local host name
  563.  */
  564.  
  565. char *ssl_localhost (SSLSTREAM *stream)
  566. {
  567.   return tcp_localhost (stream->tcpstream);
  568. }
  569.  
  570. /* Client authenticator
  571.  * Accepts: challenger function
  572.  *          responder function
  573.  *          parsed network mailbox structure
  574.  *          stream argument for functions
  575.  *          pointer to current trial count
  576.  *          returned user name
  577.  * Returns: T if success, NIL otherwise, number of trials incremented if retry
  578.  */
  579.  
  580. long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
  581.                         NETMBX *mb,void *stream,unsigned long *trial,
  582.                         char *user)
  583. {
  584.   char *s,*t,*u,pwd[MAILTMPLEN];
  585.   void *chal;
  586.   unsigned long cl,sl;
  587.   if (!mb->altflag)             /* snarl if not secure session */
  588.     mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN);
  589.                                 /* get initial (empty) challenge */
  590.   if ((chal = (*challenger) (stream,&cl)) && !cl) {
  591.     fs_give ((void **) &chal);
  592.                                 /* prompt user */
  593.     mm_login (mb,user,pwd,*trial);
  594.     if (!pwd[0]) {              /* user requested abort */
  595.       (*responder) (stream,NIL,0);
  596.       *trial = 0;               /* don't retry */
  597.       return T;                 /* will get a NO response back */
  598.     }
  599.     t = s = (char *) fs_get (sl = strlen (user) + strlen (pwd) + 2);
  600.     *t++ = '\0';                /* use authentication id as authorization id */
  601.                                 /* copy user name as authentication id */
  602.     for (u = user; *u; *t++ = *u++);
  603.     *t++ = '\0';                /* delimiting NUL */
  604.                                 /* copy password */
  605.     for (u = pwd; *u; *t++ = *u++);
  606.                                 /* send credentials */
  607.     if ((*responder) (stream,s,sl) && !(chal = (*challenger) (stream,&cl))) {
  608.       fs_give ((void **) &s);   /* free response */
  609.       ++*trial;                 /* can try again if necessary */
  610.       return T;                 /* check the authentication */
  611.     }
  612.     fs_give ((void **) &s);     /* free response */
  613.   }
  614.   if (chal) fs_give ((void **) &chal);
  615.   *trial = 0;                   /* don't retry */
  616.   return NIL;                   /* failed */
  617. }
  618.  
  619. /* Check if PLAIN valid on this system
  620.  * Returns: T, always
  621.  */
  622.  
  623. long auth_plain_valid (void)
  624. {
  625.                                 /* server forbids PLAIN if not SSL */
  626.   if (!sslstdio) auth_ssl.server = NIL;
  627.   return T;                     /* PLAIN is otherwise valid */
  628. }
  629.  
  630.  
  631. /* Server authenticator
  632.  * Accepts: responder function
  633.  *          argument count
  634.  *          argument vector
  635.  * Returns: authenticated user name or NIL
  636.  */
  637.  
  638. char *auth_plain_server (authresponse_t responder,int argc,char *argv[])
  639. {
  640.   char *ret = NIL;
  641.   char *user,*aid,*pass;
  642.   unsigned long len;
  643.                                 /* get user name */
  644.   if (aid = (*responder) ("",0,&len)) {
  645.                                 /* note: responders null-terminate */
  646.     if ((((unsigned long) ((user = aid + strlen (aid) + 1) - aid)) < len) &&
  647.         (((unsigned long) ((pass = user + strlen (user) + 1) - aid)) < len) &&
  648.         (((unsigned long) ((pass + strlen (pass)) - aid)) == len) &&
  649.         !(*aid && strcmp (aid,user)) && server_login (user,pass,argc,argv))
  650.       ret = myusername ();
  651.     fs_give ((void **) &aid);
  652.   }
  653.   return ret;
  654. }
  655.  
  656. /* Init server for SSL
  657.  * Accepts: server name
  658.  *          service name
  659.  *          alternative service name
  660.  * Returns: SSL stdio stream, always
  661.  */
  662.  
  663. void server_init (char *server,char *service,char *altservice,char *sasl,
  664.                   void *clkint,void *kodint,void *hupint,void *trmint)
  665. {
  666.   struct servent *sv;
  667.   long port;
  668.   if (server) {                 /* set server name in syslog */
  669.     openlog (server,LOG_PID,LOG_MAIL);
  670.     fclose (stderr);            /* possibly save a process ID */
  671.   }
  672.   /* Use SSL if alt service, or if server starts with "s" and not service */
  673.   if (service && altservice && ((port = tcp_serverport ()) >= 0) &&
  674.       (((sv = getservbyname (altservice,"tcp")) &&
  675.         (port == ntohs (sv->s_port))) ||
  676.        ((*server == 's') && (!(sv = getservbyname (service,"tcp")) ||
  677.                              (port != ntohs (sv->s_port))))))
  678.     sslstdio = (void *) ssl_server_init (server);
  679.                                 /* now call c-client's version */
  680.   Server_init (NIL,service,altservice,sasl,clkint,kodint,hupint,trmint);
  681. }
  682.  
  683.                                 /* link to the real one */
  684. #define server_init Server_init
  685.  
  686. /* Wait for stdin input
  687.  * Accepts: timeout in seconds
  688.  * Returns: T if have input on stdin, else NIL
  689.  */
  690.  
  691. long server_input_wait (long seconds)
  692. {
  693.   SECURITY_STATUS status;
  694.   SecBuffer buf[4];
  695.   SecBufferDesc msg;
  696.   struct timeval tmo;
  697.   fd_set fds,efd;
  698.   size_t n = 0;
  699.   size_t i;
  700.   SSLSTREAM *stream;
  701.   if (!sslstdio) return Server_input_wait (seconds);
  702.                                 /* if no input available in buffer */
  703.   while ((stream = sslstdio->sslstream)->ictr <= 0) {
  704.     do {
  705.       if (stream->iextractr) {  /* have previous unread data? */
  706.         memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
  707.         n += stream->iextractr; /* update number of bytes read */
  708.         stream->iextractr = 0;  /* no more extra data */
  709.       }
  710.       else {                    /* if nothing in TCP buffer */
  711.         if (stream->tcpstream->ictr < 1) {
  712.           FD_ZERO (&fds);       /* initialize selection vector */
  713.           FD_ZERO (&efd);       /* initialize selection vector */
  714.           FD_SET (stream->tcpstream->tcps,&fds);
  715.           FD_SET (stream->tcpstream->tcps,&efd);
  716.           tmo.tv_sec = seconds; tmo.tv_usec = 0;
  717.                                 /* sniff and block until timeout */
  718.           if (!select (stream->tcpstream->tcps+1,&fds,0,&efd,&tmo)) return NIL;
  719.         }
  720.                                 /* now read that data */
  721.         if (!tcp_getdata (stream->tcpstream)) return LONGT;
  722.                                 /* maximum amount of data to copy */
  723.         if (!(i = min (stream->sizes.cbMaximumMessage - n,
  724.                        stream->tcpstream->ictr)))
  725.           fatal ("incomplete SecBuffer already cbMaximumMessage");
  726.                                 /* do the copy */
  727.         memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
  728.         stream->tcpstream->iptr += i;
  729.         stream->tcpstream->ictr -= i;
  730.         n += i;                 /* update number of bytes to decrypt */
  731.       }
  732.       buf[0].cbBuffer = n;      /* first SecBuffer gets data */
  733.       buf[0].pvBuffer = stream->ibuf;
  734.       buf[0].BufferType = SECBUFFER_DATA;
  735.                                 /* subsequent ones are for spares */
  736.       buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
  737.         SECBUFFER_EMPTY;
  738.       msg.ulVersion = SECBUFFER_VERSION;
  739.       msg.cBuffers = 4; /* number of SecBuffers */
  740.       msg.pBuffers = buf;       /* first SecBuffer */
  741.     } while ((status = ssldecrypt (&stream->context,&msg,0,NIL)) ==
  742.              SEC_E_INCOMPLETE_MESSAGE);
  743.     switch (status) {
  744.     case SEC_E_OK:              /* won */
  745.     case SEC_I_RENEGOTIATE:     /* won but lost it after this buffer */
  746.                                 /* hunt for a buffer */
  747.       for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
  748.       if (i < 4) {              /* found a buffer? */
  749.                                 /* yes, set up pointer and counter */
  750.         stream->iptr = buf[i].pvBuffer;
  751.         stream->ictr = buf[i].cbBuffer;
  752.                                 /* any unprocessed data? */
  753.         while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
  754.                                 /* yes, note for next time around */
  755.           stream->iextraptr = buf[i].pvBuffer;
  756.           stream->iextractr = buf[i].cbBuffer;
  757.         }
  758.       }
  759.       break;
  760.     default:                    /* anything else means we're sick */
  761.       return LONGT;
  762.     }
  763.   }
  764.   return LONGT;
  765. }
  766.  
  767.                                 /* link to the other one */
  768. #define server_input_wait Server_input_wait
  769.  
  770. /* Init server for SSL
  771.  * Accepts: server name
  772.  * Returns: SSL stdio stream, always
  773.  */
  774.  
  775. SSLSTDIOSTREAM *ssl_server_init (char *server)
  776. {
  777.   SECURITY_STATUS e;
  778.   ULONG a;
  779.   TimeStamp t;
  780.   SecBuffer ibuf[2],obuf[1];
  781.   SecBufferDesc ibufs,obufs;
  782.   SSLSTDIOSTREAM *ret;
  783.   SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
  784.                                             sizeof (SSLSTREAM));
  785.   ULONG req = ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT |
  786.     ASC_REQ_CONFIDENTIALITY | ASC_REQ_USE_SESSION_KEY |
  787.     ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_STREAM | ASC_REQ_EXTENDED_ERROR;
  788.   int done = 0;
  789.   int failed = T;
  790.   int repeat = 0;
  791.   char *buf = (char *) fs_get (ssltsz);
  792.   unsigned long size;
  793.   ssl_onceonlyinit ();          /* make sure algorithms added */
  794.                                 /* get credentials and inital client data */
  795.   if ((sslfunc->AcquireCredentialsHandle
  796.        (NIL,sslpnm,SECPKG_CRED_INBOUND,NIL,NIL,NIL,NIL,&stream->cred,&t) ==
  797.        SEC_E_OK) && tcp_getdata (stream->tcpstream)) {
  798.                                 /* transfer initial client data */
  799.     memcpy (buf,stream->tcpstream->iptr,size = stream->tcpstream->ictr);
  800.                                 /* empty it from TCP's buffers */
  801.     stream->tcpstream->iptr += stream->tcpstream->ictr;
  802.     stream->tcpstream->ictr = 0;
  803.     while (!done) {             /* negotiate negotiate security context */
  804.                                 /* initialize buffers */
  805.       ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
  806.       ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
  807.       obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
  808.       ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
  809.       ibuf[1].BufferType = SECBUFFER_EMPTY;
  810.                                 /* initialize buffer descriptors */
  811.       ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
  812.       ibufs.cBuffers = 2; obufs.cBuffers = 1;
  813.       ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
  814.                                 /* negotiate security */
  815.       e = sslfunc->AcceptSecurityContext
  816.         (&stream->cred,repeat ? &stream->context : NIL,&ibufs,req,
  817.          SECURITY_NETWORK_DREP,&stream->context,&obufs,&a,&t);
  818.       repeat = T;               /* next call will use the context */
  819.                                 /* have an output buffer we need to send? */
  820.       if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
  821.         if ((done >= 0) &&      /* do so if in good state */
  822.             !tcp_sout (stream->tcpstream,obuf[0].pvBuffer,
  823.                        obuf[0].cbBuffer)) done = -1;
  824.                                 /* free the buffer */
  825.         sslfunc->FreeContextBuffer (obuf[0].pvBuffer);
  826.       }
  827.  
  828.       switch (e) {              /* negotiation state */
  829.       case SEC_E_OK:
  830.         done = T;               /* got security context, all done */
  831.                                 /* any data to be regurgitated? */
  832.         if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
  833.                                 /* yes, set this as the new data */
  834.             memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
  835.                      buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
  836.             stream->tcpstream->ictr = ibuf[1].cbBuffer;
  837.           }
  838.         if (sslfunc->QueryContextAttributes
  839.             (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes) ==
  840.             SEC_E_OK) { /* get stream sizes */
  841.                                 /* maximum SSL buffer size */
  842.           size_t i = stream->sizes.cbHeader +
  843.             stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
  844.                                 /* make buffers */
  845.           stream->ibuf = (char *) fs_get (i);
  846.           stream->obuf = (char *) fs_get (i);
  847.           failed = NIL; /* mark success */
  848.         }
  849.         break;
  850.       case SEC_I_CONTINUE_NEEDED:
  851.         if (size) {             /* continue, read any data? */
  852.                                 /* yes, anything regurgiated back to us? */
  853.           if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
  854.                                 /* yes, set this as the new data */
  855.             memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
  856.             size = ibuf[1].cbBuffer;
  857.             break;
  858.           }
  859.           size = 0;             /* otherwise, read more stuff from server */
  860.         }
  861.       case SEC_E_INCOMPLETE_MESSAGE:
  862.                                 /* need to read more data from server */
  863.         if (tcp_getdata (stream->tcpstream)) {
  864.           memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
  865.           size += stream->tcpstream->ictr;
  866.                                 /* empty it from TCP's buffers */
  867.           stream->tcpstream->iptr += stream->tcpstream->ictr;
  868.           stream->tcpstream->ictr = 0;
  869.           break;
  870.         }
  871.       default:                  /* anything else is an error */
  872.         done = -1;
  873.         break;
  874.       }
  875.     }
  876.   }
  877.  
  878.   fs_give ((void **) &buf);     /* flush temporary buffer */
  879.   if (failed) {                 /* failed to negotiate SSL */
  880.     ssl_close (stream);         /* punt stream */
  881.     exit (1);                   /* punt this program too */
  882.   }
  883.   ret = (SSLSTDIOSTREAM *)      /* success, return SSL stdio stream */
  884.     memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof(SSLSTDIOSTREAM));
  885.   ret->sslstream = stream;      /* stream to do SSL I/O */
  886.   ret->octr = SSLBUFLEN;        /* available space in output buffer */
  887.   ret->optr = ret->obuf;        /* current output buffer pointer */
  888.   return ret;
  889. }
  890.  
  891. /* Get character
  892.  * Returns: character or EOF
  893.  */
  894.  
  895. int ssl_getchar (void)
  896. {
  897.   if (!sslstdio) return getchar ();
  898.   if (!ssl_getdata (sslstdio->sslstream)) return EOF;
  899.                                 /* one last byte available */
  900.   sslstdio->sslstream->ictr--;
  901.   return (int) *(sslstdio->sslstream->iptr)++;
  902. }
  903.  
  904.  
  905. /* Get string
  906.  * Accepts: destination string pointer
  907.  *          number of bytes available
  908.  * Returns: destination string pointer or NIL if EOF
  909.  */
  910.  
  911. char *ssl_gets (char *s,int n)
  912. {
  913.   int i,c;
  914.   if (!sslstdio) return fgets (s,n,stdin);
  915.   for (i = c = 0, n-- ; (c != '\n') && (i < n); sslstdio->sslstream->ictr--) {
  916.     if ((sslstdio->sslstream->ictr <= 0) && !ssl_getdata (sslstdio->sslstream))
  917.       return NIL;               /* read error */
  918.     c = s[i++] = *(sslstdio->sslstream->iptr)++;
  919.   }
  920.   s[i] = '\0';                  /* tie off string */
  921.   return s;
  922. }
  923.  
  924. /* Put character
  925.  * Accepts: character
  926.  * Returns: character written or EOF
  927.  */
  928.  
  929. int ssl_putchar (int c)
  930. {
  931.   if (!sslstdio) return putchar (c);
  932.                                 /* flush buffer if full */
  933.   if (!sslstdio->octr && ssl_flush ()) return EOF;
  934.   sslstdio->octr--;             /* count down one character */
  935.   *sslstdio->optr++ = c;        /* write character */
  936.   return c;                     /* return that character */
  937. }
  938.  
  939.  
  940. /* Put string
  941.  * Accepts: destination string pointer
  942.  * Returns: 0 or EOF if error
  943.  */
  944.  
  945. int ssl_puts (char *s)
  946. {
  947.   if (!sslstdio) return fputs (s,stdout);
  948.   while (*s) {                  /* flush buffer if full */
  949.     if (!sslstdio->octr && ssl_flush ()) return EOF;
  950.     *sslstdio->optr++ = *s++;   /* write one more character */
  951.     sslstdio->octr--;           /* count down one character */
  952.   }
  953.   return 0;                     /* success */
  954. }
  955.  
  956.  
  957. /* Flush output
  958.  * Returns: 0 or EOF if error
  959.  */
  960.  
  961. int ssl_flush (void)
  962. {
  963.   if (!sslstdio) return fflush (stdout);
  964.                                 /* force out buffer */
  965.   if (!ssl_sout (sslstdio->sslstream,sslstdio->obuf,
  966.                  SSLBUFLEN - sslstdio->octr)) return EOF;
  967.                                 /* renew output buffer */
  968.   sslstdio->optr = sslstdio->obuf;
  969.   sslstdio->octr = SSLBUFLEN;
  970.   return 0;                     /* success */
  971. }
  972.