Respect ISO aliasing rules.
[openssl.git] / apps / s_client.c
index 8eeb726981e46f465bd1e1bd94a32edc15f1207f..66c0f8aa33edb786b9aeb2c0f375ba8b460cdcdd 100644 (file)
@@ -187,6 +187,7 @@ typedef unsigned int u_int;
 
 extern int verify_depth;
 extern int verify_error;
+extern int verify_return_error;
 
 #ifdef FIONBIO
 static int c_nbio=0;
@@ -315,7 +316,7 @@ static void sc_usage(void)
        BIO_printf(bio_err," -starttls prot - use the STARTTLS command before starting TLS\n");
        BIO_printf(bio_err,"                 for those protocols that support it, where\n");
        BIO_printf(bio_err,"                 'prot' defines which one to assume.  Currently,\n");
-       BIO_printf(bio_err,"                 only \"smtp\" and \"pop3\" are supported.\n");
+       BIO_printf(bio_err,"                 only \"smtp\", \"pop3\", \"imap\", and \"ftp\" are supported.\n");
 #ifndef OPENSSL_NO_ENGINE
        BIO_printf(bio_err," -engine id    - Initialise and use the specified engine\n");
 #endif
@@ -347,6 +348,15 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg)
        }
 #endif
 
+enum
+{
+       PROTO_OFF       = 0,
+       PROTO_SMTP,
+       PROTO_POP3,
+       PROTO_IMAP,
+       PROTO_FTP
+};
+
 int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
@@ -373,12 +383,13 @@ int MAIN(int argc, char **argv)
        int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending;
        SSL_CTX *ctx=NULL;
        int ret=1,in_init=1,i,nbio_test=0;
-       int starttls_proto = 0;
+       int starttls_proto = PROTO_OFF;
        int prexit = 0, vflags = 0;
        const SSL_METHOD *meth=NULL;
        int socket_type=SOCK_STREAM;
        BIO *sbio;
        char *inrand=NULL;
+       int mbuf_len=0;
 #ifndef OPENSSL_NO_ENGINE
        char *engine_id=NULL;
        ENGINE *e=NULL;
@@ -478,6 +489,8 @@ int MAIN(int argc, char **argv)
                        vflags |= X509_V_FLAG_CRL_CHECK;
                else if (strcmp(*argv,"-crl_check_all") == 0)
                        vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
+               else if (strcmp(*argv,"-verify_return_error") == 0)
+                       verify_return_error = 1;
                else if (strcmp(*argv,"-prexit") == 0)
                        prexit=1;
                else if (strcmp(*argv,"-crlf") == 0)
@@ -607,9 +620,13 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        ++argv;
                        if (strcmp(*argv,"smtp") == 0)
-                               starttls_proto = 1;
+                               starttls_proto = PROTO_SMTP;
                        else if (strcmp(*argv,"pop3") == 0)
-                               starttls_proto = 2;
+                               starttls_proto = PROTO_POP3;
+                       else if (strcmp(*argv,"imap") == 0)
+                               starttls_proto = PROTO_IMAP;
+                       else if (strcmp(*argv,"ftp") == 0)
+                               starttls_proto = PROTO_FTP;
                        else
                                goto bad;
                        }
@@ -869,7 +886,7 @@ re_start:
                {
                con->debug=1;
                BIO_set_callback(sbio,bio_dump_callback);
-               BIO_set_callback_arg(sbio,bio_c_out);
+               BIO_set_callback_arg(sbio,(char *)bio_c_out);
                }
        if (c_msg)
                {
@@ -895,18 +912,93 @@ re_start:
        sbuf_off=0;
 
        /* This is an ugly hack that does a lot of assumptions */
-       if (starttls_proto == 1)
+       /* We do have to handle multi-line responses which may come
+          in a single packet or not. We therefore have to use
+          BIO_gets() which does need a buffering BIO. So during
+          the initial chitchat we do push a buffering BIO into the
+          chain that is removed again later on to not disturb the
+          rest of the s_client operation. */
+       if (starttls_proto == PROTO_SMTP)
                {
-               BIO_read(sbio,mbuf,BUFSIZZ);
+               int foundit=0;
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
+               /* wait for multi-line response to end from SMTP */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       }
+               while (mbuf_len>3 && mbuf[3]=='-');
+               /* STARTTLS command requires EHLO... */
+               BIO_printf(fbio,"EHLO openssl.client.net\r\n");
+               BIO_flush(fbio);
+               /* wait for multi-line response to end EHLO SMTP response */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       if (strstr(mbuf,"STARTTLS"))
+                               foundit=1;
+                       }
+               while (mbuf_len>3 && mbuf[3]=='-');
+               BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
+               if (!foundit)
+                       BIO_printf(bio_err,
+                                  "didn't found starttls in server response,"
+                                  " try anyway...\n");
                BIO_printf(sbio,"STARTTLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
-       if (starttls_proto == 2)
+       else if (starttls_proto == PROTO_POP3)
                {
                BIO_read(sbio,mbuf,BUFSIZZ);
                BIO_printf(sbio,"STLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
+       else if (starttls_proto == PROTO_IMAP)
+               {
+               int foundit=0;
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
+               BIO_gets(fbio,mbuf,BUFSIZZ);
+               /* STARTTLS command requires CAPABILITY... */
+               BIO_printf(fbio,". CAPABILITY\r\n");
+               BIO_flush(fbio);
+               /* wait for multi-line CAPABILITY response */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       if (strstr(mbuf,"STARTTLS"))
+                               foundit=1;
+                       }
+               while (mbuf_len>3 && mbuf[0]!='.');
+               BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
+               if (!foundit)
+                       BIO_printf(bio_err,
+                                  "didn't found STARTTLS in server response,"
+                                  " try anyway...\n");
+               BIO_printf(sbio,". STARTTLS\r\n");
+               BIO_read(sbio,sbuf,BUFSIZZ);
+               }
+       else if (starttls_proto == PROTO_FTP)
+               {
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
+               /* wait for multi-line response to end from FTP */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       }
+               while (mbuf_len>3 && mbuf[3]=='-');
+               BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
+               BIO_printf(sbio,"AUTH TLS\r\n");
+               BIO_read(sbio,sbuf,BUFSIZZ);
+               }
 
        for (;;)
                {
@@ -925,10 +1017,10 @@ re_start:
                                {
                                in_init=0;
 #ifndef OPENSSL_NO_TLSEXT
-       if (servername != NULL && !SSL_session_reused(con))
-               {
-               BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
-               }
+                               if (servername != NULL && !SSL_session_reused(con))
+                                       {
+                                       BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
+                                       }
 #endif
                                print_stuff(bio_c_out,con,full_log);
                                if (full_log > 0) full_log--;
@@ -937,7 +1029,7 @@ re_start:
                                        {
                                        BIO_printf(bio_err,"%s",mbuf);
                                        /* We don't need to know any more */
-                                       starttls_proto = 0;
+                                       starttls_proto = PROTO_OFF;
                                        }
 
                                if (reconnect)
@@ -1261,6 +1353,8 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
                        }
                }
 shut:
+       if (in_init)
+               print_stuff(bio_c_out,con,full_log);
        SSL_shutdown(con);
        SHUTDOWN(SSL_get_fd(con));
        ret=0;