$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)
Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
* Initial CVS import
+
#include "citadel_decls.h"
#include "tools.h"
#include "acconfig.h"
-#include "client_crypto.h"
#ifndef HAVE_SNPRINTF
#include "snprintf.h"
#endif
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;
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);
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);
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;
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) {
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);
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;
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");
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);
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)
}
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");
/* 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);
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);
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"
+ );
}
}
}
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:
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();
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);
} /* 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);
}
/* $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.
*/
/* 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)
{
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);
+}
/* $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 */
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);
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
+++ /dev/null
-/* $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
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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
*
*/
-#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
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);
-}
#include "snprintf.h"
#endif
#include "screen.h"
-#include "client_crypto.h"
extern char temp[];
extern char tempdir[];