- if (c_nbio)
- {
- unsigned long l=1;
- BIO_printf(bio_c_out,"turning on non blocking io\n");
- if (BIO_socket_ioctl(s,FIONBIO,&l) < 0)
- {
- ERR_print_errors(bio_err);
- goto end;
- }
- }
-#endif
- if (c_Pause & 0x01) con->debug=1;
-
- if ( SSL_version(con) == DTLS1_VERSION)
- {
- struct timeval timeout;
-
- sbio=BIO_new_dgram(s,BIO_NOCLOSE);
- if (getsockname(s, &peer, (void *)&peerlen) < 0)
- {
- BIO_printf(bio_err, "getsockname:errno=%d\n",
- get_last_socket_error());
- SHUTDOWN(s);
- goto end;
- }
-
- BIO_ctrl_set_connected(sbio, 1, &peer);
-
- if ( enable_timeouts)
- {
- timeout.tv_sec = 0;
- timeout.tv_usec = DGRAM_RCV_TIMEOUT;
- BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
-
- timeout.tv_sec = 0;
- timeout.tv_usec = DGRAM_SND_TIMEOUT;
- BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
- }
-
- if ( mtu > 0)
- {
- SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
- SSL_set_mtu(con, mtu);
- }
- else
- /* want to do MTU discovery */
- BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
- }
- else
- sbio=BIO_new_socket(s,BIO_NOCLOSE);
-
-
-
- if (nbio_test)
- {
- BIO *test;
-
- test=BIO_new(BIO_f_nbio_test());
- sbio=BIO_push(test,sbio);
- }
-
- if (c_debug)
- {
- con->debug=1;
- BIO_set_callback(sbio,bio_dump_callback);
- BIO_set_callback_arg(sbio,bio_c_out);
- }
- if (c_msg)
- {
- SSL_set_msg_callback(con, msg_cb);
- SSL_set_msg_callback_arg(con, bio_c_out);
- }
-
- SSL_set_bio(con,sbio,sbio);
- SSL_set_connect_state(con);
-
- /* ok, lets connect */
- width=SSL_get_fd(con)+1;
-
- read_tty=1;
- write_tty=0;
- tty_on=0;
- read_ssl=1;
- write_ssl=1;
-
- cbuf_len=0;
- cbuf_off=0;
- sbuf_len=0;
- sbuf_off=0;
-
- /* This is an ugly hack that does a lot of assumptions */
- if (starttls_proto == 1)
- {
- BIO_read(sbio,mbuf,BUFSIZZ);
- BIO_printf(sbio,"STARTTLS\r\n");
- BIO_read(sbio,sbuf,BUFSIZZ);
- }
- if (starttls_proto == 2)
- {
- BIO_read(sbio,mbuf,BUFSIZZ);
- BIO_printf(sbio,"STLS\r\n");
- BIO_read(sbio,sbuf,BUFSIZZ);
- }
-
- for (;;)
- {
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
-
- if (SSL_in_init(con) && !SSL_total_renegotiations(con))
- {
- in_init=1;
- tty_on=0;
- }
- else
- {
- tty_on=1;
- if (in_init)
- {
- in_init=0;
- print_stuff(bio_c_out,con,full_log);
- if (full_log > 0) full_log--;
-
- if (starttls_proto)
- {
- BIO_printf(bio_err,"%s",mbuf);
- /* We don't need to know any more */
- starttls_proto = 0;
- }
-
- if (reconnect)
- {
- reconnect--;
- BIO_printf(bio_c_out,"drop connection and then reconnect\n");
- SSL_shutdown(con);
- SSL_set_connect_state(con);
- SHUTDOWN(SSL_get_fd(con));
- goto re_start;
- }
- }
- }
-
- ssl_pending = read_ssl && SSL_pending(con);
-
- if (!ssl_pending)
- {
-#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE)
- if (tty_on)
- {
- if (read_tty) FD_SET(fileno(stdin),&readfds);
- if (write_tty) FD_SET(fileno(stdout),&writefds);
- }
- if (read_ssl)
- FD_SET(SSL_get_fd(con),&readfds);
- if (write_ssl)
- FD_SET(SSL_get_fd(con),&writefds);
-#else
- if(!tty_on || !write_tty) {
- if (read_ssl)
- FD_SET(SSL_get_fd(con),&readfds);
- if (write_ssl)
- FD_SET(SSL_get_fd(con),&writefds);
- }
-#endif
-/* printf("mode tty(%d %d%d) ssl(%d%d)\n",
- tty_on,read_tty,write_tty,read_ssl,write_ssl);*/
-
- /* Note: under VMS with SOCKETSHR the second parameter
- * is currently of type (int *) whereas under other
- * systems it is (void *) if you don't have a cast it
- * will choke the compiler: if you do have a cast then
- * you can either go for (int *) or (void *).
- */
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
- /* Under Windows/DOS we make the assumption that we can
- * always write to the tty: therefore if we need to
- * write to the tty we just fall through. Otherwise
- * we timeout the select every second and see if there
- * are any keypresses. Note: this is a hack, in a proper
- * Windows application we wouldn't do this.
- */
- i=0;
- if(!write_tty) {
- if(read_tty) {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- i=select(width,(void *)&readfds,(void *)&writefds,
- NULL,&tv);
-#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
- if(!i && (!_kbhit() || !read_tty) ) continue;
+ if (c_nbio) {
+ unsigned long l = 1;
+ BIO_printf(bio_c_out, "turning on non blocking io\n");
+ if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) {
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ }
+#endif
+ if (c_Pause & 0x01)
+ SSL_set_debug(con, 1);
+
+ if (socket_type == SOCK_DGRAM) {
+
+ sbio = BIO_new_dgram(s, BIO_NOCLOSE);
+ if (getsockname(s, &peer, (void *)&peerlen) < 0) {
+ BIO_printf(bio_err, "getsockname:errno=%d\n",
+ get_last_socket_error());
+ SHUTDOWN(s);
+ goto end;
+ }
+
+ (void)BIO_ctrl_set_connected(sbio, 1, &peer);
+
+ if (enable_timeouts) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = DGRAM_RCV_TIMEOUT;
+ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = DGRAM_SND_TIMEOUT;
+ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
+ }
+
+ if (socket_mtu) {
+ if (socket_mtu < DTLS_get_link_min_mtu(con)) {
+ BIO_printf(bio_err, "MTU too small. Must be at least %ld\n",
+ DTLS_get_link_min_mtu(con));
+ BIO_free(sbio);
+ goto shut;
+ }
+ SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
+ if (!DTLS_set_link_mtu(con, socket_mtu)) {
+ BIO_printf(bio_err, "Failed to set MTU\n");
+ BIO_free(sbio);
+ goto shut;
+ }
+ } else
+ /* want to do MTU discovery */
+ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
+ } else
+ sbio = BIO_new_socket(s, BIO_NOCLOSE);
+
+ if (nbio_test) {
+ BIO *test;
+
+ test = BIO_new(BIO_f_nbio_test());
+ sbio = BIO_push(test, sbio);
+ }
+
+ if (c_debug) {
+ SSL_set_debug(con, 1);
+ BIO_set_callback(sbio, bio_dump_callback);
+ BIO_set_callback_arg(sbio, (char *)bio_c_out);
+ }
+ if (c_msg) {
+#ifndef OPENSSL_NO_SSL_TRACE
+ if (c_msg == 2)
+ SSL_set_msg_callback(con, SSL_trace);
+ else
+#endif
+ SSL_set_msg_callback(con, msg_cb);
+ SSL_set_msg_callback_arg(con, bio_c_msg ? bio_c_msg : bio_c_out);
+ }
+#ifndef OPENSSL_NO_TLSEXT
+ if (c_tlsextdebug) {
+ SSL_set_tlsext_debug_callback(con, tlsext_cb);
+ SSL_set_tlsext_debug_arg(con, bio_c_out);
+ }
+ if (c_status_req) {
+ SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp);
+ SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb);
+ SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
+# if 0
+ {
+ STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null();
+ OCSP_RESPID *id = OCSP_RESPID_new();
+ id->value.byKey = ASN1_OCTET_STRING_new();
+ id->type = V_OCSP_RESPID_KEY;
+ ASN1_STRING_set(id->value.byKey, "Hello World", -1);
+ sk_OCSP_RESPID_push(ids, id);
+ SSL_set_tlsext_status_ids(con, ids);
+ }
+# endif
+ }
+#endif
+#ifndef OPENSSL_NO_JPAKE
+ if (jpake_secret)
+ jpake_client_auth(bio_c_out, sbio, jpake_secret);
+#endif
+
+ SSL_set_bio(con, sbio, sbio);
+ SSL_set_connect_state(con);
+
+ /* ok, lets connect */
+ width = SSL_get_fd(con) + 1;
+
+ read_tty = 1;
+ write_tty = 0;
+ tty_on = 0;
+ read_ssl = 1;
+ write_ssl = 1;
+
+ cbuf_len = 0;
+ cbuf_off = 0;
+ sbuf_len = 0;
+ sbuf_off = 0;
+
+ /* This is an ugly hack that does a lot of assumptions */
+ /*
+ * 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) {
+ 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");
+ (void)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] == '-');
+ (void)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_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");
+ (void)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] != '.');
+ (void)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] == '-');
+ (void)BIO_flush(fbio);
+ BIO_pop(fbio);
+ BIO_free(fbio);
+ BIO_printf(sbio, "AUTH TLS\r\n");
+ BIO_read(sbio, sbuf, BUFSIZZ);
+ }
+ if (starttls_proto == PROTO_XMPP) {
+ int seen = 0;
+ BIO_printf(sbio, "<stream:stream "
+ "xmlns:stream='http://etherx.jabber.org/streams' "
+ "xmlns='jabber:client' to='%s' version='1.0'>", host);
+ seen = BIO_read(sbio, mbuf, BUFSIZZ);
+ mbuf[seen] = 0;
+ while (!strstr
+ (mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'")) {
+ if (strstr(mbuf, "/stream:features>"))
+ goto shut;
+ seen = BIO_read(sbio, mbuf, BUFSIZZ);
+ mbuf[seen] = 0;
+ }
+ BIO_printf(sbio,
+ "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+ seen = BIO_read(sbio, sbuf, BUFSIZZ);
+ sbuf[seen] = 0;
+ if (!strstr(sbuf, "<proceed"))
+ goto shut;
+ mbuf[0] = 0;
+ }
+
+ for (;;) {
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+
+ if ((SSL_version(con) == DTLS1_VERSION) &&
+ DTLSv1_get_timeout(con, &timeout))
+ timeoutp = &timeout;
+ else
+ timeoutp = NULL;
+
+ if (SSL_in_init(con) && !SSL_total_renegotiations(con)) {
+ in_init = 1;
+ tty_on = 0;
+ } else {
+ tty_on = 1;
+ if (in_init) {
+ in_init = 0;
+#if 0 /* This test doesn't really work as intended
+ * (needs to be fixed) */
+# 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 ");
+ }
+# endif
+#endif
+ if (sess_out) {
+ BIO *stmp = BIO_new_file(sess_out, "w");
+ if (stmp) {
+ PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
+ BIO_free(stmp);
+ } else
+ BIO_printf(bio_err, "Error writing session file %s\n",
+ sess_out);
+ }
+ if (c_brief) {
+ BIO_puts(bio_err, "CONNECTION ESTABLISHED\n");
+ print_ssl_summary(bio_err, con);
+ }
+
+ print_stuff(bio_c_out, con, full_log);
+ if (full_log > 0)
+ full_log--;
+
+ if (starttls_proto) {
+ BIO_printf(bio_err, "%s", mbuf);
+ /* We don't need to know any more */
+ starttls_proto = PROTO_OFF;
+ }
+
+ if (reconnect) {
+ reconnect--;
+ BIO_printf(bio_c_out,
+ "drop connection and then reconnect\n");
+ SSL_shutdown(con);
+ SSL_set_connect_state(con);
+ SHUTDOWN(SSL_get_fd(con));
+ goto re_start;
+ }
+ }
+ }
+
+ ssl_pending = read_ssl && SSL_pending(con);
+
+ if (!ssl_pending) {
+#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined (OPENSSL_SYS_BEOS_R5)
+ if (tty_on) {
+ if (read_tty)
+ openssl_fdset(fileno(stdin), &readfds);
+ if (write_tty)
+ openssl_fdset(fileno(stdout), &writefds);
+ }
+ if (read_ssl)
+ openssl_fdset(SSL_get_fd(con), &readfds);
+ if (write_ssl)
+ openssl_fdset(SSL_get_fd(con), &writefds);