From 7c7bb122d597489356f5e8a5551aecd7d431df0b Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Tue, 29 May 2001 20:26:21 +0000 Subject: [PATCH] GSSAPI fixes, tunnel driver. From Brendan Cully. --- Makefile.am | 12 ++--- README | 2 +- configure.in | 91 +++++++++++------------------------ globals.h | 1 + imap/auth.c | 2 +- imap/auth_gss.c | 121 ++++++++++++++++++++++++----------------------- imap/auth_sasl.c | 3 ++ imap/imap.c | 1 - init.h | 16 ++++++- m4/gssapi.m4 | 73 ++++++++++++++++++++++++++++ mutt_socket.c | 25 +++++++--- mutt_socket.h | 3 ++ mutt_tunnel.c | 111 +++++++++++++++++++++++++++++++++++++++++++ mutt_tunnel.h | 24 ++++++++++ 14 files changed, 347 insertions(+), 138 deletions(-) create mode 100644 m4/gssapi.m4 create mode 100644 mutt_tunnel.c create mode 100644 mutt_tunnel.h diff --git a/Makefile.am b/Makefile.am index 66cd7f9fc..5565fd827 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,17 +68,17 @@ non_us_sources = pgp.c pgpinvoke.c pgpkey.c pgplib.c sha1.c \ pgppacket.c pgppacket.h EXTRA_mutt_SOURCES = account.c md5c.c mutt_sasl.c mutt_socket.c mutt_ssl.c \ - pop.c pop_auth.c pop_lib.c pgp.c pgpinvoke.c pgpkey.c pgplib.c \ - sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c browser.h mbyte.h \ - remailer.h url.h mutt_ssl_nss.c pgppacket.c + mutt_tunnel.c pop.c pop_auth.c pop_lib.c pgp.c pgpinvoke.c pgpkey.c \ + pgplib.c sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c \ + browser.h mbyte.h remailer.h url.h mutt_ssl_nss.c pgppacket.c EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP TODO configure acconfig.h account.h \ attach.h buffy.h charset.h copy.h dotlock.h functions.h gen_defs \ globals.h hash.h history.h init.h keymap.h \ mailbox.h mapping.h md5.h mime.h mutt.h mutt_curses.h mutt_menu.h \ - mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mx.h pager.h \ - pgp.h pop.h protos.h reldate.h rfc1524.h rfc2047.h rfc2231.h \ - rfc822.h sha1.h sort.h mime.types VERSION prepare \ + mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \ + mx.h pager.h pgp.h pop.h protos.h reldate.h rfc1524.h rfc2047.h \ + rfc2231.h rfc822.h sha1.h sort.h mime.types VERSION prepare \ _regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \ mbyte.h lib.h extlib.c pgpewrap pgplib.h Muttrc.head Muttrc \ makedoc.c stamp-doc-rc README.SSL README.UPGRADE \ diff --git a/README b/README index 3be608ee8..74c8e0ae2 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -README for mutt-1.1 +README for mutt-1.3 =================== If you got the mutt source code from the public CVS repository (CVS diff --git a/configure.in b/configure.in index f5df4041e..d3e0e54af 100644 --- a/configure.in +++ b/configure.in @@ -590,72 +590,37 @@ then AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt)) AC_CHECK_FUNCS(getaddrinfo) AC_DEFINE(USE_SOCKET) - MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS account.o mutt_socket.o" + MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS account.o mutt_socket.o mutt_tunnel.o" fi dnl -- imap dependencies -- -AC_ARG_WITH(gss, [ --with-gss[=DIR] Compile in GSSAPI authentication for IMAP], - [ - if test "$need_imap" != "yes" - then - AC_MSG_ERROR([GSS support is only for IMAP, but IMAP is not enabled]) - fi - - if test "$with_gss" != "no" - then - if test "$with_gss" != "yes" - then - CPPFLAGS="$CPPFLAGS -I$with_gss/include" - LDFLAGS="$LDFLAGS -L$with_gss/lib" - fi - - saved_LIBS="$LIBS" - gss_type="none" - - dnl New MIT kerberos V support - AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, [ - gss_type="MIT", - MUTTLIBS="$MUTTLIBS -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err" - ],, -lkrb5 -lk5crypto -lcom_err) - - dnl Heimdal kerberos V support - if test x$gss_type = xnone - then - AC_CHECK_LIB(gssapi, gss_init_sec_context, [ - gss_type="Heimdal", - MUTTLIBS="$MUTTLIBS -lgssapi -lkrb5 -ldes -lasn1 -lroken" - MUTTLIBS="$MUTTLIBS -lcrypt -lcom_err" - AC_DEFINE(HAVE_HEIMDAL) - ],, -lkrb5 -ldes -lasn1 -lroken -lcrypt -lcom_err) - fi - - dnl Old MIT Kerberos V - dnl Note: older krb5 distributions use -lcrypto instead of - dnl -lk5crypto, which collides with OpenSSL. One way of dealing - dnl with that is to extract all objects from krb5's libcrypto - dnl and from openssl's libcrypto into the same directory, then - dnl to create a new libcrypto from these. - if test x$gss_type = xnone - then - AC_CHECK_LIB(gssapi_krb5, g_order_init, [ - gss_type="OldMIT", - MUTTLIBS="$MUTTLIBS -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err" - ],, -lkrb5 -lcrypto -lcom_err) - fi - - if test x$gss_type = xnone - then - AC_CACHE_SAVE - AC_MSG_ERROR([GSSAPI support not found]) - fi - - LIBS="$saved_LIBS" - AC_DEFINE(USE_GSS) - need_gss="yes" - fi - -]) +AC_ARG_WITH(gss, [ --with-gss[=PFX] Compile in GSSAPI authentication for IMAP], + gss_prefix="$withval", gss_prefix="no") +if test "$gss_prefix" != "no" +then + if test "$need_imap" = "yes" + then + MUTT_AM_PATH_GSSAPI(gss_prefix) + AC_MSG_CHECKING(GSSAPI implementation) + AC_MSG_RESULT($GSSAPI_IMPL) + if test "$GSSAPI_IMPL" = "none" + then + AC_CACHE_SAVE + AC_MSG_RESULT([GSSAPI libraries not found]) + fi + if test "$GSSAPI_IMPL" = "Heimdal" + then + AC_DEFINE(HAVE_HEIMDAL, 1, [ Define if your GSSAPI implementation is Heimdal ]) + fi + CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS" + MUTTLIBS="$MUTTLIBS $GSSAPI_LIBS" + AC_DEFINE(USE_GSS, 1, [ Define if you have GSSAPI libraries available ]) + need_gss="yes" + else + AC_MSG_WARN([GSS was requested but IMAP is not enabled]) + fi +fi AM_CONDITIONAL(USE_GSS, test x$need_gss = xyes) AC_ARG_WITH(ssl, [ --with-ssl[=PFX] Compile in SSL support for POP/IMAP], @@ -717,7 +682,7 @@ AC_ARG_WITH(nss, [ --with-nss[=PFX] Compile in SSL support for POP/IM dnl -- end imap dependencies -- -AC_ARG_WITH(sasl, [ --with-sasl[=DIR] Use Cyrus SASL library for POP/IMAP authentication], +AC_ARG_WITH(sasl, [ --with-sasl[=PFX] Use Cyrus SASL library for POP/IMAP authentication], [ if test "$need_socket" != "yes" then diff --git a/globals.h b/globals.h index 1888d4468..874b6d882 100644 --- a/globals.h +++ b/globals.h @@ -64,6 +64,7 @@ WHERE char *MsgFmt; #ifdef USE_SOCKET WHERE char *Preconnect INITVAL (NULL); +WHERE char *Tunnel INITVAL (NULL); #endif /* USE_SOCKET */ #ifdef MIXMASTER diff --git a/imap/auth.c b/imap/auth.c index 97ac5d120..e7c3661dd 100644 --- a/imap/auth.c +++ b/imap/auth.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1996-8 Michael R. Elkins * Copyright (C) 1996-9 Brandon Long - * Copyright (C) 1999-2000 Brendan Cully + * Copyright (C) 1999-2001 Brendan Cully * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/imap/auth_gss.c b/imap/auth_gss.c index a269230c8..cfd7d2ade 100644 --- a/imap/auth_gss.c +++ b/imap/auth_gss.c @@ -83,6 +83,23 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) maj_stat = gss_release_buffer (&min_stat, &request_buf); } #endif + /* Acquire initial credentials - without a TGT GSSAPI is UNAVAIL */ + sec_token = GSS_C_NO_BUFFER; + context = GSS_C_NO_CONTEXT; + + /* build token */ + maj_stat = gss_init_sec_context (&min_stat, GSS_C_NO_CREDENTIAL, &context, + target_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, + GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL, &send_token, + (unsigned int*) &cflags, NULL); + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + { + dprint (1, (debugfile, "Error acquiring credentials - no TGT?\n")); + gss_release_name (&min_stat, &target_name); + + return IMAP_AUTH_UNAVAIL; + } + /* now begin login */ mutt_message _("Authenticating (GSSAPI)..."); @@ -102,62 +119,48 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) /* now start the security context initialisation loop... */ dprint (2, (debugfile, "Sending credentials\n")); - sec_token = GSS_C_NO_BUFFER; - context = GSS_C_NO_CONTEXT; - do + mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length, + sizeof (buf1) - 2); + gss_release_buffer (&min_stat, &send_token); + strncat (buf1, "\r\n", sizeof (buf1)); + mutt_socket_write (idata->conn, buf1); + + while (maj_stat == GSS_S_CONTINUE_NEEDED) { - /* build token */ - maj_stat = gss_init_sec_context (&min_stat, - GSS_C_NO_CREDENTIAL, - &context, - target_name, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - sec_token, - NULL, - &send_token, - (unsigned int*) &cflags, - NULL); - if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + /* Read server data */ + do + rc = imap_cmd_step (idata); + while (rc == IMAP_CMD_CONTINUE); + + if (rc != IMAP_CMD_RESPOND) { - dprint (1, (debugfile, "Error exchanging credentials\n")); + dprint (1, (debugfile, "Error receiving server response.\n")); gss_release_name (&min_stat, &target_name); - /* end authentication attempt */ - mutt_socket_write (idata->conn, "*\r\n"); - do - rc = imap_cmd_step (idata); - while (rc == IMAP_CMD_CONTINUE); goto bail; } - /* send token */ + request_buf.length = mutt_from_base64 (buf2, idata->cmd.buf + 2); + request_buf.value = buf2; + sec_token = &request_buf; + + /* Write client data */ + maj_stat = gss_init_sec_context (&min_stat, GSS_C_NO_CREDENTIAL, &context, + target_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, + GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL, &send_token, + (unsigned int*) &cflags, NULL); + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + { + dprint (1, (debugfile, "Error exchanging credentials\n")); + gss_release_name (&min_stat, &target_name); + + goto err_abort_cmd; + } mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length, sizeof (buf1) - 2); gss_release_buffer (&min_stat, &send_token); strncat (buf1, "\r\n", sizeof (buf1)); mutt_socket_write (idata->conn, buf1); - - if (maj_stat == GSS_S_CONTINUE_NEEDED) - { - do - rc = imap_cmd_step (idata); - while (rc == IMAP_CMD_CONTINUE); - - if (rc != IMAP_CMD_RESPOND) - { - dprint (1, (debugfile, "Error receiving server response.\n")); - gss_release_name (&min_stat, &target_name); - goto bail; - } - - request_buf.length = mutt_from_base64 (buf2, idata->cmd.buf + 2); - request_buf.value = buf2; - sec_token = &request_buf; - } } - while (maj_stat == GSS_S_CONTINUE_NEEDED); gss_release_name (&min_stat, &target_name); @@ -180,8 +183,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) { dprint (2, (debugfile, "Couldn't unwrap security level data\n")); gss_release_buffer (&min_stat, &send_token); - mutt_socket_write(idata->conn, "*\r\n"); - goto bail; + goto err_abort_cmd; } dprint (2, (debugfile, "Credential exchange complete\n")); @@ -189,10 +191,9 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) server_conf_flags = ((char*) send_token.value)[0]; if ( !(((char*) send_token.value)[0] & GSS_AUTH_P_NONE) ) { - dprint (2, (debugfile, "Server requires integrity or privace\n")); + dprint (2, (debugfile, "Server requires integrity or privacy\n")); gss_release_buffer (&min_stat, &send_token); - mutt_socket_write(idata->conn, "*\r\n"); - goto bail; + goto err_abort_cmd; } /* we don't care about buffer size if we don't wrap content. But here it is */ @@ -218,8 +219,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) if (maj_stat != GSS_S_COMPLETE) { dprint (2, (debugfile, "Error creating login request\n")); - mutt_socket_write(idata->conn, "*\r\n"); - goto bail; + goto err_abort_cmd; } mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length, @@ -233,11 +233,10 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) do rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); - if (rc != IMAP_CMD_OK) + if (rc == IMAP_CMD_RESPOND) { - dprint (1, (debugfile, "Error receiving server response.\n")); - mutt_socket_write(idata->conn, "*\r\n"); - goto bail; + dprint (1, (debugfile, "Unexpected server continuation request.\n")); + goto err_abort_cmd; } if (imap_code (idata->cmd.buf)) { @@ -245,10 +244,8 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) dprint (2, (debugfile, "Releasing GSS credentials\n")); maj_stat = gss_delete_sec_context (&min_stat, &context, &send_token); if (maj_stat != GSS_S_COMPLETE) - { dprint (1, (debugfile, "Error releasing credentials\n")); - goto bail; - } + /* send_token may contain a notification to the server to flush * credentials. RFC 1731 doesn't specify what to do, and since this * support is only for authentication, we'll assume the server knows @@ -257,6 +254,14 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) return IMAP_AUTH_SUCCESS; } + else + goto bail; + + err_abort_cmd: + mutt_socket_write (idata->conn, "*\r\n"); + do + rc = imap_cmd_step (idata); + while (rc == IMAP_CMD_CONTINUE); bail: mutt_error _("GSSAPI authentication failed."); diff --git a/imap/auth_sasl.c b/imap/auth_sasl.c index 7eb78131c..640e434f9 100644 --- a/imap/auth_sasl.c +++ b/imap/auth_sasl.c @@ -110,6 +110,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata) } if (!client_start) + { do { rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); @@ -117,6 +118,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); + } else client_start = 0; @@ -144,6 +146,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata) if (rc < 0) { mutt_socket_write (idata->conn, "*\r\n"); + dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc)); } } diff --git a/imap/imap.c b/imap/imap.c index 8f911dc3b..7d9c9d77c 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -66,7 +66,6 @@ int imap_access (const char* path, int flags) FREE (&mx.mbox); return -1; } - imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox)); FREE (&mx.mbox); diff --git a/init.h b/init.h index 915606b7c..9300057aa 100644 --- a/init.h +++ b/init.h @@ -1492,7 +1492,7 @@ struct option_t MuttVars[] = { ** .pp ** Mutt allows you to indefinitely ``$postpone sending a message'' which ** you are editing. When you choose to postpone a message, Mutt saves it - ** in the mail folder specified by this variable. Also see the ``$$postpone'' + ** in the mailbox specified by this variable. Also see the ``$$postpone'' ** variable. */ #ifdef USE_SOCKET @@ -2128,6 +2128,20 @@ struct option_t MuttVars[] = { ** by \fIyou\fP. The sixth character is used to indicate when a mail ** was sent to a mailing-list you subscribe to (default: L). */ +#ifdef USE_SOCKET + { "tunnel", DT_STR, R_NONE, UL &Tunnel, UL 0 }, + /* + ** .pp + ** Setting this variable will cause mutt to open a pipe to a command + ** instead of a raw socket. You may be able to use this to set up + ** preauthenticated connections to your IMAP/POP3 server. Example: + ** .pp + ** tunnel="ssh -q mailhost.net /usr/local/libexec/imapd" + ** .pp + ** NOTE: For this example to work you must be able to log in to the remote + ** machine without having to enter a password. + */ +#endif { "use_8bitmime", DT_BOOL, R_NONE, OPTUSE8BITMIME, 0 }, /* ** .pp diff --git a/m4/gssapi.m4 b/m4/gssapi.m4 new file mode 100644 index 000000000..31382157a --- /dev/null +++ b/m4/gssapi.m4 @@ -0,0 +1,73 @@ +# gssapi.m4: Find GSSAPI libraries in either Heimdal or MIT implementations +# Brendan Cully 20010529 + +dnl MUTT_AM_PATH_GSSAPI(PREFIX) +dnl Search for a GSSAPI implementation in the standard locations plus PREFIX, +dnl if it is set and not "yes". +dnl Defines GSSAPI_CFLAGS and GSSAPI_LIBS if found. +dnl Defines GSSAPI_IMPL to "Heimdal", "MIT", or "OldMIT", or "none" if not found +AC_DEFUN(MUTT_AM_PATH_GSSAPI, +[ + GSSAPI_PREFIX=[$]$1 + GSSAPI_IMPL="none" + dnl First try krb5-config + if test "$GSSAPI_PREFIX" != "yes" + then + krb5_path="$GSSAPI_PREFIX/bin" + else + krb5_path="$PATH" + fi + AC_PATH_PROG(KRB5CFGPATH, krb5-config, none, $krb5_path) + if test "$KRB5CFGPATH" != "none" + then + GSSAPI_CFLAGS="$CPPFLAGS `$KRB5CFGPATH --cflags gssapi`" + GSSAPI_LIBS="$MUTTLIBS `$KRB5CFGPATH --libs gssapi`" + GSSAPI_IMPL="Heimdal" + else + dnl No krb5-config, run the old code + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" + saved_LIBS="$LIBS" + if test "$GSSAPI_PREFIX" != "yes" + then + GSSAPI_CFLAGS="-I$GSSAPI_PREFIX/include" + GSSAPI_LDFLAGS="-L$GSSAPI_PREFIX/lib" + CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS" + LDFLAGS="$LDFLAGS $GSSAPI_LDFLAGS" + fi + + dnl New MIT kerberos V support + AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, [ + GSSAPI_IMPL="MIT", + GSSAPI_LIBS="$GSSAPI_LDFLAGS -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err" + ],, -lkrb5 -lk5crypto -lcom_err) + + dnl Heimdal kerberos V support + if test "$GSSAPI_IMPL" = "none" + then + AC_CHECK_LIB(gssapi, gss_init_sec_context, [ + GSSAPI_IMPL="Heimdal" + GSSAPI_LIBS="$GSSAPI_LDFLAGS -lgssapi -lkrb5 -ldes -lasn1 -lroken" + GSSAPI_LIBS="$GSSAPI_LIBS -lcrypt -lcom_err" + ],, -lkrb5 -ldes -lasn1 -lroken -lcrypt -lcom_err) + fi + + dnl Old MIT Kerberos V + dnl Note: older krb5 distributions use -lcrypto instead of + dnl -lk5crypto, which collides with OpenSSL. One way of dealing + dnl with that is to extract all objects from krb5's libcrypto + dnl and from openssl's libcrypto into the same directory, then + dnl to create a new libcrypto from these. + if test "$GSSAPI_IMPL" = "none" + then + AC_CHECK_LIB(gssapi_krb5, g_order_init, [ + GSSAPI_IMPL="OldMIT", + GSSAPI_LIBS="$GSSAPI_LDFLAGS -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err" + ],, -lkrb5 -lcrypto -lcom_err) + fi + fi + + CPPFLAGS="$saved_CPPFLAGS" + LDFLAGS="$saved_LDFLAGS" + LIBS="$saved_LIBS" +]) \ No newline at end of file diff --git a/mutt_socket.c b/mutt_socket.c index 44771459f..f00e09f16 100644 --- a/mutt_socket.c +++ b/mutt_socket.c @@ -21,6 +21,7 @@ #include "mutt.h" #include "globals.h" #include "mutt_socket.h" +#include "mutt_tunnel.h" #ifdef USE_SSL # include "mutt_ssl.h" #endif @@ -201,7 +202,9 @@ CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account) conn->next = Connections; Connections = conn; - if (account->flags & M_ACCT_SSL) + if (Tunnel && *Tunnel) + mutt_tunnel_socket_setup (conn); + else if (account->flags & M_ACCT_SSL) { #ifdef USE_SSL ssl_socket_setup (conn); @@ -226,16 +229,11 @@ CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account) return conn; } -/* socket_connect: set up to connect to a socket fd. Preconnect goes here. */ -static int socket_connect (int fd, struct sockaddr* sa) +int mutt_socket_preconnect (void) { - int sa_size; int rc; int save_errno; - /* old first_try_without_preconnect removed for now. unset $preconnect - first. */ - if (mutt_strlen (Preconnect)) { dprint (1, (debugfile, "Executing preconnect: %s\n", Preconnect)); @@ -251,6 +249,19 @@ static int socket_connect (int fd, struct sockaddr* sa) } } + return 0; +} + +/* socket_connect: set up to connect to a socket fd. */ +static int socket_connect (int fd, struct sockaddr* sa) +{ + int sa_size; + int rc; + int save_errno; + + if ((rc = mutt_socket_preconnect ())) + return rc; + if (sa->sa_family == AF_INET) sa_size = sizeof (struct sockaddr_in); #ifdef HAVE_GETADDRINFO diff --git a/mutt_socket.h b/mutt_socket.h index b20767da8..e508ee315 100644 --- a/mutt_socket.h +++ b/mutt_socket.h @@ -63,6 +63,9 @@ CONNECTION* mutt_socket_head (void); void mutt_socket_free (CONNECTION* conn); CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account); +/* other methods may call this to try preconnect code */ +int mutt_socket_preconnect (void); + int raw_socket_read (CONNECTION *conn); int raw_socket_write (CONNECTION* conn, const char* buf, size_t count); int raw_socket_open (CONNECTION *conn); diff --git a/mutt_tunnel.c b/mutt_tunnel.c new file mode 100644 index 000000000..0f26e6e70 --- /dev/null +++ b/mutt_tunnel.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2000 Manoj Kasichainula + * Copyright (C) 2001 Brendan Cully + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ + +#include "mutt.h" +#include "mutt_socket.h" +#include "mutt_tunnel.h" + +#include +#include +#include +#include + +/* -- data types -- */ +typedef struct +{ + pid_t pid; +} TUNNEL_DATA; + +/* forward declarations */ +static int tunnel_socket_open (CONNECTION*); +static int tunnel_socket_close (CONNECTION*); + +/* -- public functions -- */ +int mutt_tunnel_socket_setup (CONNECTION *conn) +{ + conn->open = tunnel_socket_open; + conn->read = raw_socket_read; + conn->write = raw_socket_write; + conn->close = tunnel_socket_close; + + return 0; +} + +static int tunnel_socket_open (CONNECTION *conn) +{ + TUNNEL_DATA* tunnel; + int pid; + int rc; + int sv[2]; + + mutt_message (_("Connecting with \"%s\"..."), Tunnel); + + if ((rc = mutt_socket_preconnect ())) + return rc; + + rc = socketpair (PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv); + if (rc == -1) + { + mutt_perror ("socketpair"); + return -1; + } + + if ((pid = fork ()) == 0) + { + mutt_block_signals_system (); + if (close (sv[0]) < 0 || + dup2 (sv[1], STDIN_FILENO) < 0 || + dup2 (sv[1], STDOUT_FILENO) < 0 || + close (sv[1]) < 0) + _exit (127); + + execl (EXECSHELL, "sh", "-c", Tunnel, NULL); + _exit (127); + } + if (pid == -1) + { + close (sv[0]); + close (sv[1]); + mutt_perror ("fork"); + return -1; + } + if (close(sv[1]) < 0) + mutt_perror ("close"); + + conn->fd = sv[0]; + tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA)); + tunnel->pid = pid; + + return 0; +} + +static int tunnel_socket_close (CONNECTION* conn) +{ + TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->data; + + if (!tunnel) + return 0; + + waitpid (tunnel->pid, NULL, 0); + close (conn->fd); + conn->fd = -1; + FREE (&conn->data); + + return 0; +} diff --git a/mutt_tunnel.h b/mutt_tunnel.h new file mode 100644 index 000000000..b6e20afdf --- /dev/null +++ b/mutt_tunnel.h @@ -0,0 +1,24 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ + +#ifndef _MUTT_TUNNEL_H_ +#define _MUTT_TUNNEL_H_ 1 + +#include "mutt_socket.h" + +int mutt_tunnel_socket_setup (CONNECTION *); + +#endif /* _MUTT_TUNNEL_H_ */ -- 2.40.0