* Move (nearly) all IPC-related code to citadel_ipc.[ch].
authorMichael Hampton <io_error@uncensored.citadel.org>
Sun, 6 Oct 2002 18:46:30 +0000 (18:46 +0000)
committerMichael Hampton <io_error@uncensored.citadel.org>
Sun, 6 Oct 2002 18:46:30 +0000 (18:46 +0000)
citadel/ChangeLog
citadel/citadel.c
citadel/citadel_ipc.c
citadel/citadel_ipc.h
citadel/client_crypto.c [deleted file]
citadel/client_crypto.h [deleted file]
citadel/ipc.h [deleted file]
citadel/ipc_c_tcp.c
citadel/routines2.c

index 3eb613ad07ec166ff91cc4cca96de81cc5db23f6..dffd9987b0833d30da026196deaafb613dc4d963 100644 (file)
@@ -1,4 +1,7 @@
  $Log$
+ Revision 601.19  2002/10/06 18:46:30  error
+ * Move (nearly) all IPC-related code to citadel_ipc.[ch].
+
  Revision 601.18  2002/10/05 04:48:29  ajc
  * Change MAXSETUP from 4 to 3 (bug reported by mavherzog, fix suggested by IO)
 
@@ -4049,3 +4052,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
+
index 7ad8d3397e52fe7af205a8a37cd086d2cb87acb9..64649facedd77871228e5c44a89f31f0406a2509 100644 (file)
@@ -46,7 +46,6 @@
 #include "citadel_decls.h"
 #include "tools.h"
 #include "acconfig.h"
-#include "client_crypto.h"
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
 #endif
@@ -962,7 +961,7 @@ int main(int argc, char **argv)
                if (!strcmp(argv[a], "-X")) {
 #ifdef HAVE_OPENSSL
                        arg_encrypt = RC_YES;
-                        argc = shift(argc, argv, a, 1);
+                       argc = shift(argc, argv, a, 1);
 #else
                        fprintf(stderr, "Not compiled with encryption support");
                        return 1;
@@ -1007,8 +1006,8 @@ int main(int argc, char **argv)
                                        logoff(NULL, 3);
                                }
                                /*
-                               scr_printf("Privileges changed to uid %d gid %d\n",
-                                               getuid(), getgid());
+                                 scr_printf("Privileges changed to uid %d gid %d\n",
+                                 getuid(), getgid());
                                */
                        }
                        argc = shift(argc, argv, a, 1);
@@ -1020,6 +1019,11 @@ int main(int argc, char **argv)
        sln_printf("Attaching to server... \r");
        sln_flush();
        ipc = CtdlIPC_new(argc, argv, hostbuf, portbuf);
+       if (!ipc) {
+               screen_delete();
+               error_printf("Can't connect: %s\n", strerror(errno));
+               logoff(NULL, 3);
+       }
        ipc_for_signal_handlers = ipc;  /* KLUDGE cover your eyes */
 
        CtdlIPC_getline(ipc, aaa);
@@ -1028,37 +1032,44 @@ int main(int argc, char **argv)
                logoff(ipc, atoi(aaa));
        }
 
-/* If there is a [nonce] at the end, put the nonce in <nonce>, else nonce
- * is zeroized.
- */
+       /* If there is a [nonce] at the end, put the nonce in <nonce>, else nonce
       * is zeroized.
       */
        
        if ((sptr = strchr(aaa, '<')) == NULL)
-       {
-          nonce[0] = '\0';
-       }
+               {
+                       nonce[0] = '\0';
+               }
        else
-       {
-          if ((sptr2 = strchr(sptr, '>')) == NULL)
-          {
-             nonce[0] = '\0';
-          }
-          else
-          {
-             sptr2++;
-             *sptr2 = '\0';
-             strncpy(nonce, sptr, NONCE_SIZE);
-          }
+               {
+                       if ((sptr2 = strchr(sptr, '>')) == NULL)
+                               {
+                                       nonce[0] = '\0';
+                               }
+                       else
+                               {
+                                       sptr2++;
+                                       *sptr2 = '\0';
+                                       strncpy(nonce, sptr, NONCE_SIZE);
+                               }
+               }
+
+       /* Evaluate encryption preferences */
+       if (arg_encrypt != RC_NO && rc_encrypt != RC_NO) {
+               if (!ipc->isLocal || arg_encrypt == RC_YES || rc_encrypt == RC_YES) {
+                       secure = (CtdlIPCStartEncryption(ipc, aaa) / 100 == 2) ? 1 : 0;
+                       if (!secure)
+                               error_printf("Can't encrypt: %s\n", aaa);
+               }
        }
 
        get_serv_info(ipc, telnet_client_host);
-
        scr_printf("%-24s\n%s\n%s\n", serv_info.serv_software, serv_info.serv_humannode,
-               serv_info.serv_bbs_city);
+                  serv_info.serv_bbs_city);
        scr_flush();
 
-       secure = starttls(ipc);
        status_line(serv_info.serv_humannode, serv_info.serv_bbs_city, NULL,
-                       secure, -1);
+                   secure, -1);
 
        screenwidth = 80;       /* default screen dimensions */
        screenheight = 24;
@@ -1068,7 +1079,7 @@ int main(int argc, char **argv)
        formout(ipc, "hello");  /* print the opening greeting */
        scr_printf("\n");
 
-GSTA:  /* See if we have a username and password on disk */
+ GSTA: /* See if we have a username and password on disk */
        if (rc_remember_passwords) {
                get_stored_password(hostbuf, portbuf, fullname, password);
                if (strlen(fullname) > 0) {
@@ -1076,13 +1087,13 @@ GSTA:   /* See if we have a username and password on disk */
                        CtdlIPC_putline(ipc, aaa);
                        CtdlIPC_getline(ipc, aaa);
                        if (nonce[0])
-                       {
-                               snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
-                       }
+                               {
+                                       snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
+                               }
                        else    /* Else no APOP */
-                       {
-                               snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
-                       }
+                               {
+                                       snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
+                               }
                        
                        CtdlIPC_putline(ipc, aaa);
                        CtdlIPC_getline(ipc, aaa);
@@ -1110,9 +1121,9 @@ GSTA:     /* See if we have a username and password on disk */
                        scr_printf("Please enter the name you wish to log in with.\n");
                }
        } while (
-                       (!strcasecmp(fullname, "bbs"))
-                       || (!strcasecmp(fullname, "new"))
-                       || (strlen(fullname) == 0));
+                (!strcasecmp(fullname, "bbs"))
+                || (!strcasecmp(fullname, "new"))
+                || (strlen(fullname) == 0));
 
        if (!strcasecmp(fullname, "off")) {
                mcmd = 29;
@@ -1132,20 +1143,20 @@ GSTA:   /* See if we have a username and password on disk */
        strproc(password);
 
        if (nonce[0])
-       {
-               snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
-       }
+               {
+                       snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
+               }
        else    /* Else no APOP */
-       {
-               snprintf(aaa, sizeof aaa, "PASS %s", password);
-       }
+               {
+                       snprintf(aaa, sizeof aaa, "PASS %s", password);
+               }
        
        CtdlIPC_putline(ipc, aaa);
        CtdlIPC_getline(ipc, aaa);
        if (aaa[0] == '2') {
                load_user_info(&aaa[4]);
                offer_to_remember_password(hostbuf, portbuf,
-                                       fullname, password);
+                                          fullname, password);
                goto PWOK;
        }
        scr_printf("<< wrong password >>\n");
@@ -1153,11 +1164,11 @@ GSTA:   /* See if we have a username and password on disk */
                logoff(ipc, 0);
        goto GSTA;
 
-NEWUSR:        if (strlen(rc_password) == 0) {
-               scr_printf("No record. Enter as new user? ");
-               if (yesno() == 0)
-                       goto GSTA;
      }
+ NEWUSR:       if (strlen(rc_password) == 0) {
+        scr_printf("No record. Enter as new user? ");
+        if (yesno() == 0)
+                goto GSTA;
+ }
        snprintf(aaa, sizeof aaa, "NEWU %s", fullname);
        CtdlIPC_putline(ipc, aaa);
        CtdlIPC_getline(ipc, aaa);
@@ -1172,7 +1183,7 @@ NEWUSR:   if (strlen(rc_password) == 0) {
 
        enter_config(ipc, 1);
 
-PWOK:
+ PWOK:
        /* Switch color support on or off if we're in user mode */
        if (rc_ansi_color == 3) {
                if (userflags & US_COLOR)
@@ -1182,12 +1193,12 @@ PWOK:
        }
 
        scr_printf("%s\nAccess level: %d (%s)\n"
-               "User #%ld / Login #%d",
-               fullname, axlevel, axdefs[(int) axlevel],
-               usernum, timescalled);
+                  "User #%ld / Login #%d",
+                  fullname, axlevel, axdefs[(int) axlevel],
+                  usernum, timescalled);
        if (lastcall > 0L) {
                scr_printf(" / Last login: %s\n",
-                       asctime(localtime(&lastcall)) );
+                          asctime(localtime(&lastcall)) );
        }
        scr_printf("\n");
 
@@ -1249,8 +1260,8 @@ PWOK:
        /* Enter the lobby */
        dotgoto(ipc, "_BASEROOM_", 1, 0);
 
-/* Main loop for the system... user is logged in. */
-    uglistsize = 0;
+       /* Main loop for the system... user is logged in. */
+       uglistsize = 0;
 
        if (newnow == 1)
                readmsgs(ipc, 3, 1, 5);
@@ -1477,7 +1488,7 @@ PWOK:
 
                        case 85:
                                scr_printf("All users will be disconnected!  "
-                                       "Really terminate the server? ");
+                                          "Really terminate the server? ");
                                if (yesno() == 1) {
                                        r = CtdlIPCTerminateServerNow(ipc, aaa);
                                        scr_printf("%s\n", aaa);
@@ -1491,18 +1502,18 @@ PWOK:
 
                        case 86:
                                scr_printf("Do you really want to schedule a "
-                                       "server shutdown? ");
+                                          "server shutdown? ");
                                if (yesno() == 1) {
                                        r = CtdlIPCTerminateServerScheduled(ipc, 1, aaa);
                                        if (r / 100 == 2) {
                                                if (atoi(aaa)) {
                                                        scr_printf(
-"The Citadel server will terminate when all users are logged off.\n"
-                                                               );
+                                                                  "The Citadel server will terminate when all users are logged off.\n"
+                                                                  );
                                                } else {
                                                        scr_printf(
-"The Citadel server will not terminate.\n"
-                                                               );
+                                                                  "The Citadel server will not terminate.\n"
+                                                                  );
                                                }
                                        }
                                }
@@ -1510,17 +1521,17 @@ PWOK:
 
                        case 87:
                                network_config_management(ipc, "listrecp",
-                                "Message-by-message mailing list recipients");
+                                                         "Message-by-message mailing list recipients");
                                break;
 
                        case 94:
                                network_config_management(ipc, "digestrecp",
-                                "Digest mailing list recipients");
+                                                         "Digest mailing list recipients");
                                break;
 
                        case 89:
                                network_config_management(ipc, "ignet_push_share",
-                                       "Nodes with which we share this room");
+                                                         "Nodes with which we share this room");
                                break;
 
                        case 88:
@@ -1547,7 +1558,7 @@ PWOK:
                                        sttybbs(SB_RESTORE);
                                        snprintf(aaa, sizeof aaa, "USERNAME=\042%s\042; export USERNAME;"
                                                 "exec ./subsystem %ld %d %d", fullname,
-                                         usernum, screenwidth, axlevel);
+                                                usernum, screenwidth, axlevel);
                                        ka_system(aaa);
                                        sttybbs(SB_NO_INTR);
                                        screen_set();
@@ -1564,9 +1575,9 @@ PWOK:
                                who_is_online(ipc, 1);
                                break;
 
-            case 91:
-                who_is_online(ipc, 2);
-                break;
+                       case 91:
+                               who_is_online(ipc, 2);
+                               break;
                 
                        case 80:
                                do_system_configuration(ipc);
@@ -1680,7 +1691,7 @@ PWOK:
                        }       /* end switch */
        } while (termn8 == 0);
 
-TERMN8:        scr_printf("%s logged out.\n", fullname);
+ TERMN8:       scr_printf("%s logged out.\n", fullname);
        while (march != NULL) {
                remove_march(march->march_name, 0);
        }
index 2377445120e5341da886a097386c5d78cc94f1fa..5162ece6721622bbd56082830fb0ad2f6057626b 100644 (file)
@@ -1,5 +1,9 @@
 /* $Id$ */
 
+#define        UDS                     "_UDS_"
+#define DEFAULT_HOST           UDS
+#define DEFAULT_PORT           "citadel"
+
 #include "sysdep.h"
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
 #  include <time.h>
 # endif
 #endif
+#include <unistd.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <string.h>
 #include <malloc.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/un.h>
 #ifdef THREADED_CLIENT
 #include <pthread.h>
 #endif
 #include "citadel.h"
 #include "citadel_ipc.h"
 #include "citadel_decls.h"
-#include "client_crypto.h"
 #include "tools.h"
 
 #ifdef THREADED_CLIENT
 pthread_mutex_t rwlock;
 #endif
+
+#ifdef HAVE_OPENSSL
+static SSL_CTX *ssl_ctx;
+char arg_encrypt;
+char rc_encrypt;
+#ifdef THREADED_CLIENT
+pthread_mutex_t **Critters;                    /* Things that need locking */
+#endif /* THREADED_CLIENT */
+
+#endif /* HAVE_OPENSSL */
+
+
+static void (*status_hook)(char *s) = NULL;
+
+void setCryptoStatusHook(void (*hook)(char *s)) {
+       status_hook = hook;
+}
+
+
 char express_msgs = 0;
 
 
+static void serv_read(CtdlIPC *ipc, char *buf, int bytes);
+static void serv_write(CtdlIPC *ipc, const char *buf, int nbytes);
+#ifdef HAVE_OPENSSL
+static void serv_read_ssl(CtdlIPC *ipc, char *buf, int bytes);
+static void serv_write_ssl(CtdlIPC *ipc, const char *buf, int nbytes);
+static void ssl_lock(int mode, int n, const char *file, int line);
+static void endtls(SSL *ssl);
+#ifdef THREADED_CLIENT
+static unsigned long id_callback(void);
+#endif /* THREADED_CLIENT */
+#endif /* HAVE_OPENSSL */
+
+
 /*
  * Does nothing.  The server should always return 200.
  */
@@ -1754,10 +1795,97 @@ int CtdlIPCSetMessageSeen(CtdlIPC *ipc, long msgnum, int seen, char *cret)
 /* STLS */
 int CtdlIPCStartEncryption(CtdlIPC *ipc, char *cret)
 {
-       return CtdlIPCGenericCommand(ipc, "STLS", NULL, 0, NULL, NULL, cret);
+       int a;
+       int r;
+       char buf[SIZ];
+
+#ifdef HAVE_OPENSSL
+       SSL *temp_ssl;
+
+       /* New SSL object */
+       temp_ssl = SSL_new(ssl_ctx);
+       if (!temp_ssl) {
+               error_printf("SSL_new failed: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               return -2;
+       }
+       /* Pointless flag waving */
+#if SSLEAY_VERSION_NUMBER >= 0x0922
+       SSL_set_session_id_context(temp_ssl, "Citadel/UX SID", 14);
+#endif
+
+       if (!access("/var/run/egd-pool", F_OK))
+               RAND_egd("/var/run/egd-pool");
+
+       if (!RAND_status()) {
+               error_printf("PRNG not properly seeded\n");
+               return -2;
+       }
+
+       /* Associate network connection with SSL object */
+       if (SSL_set_fd(temp_ssl, ipc->sock) < 1) {
+               error_printf("SSL_set_fd failed: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               return -2;
+       }
+
+       if (status_hook != NULL)
+               status_hook("Requesting encryption...\r");
+
+       /* Ready to start SSL/TLS */
+       /* Old code
+       CtdlIPC_putline(ipc, "STLS");
+       CtdlIPC_getline(ipc, buf);
+       if (buf[0] != '2') {
+               error_printf("Server can't start TLS: %s\n", buf);
+               return 0;
+       }
+       */
+       r = CtdlIPCGenericCommand(ipc,
+                                 "STLS", NULL, 0, NULL, NULL, cret);
+       if (r / 100 != 2) {
+               error_printf("Server can't start TLS: %s\n", buf);
+               endtls(temp_ssl);
+               return r;
+       }
+
+       /* Do SSL/TLS handshake */
+       if ((a = SSL_connect(temp_ssl)) < 1) {
+               error_printf("SSL_connect failed: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               endtls(temp_ssl);
+               return -2;
+       }
+       ipc->ssl = temp_ssl;
+
+       BIO_set_close(ipc->ssl->rbio, BIO_NOCLOSE);
+       {
+               int bits, alg_bits;
+
+               bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ipc->ssl), &alg_bits);
+               error_printf("Encrypting with %s cipher %s (%d of %d bits)\n",
+                               SSL_CIPHER_get_version(SSL_get_current_cipher(ipc->ssl)),
+                               SSL_CIPHER_get_name(SSL_get_current_cipher(ipc->ssl)),
+                               bits, alg_bits);
+       }
+       return r;
+#else
+       return 0;
+#endif /* HAVE_OPENSSL */
 }
 
 
+#ifdef HAVE_OPENSSL
+static void endtls(SSL *ssl)
+{
+       if (ssl) {
+               SSL_shutdown(ssl);
+               SSL_free(ssl);
+       }
+}
+#endif
+
+
 /* QDIR */
 int CtdlIPCDirectoryLookup(CtdlIPC *ipc, const char *address, char *cret)
 {
@@ -2242,3 +2370,449 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc,
        CtdlIPC_unlock(ipc);
        return ret;
 }
+
+
+static int connectsock(char *host, char *service, char *protocol, int defaultPort)
+{
+       struct hostent *phe;
+       struct servent *pse;
+       struct protoent *ppe;
+       struct sockaddr_in sin;
+       int s, type;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+
+       pse = getservbyname(service, protocol);
+       if (pse != NULL) {
+               sin.sin_port = pse->s_port;
+       }
+       else if (atoi(service) > 0) {
+               sin.sin_port = htons(atoi(service));
+       }
+       else {
+               sin.sin_port = htons(defaultPort);
+       }
+       phe = gethostbyname(host);
+       if (phe) {
+               memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
+       } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
+               return -1;
+       }
+       if ((ppe = getprotobyname(protocol)) == 0) {
+               return -1;
+       }
+       if (!strcmp(protocol, "udp")) {
+               type = SOCK_DGRAM;
+       } else {
+               type = SOCK_STREAM;
+       }
+
+       s = socket(PF_INET, type, ppe->p_proto);
+       if (s < 0) {
+               return -1;
+       }
+
+       if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+               return -1;
+       }
+
+       return (s);
+}
+
+static int uds_connectsock(int *isLocal, char *sockpath)
+{
+       struct sockaddr_un addr;
+       int s;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0) {
+               return -1;
+       }
+
+       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               return -1;
+       }
+
+       *isLocal = 1;
+       return s;
+}
+
+
+/*
+ * input binary data from socket
+ */
+static void serv_read(CtdlIPC *ipc, char *buf, int bytes)
+{
+       int len, rlen;
+
+#if defined(HAVE_OPENSSL)
+       if (ipc->ssl) {
+               serv_read_ssl(ipc, buf, bytes);
+               return;
+       }
+#endif
+       len = 0;
+       while (len < bytes) {
+               rlen = read(ipc->sock, &buf[len], bytes - len);
+               if (rlen < 1) {
+                       connection_died(ipc);
+                       return;
+               }
+               len += rlen;
+       }
+}
+
+
+/*
+ * send binary to server
+ */
+static void serv_write(CtdlIPC *ipc, const char *buf, int nbytes)
+{
+       int bytes_written = 0;
+       int retval;
+
+#if defined(HAVE_OPENSSL)
+       if (ipc->ssl) {
+               serv_write_ssl(ipc, buf, nbytes);
+               return;
+       }
+#endif
+       while (bytes_written < nbytes) {
+               retval = write(ipc->sock, &buf[bytes_written],
+                              nbytes - bytes_written);
+               if (retval < 1) {
+                       connection_died(ipc);
+                       return;
+               }
+               bytes_written += retval;
+       }
+}
+
+
+#ifdef HAVE_OPENSSL
+/*
+ * input binary data from encrypted connection
+ */
+static void serv_read_ssl(CtdlIPC* ipc, char *buf, int bytes)
+{
+       int len, rlen;
+       char junk[1];
+
+       len = 0;
+       while (len < bytes) {
+               if (SSL_want_read(ipc->ssl)) {
+                       if ((SSL_write(ipc->ssl, junk, 0)) < 1) {
+                               error_printf("SSL_write in serv_read:\n");
+                               ERR_print_errors_fp(stderr);
+                       }
+               }
+               rlen = SSL_read(ipc->ssl, &buf[len], bytes - len);
+               if (rlen < 1) {
+                       long errval;
+
+                       errval = SSL_get_error(ipc->ssl, rlen);
+                       if (errval == SSL_ERROR_WANT_READ ||
+                                       errval == SSL_ERROR_WANT_WRITE) {
+                               sleep(1);
+                               continue;
+                       }
+                       if (errval == SSL_ERROR_ZERO_RETURN ||
+                                       errval == SSL_ERROR_SSL) {
+                               serv_read(ipc, &buf[len], bytes - len);
+                               return;
+                       }
+                       error_printf("SSL_read in serv_read:\n");
+                       ERR_print_errors_fp(stderr);
+                       connection_died();
+                       return;
+               }
+               len += rlen;
+       }
+}
+
+
+/*
+ * send binary to server encrypted
+ */
+static void serv_write_ssl(CtdlIPC *ipc, const char *buf, int nbytes)
+{
+       int bytes_written = 0;
+       int retval;
+       char junk[1];
+
+       while (bytes_written < nbytes) {
+               if (SSL_want_write(ipc->ssl)) {
+                       if ((SSL_read(ipc->ssl, junk, 0)) < 1) {
+                               error_printf("SSL_read in serv_write:\n");
+                               ERR_print_errors_fp(stderr);
+                       }
+               }
+               retval = SSL_write(ipc->ssl, &buf[bytes_written],
+                               nbytes - bytes_written);
+               if (retval < 1) {
+                       long errval;
+
+                       errval = SSL_get_error(ipc->ssl, retval);
+                       if (errval == SSL_ERROR_WANT_READ ||
+                                       errval == SSL_ERROR_WANT_WRITE) {
+                               sleep(1);
+                               continue;
+                       }
+                       if (errval == SSL_ERROR_ZERO_RETURN ||
+                                       errval == SSL_ERROR_SSL) {
+                               serv_write(ipc, &buf[bytes_written],
+                                               nbytes - bytes_written);
+                               return;
+                       }
+                       error_printf("SSL_write in serv_write:\n");
+                       ERR_print_errors_fp(stderr);
+                       connection_died();
+                       return;
+               }
+               bytes_written += retval;
+       }
+}
+
+
+static void CtdlIPC_init_OpenSSL(void)
+{
+       int a;
+       SSL_METHOD *ssl_method;
+       DH *dh;
+       
+       /* already done init */
+       if (ssl_ctx) {
+               return;
+       }
+
+       /* Get started */
+       ssl_ctx = NULL;
+       dh = NULL;
+       SSL_load_error_strings();
+       SSLeay_add_ssl_algorithms();
+
+       /* Set up the SSL context in which we will oeprate */
+       ssl_method = SSLv23_client_method();
+       ssl_ctx = SSL_CTX_new(ssl_method);
+       if (!ssl_ctx) {
+               error_printf("SSL_CTX_new failed: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               return;
+       }
+       /* Any reasonable cipher we can get */
+       if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
+               error_printf("No ciphers available for encryption\n");
+               return;
+       }
+       SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
+       
+       /* Load DH parameters into the context */
+       dh = DH_new();
+       if (!dh) {
+               error_printf("Can't allocate a DH object: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               return;
+       }
+       if (!(BN_hex2bn(&(dh->p), DH_P))) {
+               error_printf("Can't assign DH_P: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               DH_free(dh);
+               return;
+       }
+       if (!(BN_hex2bn(&(dh->g), DH_G))) {
+               error_printf("Can't assign DH_G: %s\n",
+                               ERR_reason_error_string(ERR_get_error()));
+               DH_free(dh);
+               return;
+       }
+       dh->length = DH_L;
+       SSL_CTX_set_tmp_dh(ssl_ctx, dh);
+       DH_free(dh);
+
+#ifdef THREADED_CLIENT
+       /* OpenSSL requires callbacks for threaded clients */
+       CRYPTO_set_locking_callback(ssl_lock);
+       CRYPTO_set_id_callback(id_callback);
+
+       /* OpenSSL requires us to do semaphores for threaded clients */
+       Critters = malloc(CRYPTO_num_locks() * sizeof (pthread_mutex_t *));
+       if (!Critters) {
+               perror("malloc failed");
+               exit(1);
+       } else {
+               for (a = 0; a < CRYPTO_num_locks(); a++) {
+                       Critters[a] = malloc(sizeof (pthread_mutex_t));
+                       if (!Critters[a]) {
+                               perror("malloc failed");
+                               exit(1);
+                       }
+                       pthread_mutex_init(Critters[a], NULL);
+               }
+       }
+#endif /* THREADED_CLIENT */       
+}
+
+
+static void ssl_lock(int mode, int n, const char *file, int line)
+{
+#ifdef THREADED_CLIENT
+       if (mode & CRYPTO_LOCK)
+               pthread_mutex_lock(Critters[n]);
+       else
+               pthread_mutex_unlock(Critters[n]);
+#endif /* THREADED_CLIENT */
+}
+
+#ifdef THREADED_CLIENT
+static unsigned long id_callback(void) {
+       return (unsigned long)pthread_self();
+}
+#endif /* THREADED_CLIENT */
+#endif /* HAVE_OPENSSL */
+
+
+/*
+ * input string from socket - implemented in terms of serv_read()
+ */
+void CtdlIPC_getline(CtdlIPC* ipc, char *buf)
+{
+       int i;
+
+       /* Read one character at a time. */
+       for (i = 0;; i++) {
+               serv_read(ipc, &buf[i], 1);
+               if (buf[i] == '\n' || i == (SIZ-1))
+                       break;
+       }
+
+       /* If we got a long line, discard characters until the newline. */
+       if (i == (SIZ-1))
+               while (buf[i] != '\n')
+                       serv_read(ipc, &buf[i], 1);
+
+       /* Strip the trailing newline.
+        */
+       buf[i] = 0;
+}
+
+
+/*
+ * send line to server - implemented in terms of serv_write()
+ */
+void CtdlIPC_putline(CtdlIPC *ipc, const char *buf)
+{
+       /* error_printf("< %s\n", buf); */
+       serv_write(ipc, buf, strlen(buf));
+       serv_write(ipc, "\n", 1);
+
+       ipc->last_command_sent = time(NULL);
+}
+
+
+/*
+ * attach to server
+ */
+CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
+{
+       int a;
+       char cithost[SIZ];
+       char citport[SIZ];
+       char sockpath[SIZ];
+
+       CtdlIPC *ipc = ialloc(CtdlIPC);
+       if (!ipc) {
+               return 0;
+       }
+#if defined(HAVE_OPENSSL)
+       ipc->ssl = NULL;
+       CtdlIPC_init_OpenSSL();
+#endif
+#if defined(HAVE_PTHREAD_H)
+       pthread_mutex_init(&(ipc->mutex), NULL); /* Default fast mutex */
+#endif
+       ipc->sock = -1;                 /* Not connected */
+       ipc->isLocal = 0;               /* Not local, of course! */
+       ipc->downloading = 0;
+       ipc->uploading = 0;
+       ipc->last_command_sent = 0L;
+
+       strcpy(cithost, DEFAULT_HOST);  /* default host */
+       strcpy(citport, DEFAULT_PORT);  /* default port */
+
+       for (a = 0; a < argc; ++a) {
+               if (a == 0) {
+                       /* do nothing */
+               } else if (a == 1) {
+                       strcpy(cithost, argv[a]);
+               } else if (a == 2) {
+                       strcpy(citport, argv[a]);
+               } else {
+                       error_printf("%s: usage: ",argv[0]);
+                       error_printf("%s [host] [port] ",argv[0]);
+                       ifree(ipc);
+                       errno = EINVAL;
+                       return 0;
+               }
+       }
+
+       if ((!strcmp(cithost, "localhost"))
+          || (!strcmp(cithost, "127.0.0.1"))) {
+               ipc->isLocal = 1;
+       }
+
+       /* If we're using a unix domain socket we can do a bunch of stuff */
+       if (!strcmp(cithost, UDS)) {
+               snprintf(sockpath, sizeof sockpath, "citadel.socket");
+               ipc->sock = uds_connectsock(&(ipc->isLocal), sockpath);
+               if (ipc->sock == -1) {
+                       ifree(ipc);
+                       return 0;
+               }
+               if (hostbuf != NULL) strcpy(hostbuf, cithost);
+               if (portbuf != NULL) strcpy(portbuf, sockpath);
+               return ipc;
+       }
+
+       ipc->sock = connectsock(cithost, citport, "tcp", 504);
+       if (ipc->sock == -1) {
+               ifree(ipc);
+               return 0;
+       }
+       if (hostbuf != NULL) strcpy(hostbuf, cithost);
+       if (portbuf != NULL) strcpy(portbuf, citport);
+       return ipc;
+}
+
+/*
+ * return the file descriptor of the server socket so we can select() on it.
+ *
+ * FIXME: This is only used in chat mode; eliminate it when chat mode gets
+ * rewritten...
+ */
+int CtdlIPC_getsockfd(CtdlIPC* ipc)
+{
+       return ipc->sock;
+}
+
+
+/*
+ * return one character
+ *
+ * FIXME: This is only used in chat mode; eliminate it when chat mode gets
+ * rewritten...
+ */
+char CtdlIPC_get(CtdlIPC* ipc)
+{
+       char buf[2];
+       char ch;
+
+       serv_read(ipc, buf, 1);
+       ch = (int) buf[0];
+
+       return (ch);
+}
index 2f834d200bd4c63b8cfd766f861a7982359071fc..25667072c8d8875370c666602bbfa7553f2283b3 100644 (file)
@@ -1,11 +1,61 @@
 /* $Id$ */
 
-#include "ipc.h"
+#include "sysdep.h"
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* Quick and dirty hack; we don't want to use malloc() in C++ */
+#ifdef __cplusplus
+#define ialloc(t)      new t()
+#define ifree(o)       delete o
+#else
+#define ialloc(t)      malloc(sizeof(t))
+#define ifree(o)       free(o);
+#endif
+
+/* This class is responsible for the server connection */
+typedef struct _CtdlIPC {
+#if defined(HAVE_OPENSSL)
+       /* NULL if not encrypted, non-NULL otherwise */
+       SSL *ssl;
+#endif
+#if defined(HAVE_PTHREAD_H)
+       /* Fast mutex, call CtdlIPC_lock() or CtdlIPC_unlock() to use */
+       pthread_mutex_t mutex;
+#endif
+       /* -1 if not connected, >= 0 otherwise */
+       int sock;
+       /* 1 if server is local, 0 otherwise or if not connected */
+       int isLocal;
+       /* 1 if a download is open on the server, 0 otherwise */
+       int downloading;
+       /* 1 if an upload is open on the server, 0 otherwise */
+       int uploading;
+       /* Time the last command was sent to the server */
+       time_t last_command_sent;
+} CtdlIPC;
+
+/* C constructor */
+CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf);
+/* C destructor */
+void CtdlIPC_delete(CtdlIPC* ipc);
+/* Convenience destructor; also nulls out caller's pointer */
+void CtdlIPC_delete_ptr(CtdlIPC** pipc);
+/* Read a line from server, discarding newline */
+void CtdlIPC_getline(CtdlIPC* ipc, char *buf);
+/* Write a line to server, adding newline */
+void CtdlIPC_putline(CtdlIPC* ipc, const char *buf);
+
 struct ctdlipcroom {
        char RRname[ROOMNAMELEN];       /* Name of room */
        long RRunread;                  /* Number of unread messages */
@@ -60,6 +110,12 @@ struct ctdlipcmisc {
        char needvalid;                 /* Nonzero if users need validation */
 };
 
+/* Shared Diffie-Hellman parameters */
+#define DH_P           "1A74527AEE4EE2568E85D4FB2E65E18C9394B9C80C42507D7A6A0DBE9A9A54B05A9A96800C34C7AA5297095B69C88901EEFD127F969DCA26A54C0E0B5C5473EBAEB00957D2633ECAE3835775425DE66C0DE6D024DBB17445E06E6B0C78415E589B8814F08531D02FD43778451E7685541079CFFB79EF0D26EFEEBBB69D1E80383"
+#define DH_G           "2"
+#define DH_L           1024
+#define CIT_CIPHERS    "ALL:RC4+RSA:+SSLv2:@STRENGTH"  /* see ciphers(1) */
+
 int CtdlIPCNoop(CtdlIPC *ipc);
 int CtdlIPCEcho(CtdlIPC *ipc, const char *arg, char *cret);
 int CtdlIPCQuit(CtdlIPC *ipc);
@@ -184,6 +240,14 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc, const char *command, const char *to_send
                size_t bytes_to_send, char **to_receive,
                size_t *bytes_to_receive, char *proto_response);
 
+/* Internals */
+int starttls(CtdlIPC *ipc);
+void setCryptoStatusHook(void (*hook)(char *s));
+/* This is all Ford's doing.  FIXME: figure out what it's doing */
+extern int (*error_printf)(char *s, ...);
+void setIPCDeathHook(void (*hook)(void));
+void setIPCErrorPrintf(int (*func)(char *s, ...));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/citadel/client_crypto.c b/citadel/client_crypto.c
deleted file mode 100644 (file)
index fa732cb..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/* $Id$ */
-
-#include "sysdep.h"
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
-#include <unistd.h>
-#include <sys/types.h>
-#include "citadel.h"
-#include "citadel_ipc.h"
-
-#ifdef HAVE_OPENSSL
-static SSL_CTX *ssl_ctx;
-char arg_encrypt;
-char rc_encrypt;
-#ifdef THREADED_CLIENT
-pthread_mutex_t **Critters;                    /* Things that need locking */
-#endif /* THREADED_CLIENT */
-
-#endif /* HAVE_OPENSSL */
-
-
-static void (*status_hook)(char *s) = NULL;
-
-void setCryptoStatusHook(void (*hook)(char *s)) {
-       status_hook = hook;
-}
-
-
-#ifdef HAVE_OPENSSL
-/*
- * input binary data from encrypted connection
- */
-void serv_read_ssl(CtdlIPC* ipc, char *buf, int bytes)
-{
-       int len, rlen;
-       char junk[1];
-
-       len = 0;
-       while (len < bytes) {
-               if (SSL_want_read(ipc->ssl)) {
-                       if ((SSL_write(ipc->ssl, junk, 0)) < 1) {
-                               error_printf("SSL_write in serv_read:\n");
-                               ERR_print_errors_fp(stderr);
-                       }
-               }
-               rlen = SSL_read(ipc->ssl, &buf[len], bytes - len);
-               if (rlen < 1) {
-                       long errval;
-
-                       errval = SSL_get_error(ipc->ssl, rlen);
-                       if (errval == SSL_ERROR_WANT_READ ||
-                                       errval == SSL_ERROR_WANT_WRITE) {
-                               sleep(1);
-                               continue;
-                       }
-                       if (errval == SSL_ERROR_ZERO_RETURN ||
-                                       errval == SSL_ERROR_SSL) {
-                               serv_read(ipc, &buf[len], bytes - len);
-                               return;
-                       }
-                       error_printf("SSL_read in serv_read:\n");
-                       ERR_print_errors_fp(stderr);
-                       connection_died();
-                       return;
-               }
-               len += rlen;
-       }
-}
-
-
-/*
- * send binary to server encrypted
- */
-void serv_write_ssl(CtdlIPC *ipc, const char *buf, int nbytes)
-{
-       int bytes_written = 0;
-       int retval;
-       char junk[1];
-
-       while (bytes_written < nbytes) {
-               if (SSL_want_write(ipc->ssl)) {
-                       if ((SSL_read(ipc->ssl, junk, 0)) < 1) {
-                               error_printf("SSL_read in serv_write:\n");
-                               ERR_print_errors_fp(stderr);
-                       }
-               }
-               retval = SSL_write(ipc->ssl, &buf[bytes_written],
-                               nbytes - bytes_written);
-               if (retval < 1) {
-                       long errval;
-
-                       errval = SSL_get_error(ipc->ssl, retval);
-                       if (errval == SSL_ERROR_WANT_READ ||
-                                       errval == SSL_ERROR_WANT_WRITE) {
-                               sleep(1);
-                               continue;
-                       }
-                       if (errval == SSL_ERROR_ZERO_RETURN ||
-                                       errval == SSL_ERROR_SSL) {
-                               serv_write(ipc, &buf[bytes_written],
-                                               nbytes - bytes_written);
-                               return;
-                       }
-                       error_printf("SSL_write in serv_write:\n");
-                       ERR_print_errors_fp(stderr);
-                       connection_died();
-                       return;
-               }
-               bytes_written += retval;
-       }
-}
-
-
-void ssl_lock(int mode, int n, const char *file, int line)
-{
-#ifdef THREADED_CLIENT
-       if (mode & CRYPTO_LOCK)
-               pthread_mutex_lock(Critters[n]);
-       else
-               pthread_mutex_unlock(Critters[n]);
-#endif /* THREADED_CLIENT */
-}
-#endif /* HAVE_OPENSSL */
-
-#if defined(THREADED_CLIENT) && defined(HAVE_OPENSSL)
-static unsigned long id_callback(void) {
-       return (unsigned long)pthread_self();
-}
-#endif
-
-/* FIXME: per application not per ipc */
-/*
- * starttls() starts SSL/TLS if possible
- * Returns 1 if the session is encrypted, 0 otherwise
- */
-int starttls(CtdlIPC *ipc)
-{
-#ifdef HAVE_OPENSSL
-       int a;
-       int r;                          /* IPC response code */
-       char buf[SIZ];
-       SSL_METHOD *ssl_method;
-       DH *dh;
-       
-       /* Figure out whether to encrypt the session based on user options */
-       /* User request to disable encryption */
-       if (arg_encrypt == RC_NO || rc_encrypt == RC_NO) {
-               return 0;
-       }
-       /* User expressed no preference */
-       else if (rc_encrypt == RC_DEFAULT && arg_encrypt == RC_DEFAULT &&
-                       ipc->isLocal) {
-               return 0;
-       }
-
-       /* Get started */
-       ipc->ssl = NULL;
-       ssl_ctx = NULL;
-       dh = NULL;
-       SSL_load_error_strings();
-       SSLeay_add_ssl_algorithms();
-
-       /* Set up the SSL context in which we will oeprate */
-       ssl_method = SSLv23_client_method();
-       ssl_ctx = SSL_CTX_new(ssl_method);
-       if (!ssl_ctx) {
-               error_printf("SSL_CTX_new failed: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               return 0;
-       }
-       /* Any reasonable cipher we can get */
-       if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
-               error_printf("No ciphers available for encryption\n");
-               endtls(ipc);
-               return 0;
-       }
-       SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
-       
-       /* Load DH parameters into the context */
-       dh = DH_new();
-       if (!dh) {
-               error_printf("Can't allocate a DH object: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               endtls(ipc);
-               return 0;
-       }
-       if (!(BN_hex2bn(&(dh->p), DH_P))) {
-               error_printf("Can't assign DH_P: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               DH_free(dh);
-               endtls(ipc);
-               return 0;
-       }
-       if (!(BN_hex2bn(&(dh->g), DH_G))) {
-               error_printf("Can't assign DH_G: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               DH_free(dh);
-               endtls(ipc);
-               return 0;
-       }
-       dh->length = DH_L;
-       SSL_CTX_set_tmp_dh(ssl_ctx, dh);
-       DH_free(dh);
-
-#ifdef THREADED_CLIENT
-       /* OpenSSL requires callbacks for threaded clients */
-       CRYPTO_set_locking_callback(ssl_lock);
-       CRYPTO_set_id_callback(id_callback);
-
-       /* OpenSSL requires us to do semaphores for threaded clients */
-       Critters = malloc(CRYPTO_num_locks() * sizeof (pthread_mutex_t *));
-       if (!Critters) {
-               perror("malloc failed");
-               exit(1);
-       } else {
-               for (a = 0; a < CRYPTO_num_locks(); a++) {
-                       Critters[a] = malloc(sizeof (pthread_mutex_t));
-                       if (!Critters[a]) {
-                               perror("malloc failed");
-                               exit(1);
-                       }
-                       pthread_mutex_init(Critters[a], NULL);
-               }
-       }
-#endif /* THREADED_CLIENT */
-
-       /* New SSL object */
-       ipc->ssl = SSL_new(ssl_ctx);
-       if (!ipc->ssl) {
-               error_printf("SSL_new failed: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               endtls(ipc);
-               return 0;
-       }
-       /* Pointless flag waving */
-#if SSLEAY_VERSION_NUMBER >= 0x0922
-       SSL_set_session_id_context(ipc->ssl, "Citadel/UX SID", 14);
-#endif
-
-       if (!access("/var/run/egd-pool", F_OK))
-               RAND_egd("/var/run/egd-pool");
-
-       if (!RAND_status()) {
-               error_printf("PRNG not properly seeded\n");
-               endtls(ipc);
-               return 0;
-       }
-
-       /* Associate network connection with SSL object */
-       if (SSL_set_fd(ipc->ssl, ipc->sock) < 1) {
-               error_printf("SSL_set_fd failed: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               endtls(ipc);
-               return 0;
-       }
-
-       if (status_hook != NULL)
-               status_hook("Requesting encryption...\r");
-
-       /* Ready to start SSL/TLS */
-       /* Old code
-       CtdlIPC_putline(ipc, "STLS");
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] != '2') {
-               error_printf("Server can't start TLS: %s\n", buf);
-               return 0;
-       }
-       */
-       {
-               /*
-                * We can't have ipc->ssl set when we call StartEncryption()
-                * because the connection isn't yet encrypted.  So we fake it.
-                */
-               SSL *temp_ssl;
-
-               temp_ssl = ipc->ssl;
-               ipc->ssl = NULL;
-               r = CtdlIPCStartEncryption(ipc, buf);
-               ipc->ssl = temp_ssl;
-               if (r / 100 != 2) {
-                       error_printf("Server can't start TLS: %s\n", buf);
-                       return 0;
-               }
-       }
-
-       /* Do SSL/TLS handshake */
-       if ((a = SSL_connect(ipc->ssl)) < 1) {
-               error_printf("SSL_connect failed: %s\n",
-                               ERR_reason_error_string(ERR_get_error()));
-               endtls(ipc);
-               return 0;
-       }
-       BIO_set_close(ipc->ssl->rbio, BIO_NOCLOSE);
-       {
-               int bits, alg_bits;
-
-               bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ipc->ssl), &alg_bits);
-               error_printf("Encrypting with %s cipher %s (%d of %d bits)\n",
-                               SSL_CIPHER_get_version(SSL_get_current_cipher(ipc->ssl)),
-                               SSL_CIPHER_get_name(SSL_get_current_cipher(ipc->ssl)),
-                               bits, alg_bits);
-       }
-       return 1;
-#else
-       return 0;
-#endif /* HAVE_OPENSSL */
-}
-
-
-/*
- * void endtls() - end SSL/TLS session
- */
-void endtls(CtdlIPC *ipc)
-{
-#ifdef HAVE_OPENSSL
-       if (ipc->ssl) {
-               SSL_shutdown(ipc->ssl);
-               SSL_free(ipc->ssl);
-               ipc->ssl = NULL;
-       }
-#endif
-}
diff --git a/citadel/client_crypto.h b/citadel/client_crypto.h
deleted file mode 100644 (file)
index e757d9d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* $Id$ */
-
-#ifdef HAVE_OPENSSL
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Shared Diffie-Hellman parameters */
-#define DH_P           "1A74527AEE4EE2568E85D4FB2E65E18C9394B9C80C42507D7A6A0DBE9A9A54B05A9A96800C34C7AA5297095B69C88901EEFD127F969DCA26A54C0E0B5C5473EBAEB00957D2633ECAE3835775425DE66C0DE6D024DBB17445E06E6B0C78415E589B8814F08531D02FD43778451E7685541079CFFB79EF0D26EFEEBBB69D1E80383"
-#define DH_G           "2"
-#define DH_L           1024
-#define CIT_CIPHERS    "ALL:RC4+RSA:+SSLv2:@STRENGTH"  /* see ciphers(1) */
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/citadel/ipc.h b/citadel/ipc.h
deleted file mode 100644 (file)
index 41c8856..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* $Id$ */
-
-#include "sysdep.h"
-#include "client_crypto.h"
-
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Quick and dirty hack; we don't want to use malloc() in C++ */
-#ifdef __cplusplus
-#define ialloc(t)      new t()
-#define ifree(o)       delete o
-#else
-#define ialloc(t)      malloc(sizeof(t))
-#define ifree(o)       free(o);
-#endif
-
-/* This class is responsible for the server connection */
-typedef struct _CtdlIPC {
-#if defined(HAVE_OPENSSL)
-       /* NULL if not encrypted, non-NULL otherwise */
-       SSL *ssl;
-#endif
-#if defined(HAVE_PTHREAD_H)
-       /* Fast mutex, call CtdlIPC_lock() or CtdlIPC_unlock() to use */
-       pthread_mutex_t mutex;
-#endif
-       /* -1 if not connected, >= 0 otherwise */
-       int sock;
-       /* 1 if server is local, 0 otherwise or if not connected */
-       int isLocal;
-       /* 1 if a download is open on the server, 0 otherwise */
-       int downloading;
-       /* 1 if an upload is open on the server, 0 otherwise */
-       int uploading;
-} CtdlIPC;
-
-/* C constructor */
-CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf);
-/* C destructor */
-void CtdlIPC_delete(CtdlIPC* ipc);
-/* Convenience destructor; also nulls out caller's pointer */
-void CtdlIPC_delete_ptr(CtdlIPC** pipc);
-/* Read a line from server, discarding newline */
-void CtdlIPC_getline(CtdlIPC* ipc, char *buf);
-/* Write a line to server, adding newline */
-void CtdlIPC_putline(CtdlIPC* ipc, const char *buf);
-
-/* Internals */
-int starttls(CtdlIPC *ipc);
-void endtls(CtdlIPC *ipc);
-void setCryptoStatusHook(void (*hook)(char *s));
-void serv_read(CtdlIPC *ipc, char *buf, int bytes);
-void serv_write(CtdlIPC *ipc, const char *buf, int nbytes);
-#ifdef HAVE_OPENSSL
-void serv_read_ssl(CtdlIPC *ipc, char *buf, int bytes);
-void serv_write_ssl(CtdlIPC *ipc, const char *buf, int nbytes);
-void ssl_lock(int mode, int n, const char *file, int line);
-#endif /* HAVE_OPENSSL */
-/* This is all Ford's doing.  FIXME: figure out what it's doing */
-extern int (*error_printf)(char *s, ...);
-void setIPCDeathHook(void (*hook)(void));
-void setIPCErrorPrintf(int (*func)(char *s, ...));
-
-#ifdef __cplusplus
-}
-#endif
index b051f6876cff822a347c6c167c4e17b0bec8cc79..1e8e8dcb44a3477573b3968a3d0019c28a38ed4a 100644 (file)
@@ -5,11 +5,6 @@
  *
  */
 
-#define        UDS                     "_UDS_"
-
-#define DEFAULT_HOST           UDS
-#define DEFAULT_PORT           "citadel"
-
 
 #include "sysdep.h"
 #undef NDEBUG
 #include <errno.h>
 #include <stdarg.h>
 #include "citadel.h"
-#include "ipc.h"
+#include "citadel_ipc.h"
 #include "citadel_decls.h"
 #include "tools.h"
-#if defined(HAVE_OPENSSL)
-#include "client_crypto.h"
-#endif
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
 #endif
 
-/*
- * If ipc->isLocal is set to nonzero, the client assumes that it is running on
- * the same computer as the server.  Several things happen when this is the
- * case, including the ability to map a specific tty to a particular login
- * session in the "<W>ho is online" listing, the ability to run external
- * programs, and the ability to download files directly off the disk without
- * having to first fetch them from the server.
- * Set the flag to 1 if this IPC is local (as is the case with pipes, or a
- * network session to the local machine) or 0 if the server is executing on
- * a remote computer.
- */
-
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
 /*
  * FIXME: rewrite all of Ford's stuff here, it won't work with multiple
  * instances
@@ -96,286 +72,3 @@ static void ipc_timeout(int signum)
        logoff(NULL, 3);
 }
 */
-
-
-static int connectsock(char *host, char *service, char *protocol, int defaultPort)
-{
-       struct hostent *phe;
-       struct servent *pse;
-       struct protoent *ppe;
-       struct sockaddr_in sin;
-       int s, type;
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-
-       pse = getservbyname(service, protocol);
-       if (pse != NULL) {
-               sin.sin_port = pse->s_port;
-       }
-       else if (atoi(service) > 0) {
-               sin.sin_port = htons(atoi(service));
-       }
-       else {
-               sin.sin_port = htons(defaultPort);
-       }
-       phe = gethostbyname(host);
-       if (phe) {
-               memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
-       } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
-               error_printf("Can't get %s host entry: %s\n",
-                       host, strerror(errno));
-               return -1;
-       }
-       if ((ppe = getprotobyname(protocol)) == 0) {
-               error_printf("Can't get %s protocol entry: %s\n",
-                       protocol, strerror(errno));
-               return -1;
-       }
-       if (!strcmp(protocol, "udp")) {
-               type = SOCK_DGRAM;
-       } else {
-               type = SOCK_STREAM;
-       }
-
-       s = socket(PF_INET, type, ppe->p_proto);
-       if (s < 0) {
-               error_printf("Can't create socket: %s\n", strerror(errno));
-               return -1;
-       }
-       /*
-       signal(SIGALRM, ipc_timeout);
-       alarm(30);
-       */
-
-       if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-               error_printf("Can't connect to %s:%s: %s\n",
-                       host, service, strerror(errno));
-               return -1;
-       }
-       /*
-       alarm(0);
-       signal(SIGALRM, SIG_IGN);
-       */
-
-       return (s);
-}
-
-static int uds_connectsock(int *isLocal, char *sockpath)
-{
-       struct sockaddr_un addr;
-       int s;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
-
-       s = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (s < 0) {
-               error_printf("Can't create socket: %s\n", strerror(errno));
-               return -1;
-       }
-
-       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               error_printf("can't connect: %s\n", strerror(errno));
-               return -1;
-       }
-
-       *isLocal = 1;
-       return s;
-}
-
-
-/*
- * input binary data from socket
- */
-void serv_read(CtdlIPC *ipc, char *buf, int bytes)
-{
-       int len, rlen;
-
-#if defined(HAVE_OPENSSL)
-       if (ipc->ssl) {
-               serv_read_ssl(ipc, buf, bytes);
-               return;
-       }
-#endif
-       len = 0;
-       while (len < bytes) {
-               rlen = read(ipc->sock, &buf[len], bytes - len);
-               if (rlen < 1) {
-                       connection_died(ipc);
-                       return;
-               }
-               len += rlen;
-       }
-}
-
-
-/*
- * send binary to server
- */
-void serv_write(CtdlIPC *ipc, const char *buf, int nbytes)
-{
-       int bytes_written = 0;
-       int retval;
-
-#if defined(HAVE_OPENSSL)
-       if (ipc->ssl) {
-               serv_write_ssl(ipc, buf, nbytes);
-               return;
-       }
-#endif
-       while (bytes_written < nbytes) {
-               retval = write(ipc->sock, &buf[bytes_written],
-                              nbytes - bytes_written);
-               if (retval < 1) {
-                       connection_died(ipc);
-                       return;
-               }
-               bytes_written += retval;
-       }
-}
-
-
-
-/*
- * input string from socket - implemented in terms of serv_read()
- */
-void CtdlIPC_getline(CtdlIPC* ipc, char *buf)
-{
-       int i;
-
-       /* Read one character at a time. */
-       for (i = 0;; i++) {
-               serv_read(ipc, &buf[i], 1);
-               if (buf[i] == '\n' || i == (SIZ-1))
-                       break;
-       }
-
-       /* If we got a long line, discard characters until the newline. */
-       if (i == (SIZ-1))
-               while (buf[i] != '\n')
-                       serv_read(ipc, &buf[i], 1);
-
-       /* Strip the trailing newline.
-        */
-       buf[i] = 0;
-}
-
-
-/*
- * send line to server - implemented in terms of serv_write()
- */
-void CtdlIPC_putline(CtdlIPC *ipc, const char *buf)
-{
-       /* error_printf("< %s\n", buf); */
-       int watch_ssl = 0;
-       if (ipc->ssl) watch_ssl = 1;
-       assert(!watch_ssl || ipc->ssl);
-       serv_write(ipc, buf, strlen(buf));
-       assert(!watch_ssl || ipc->ssl);
-       serv_write(ipc, "\n", 1);
-       assert(!watch_ssl || ipc->ssl);
-}
-
-
-/*
- * attach to server
- */
-CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
-{
-       int a;
-       char cithost[SIZ];
-       char citport[SIZ];
-       char sockpath[SIZ];
-
-       CtdlIPC *ipc = ialloc(CtdlIPC);
-       if (!ipc) {
-               error_printf("Out of memory creating CtdlIPC!\n");
-               return 0;
-       }
-#if defined(HAVE_OPENSSL)
-       ipc->ssl = NULL;
-#endif
-#if defined(HAVE_PTHREAD_H)
-       pthread_mutex_init(&(ipc->mutex), NULL); /* Default fast mutex */
-#endif
-       ipc->sock = -1;                 /* Not connected */
-       ipc->isLocal = 0;               /* Not local, of course! */
-       ipc->downloading = 0;
-       ipc->uploading = 0;
-
-       strcpy(cithost, DEFAULT_HOST);  /* default host */
-       strcpy(citport, DEFAULT_PORT);  /* default port */
-
-       for (a = 0; a < argc; ++a) {
-               if (a == 0) {
-                       /* do nothing */
-               } else if (a == 1) {
-                       strcpy(cithost, argv[a]);
-               } else if (a == 2) {
-                       strcpy(citport, argv[a]);
-               } else {
-                       error_printf("%s: usage: ",argv[0]);
-                       error_printf("%s [host] [port] ",argv[0]);
-                       ifree(ipc);
-                       return 0;
-               }
-       }
-
-       if ((!strcmp(cithost, "localhost"))
-          || (!strcmp(cithost, "127.0.0.1"))) {
-               ipc->isLocal = 1;
-       }
-
-       /* If we're using a unix domain socket we can do a bunch of stuff */
-       if (!strcmp(cithost, UDS)) {
-               snprintf(sockpath, sizeof sockpath, "citadel.socket");
-               ipc->sock = uds_connectsock(&(ipc->isLocal), sockpath);
-               if (ipc->sock == -1) {
-                       ifree(ipc);
-                       return 0;
-               }
-               if (hostbuf != NULL) strcpy(hostbuf, cithost);
-               if (portbuf != NULL) strcpy(portbuf, sockpath);
-               return ipc;
-       }
-
-       ipc->sock = connectsock(cithost, citport, "tcp", 504);
-       if (ipc->sock == -1) {
-               ifree(ipc);
-               return 0;
-       }
-       if (hostbuf != NULL) strcpy(hostbuf, cithost);
-       if (portbuf != NULL) strcpy(portbuf, citport);
-       return ipc;
-}
-
-/*
- * return the file descriptor of the server socket so we can select() on it.
- *
- * FIXME: This is only used in chat mode; eliminate it when chat mode gets
- * rewritten...
- */
-int CtdlIPC_getsockfd(CtdlIPC* ipc)
-{
-       return ipc->sock;
-}
-
-
-/*
- * return one character
- *
- * FIXME: This is only used in chat mode; eliminate it when chat mode gets
- * rewritten...
- */
-char CtdlIPC_get(CtdlIPC* ipc)
-{
-       char buf[2];
-       char ch;
-
-       serv_read(ipc, buf, 1);
-       ch = (int) buf[0];
-
-       return (ch);
-}
index 6a8c4f551363965cc32a311602635d9af2a2d569..f851e3df450c6c9e491f3188dd139cbf734eace2 100644 (file)
@@ -44,7 +44,6 @@
 #include "snprintf.h"
 #endif
 #include "screen.h"
-#include "client_crypto.h"
 
 extern char temp[];
 extern char tempdir[];