BIG CHANGES: PAY ATTENTION
authorArt Cancro <ajc@citadel.org>
Mon, 27 Dec 2021 20:49:38 +0000 (15:49 -0500)
committerArt Cancro <ajc@citadel.org>
Mon, 27 Dec 2021 20:49:38 +0000 (15:49 -0500)
1. WebCit must now run on the same host as Citadel Server, which is how everyone runs it anyway.
2. WebCit now uses the SSL key and Certificate from the Citadel Server directory.

webcit/Makefile.in
webcit/auth.c
webcit/crypto.c
webcit/serv_func.c
webcit/sockets.c [new file with mode: 0644]
webcit/sockets.h [new file with mode: 0644]
webcit/sysdep.c
webcit/tcp_sockets.c [deleted file]
webcit/tcp_sockets.h [deleted file]
webcit/webcit.h
webcit/webserver.c

index f6b2f361ebaf77b42fdd8d434fba5cba69b65ac6..9749bad130ec446cd18f7ac4fec0d5c8b9ae510f 100644 (file)
@@ -19,7 +19,7 @@ SUBDIRS=$(LIB_SUBDIRS) $(PROG_SUBDIRS)
 LOCALEDIR=@LOCALEDIR@
 WWWDIR=@WWWDIR@
 ETCDIR=@ETCDIR@
-HEADERS=calendar.h  dav.h  messages.h  modules_init.h  paramhandling.h  preferences.h  roomops.h  subst.h  sysdep.h  tcp_sockets.h  utils.h  webcit.h  webserver.h
+HEADERS=calendar.h  dav.h  messages.h  modules_init.h  paramhandling.h  preferences.h  roomops.h  subst.h  sysdep.h  sockets.h  utils.h  webcit.h  webserver.h
 
 # End of configuration section
 
@@ -51,7 +51,7 @@ distclean: clean
 
 webcit: webserver.o context_loop.o ical_dezonify.o \
        cookie_conversion.o locate_host.o summary.o \
-       webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o marchlist.o \
+       webcit.o auth.o sockets.o mainmenu.o serv_func.o who.o marchlist.o \
        roomops.o roomlist.o roomtokens.o roomviews.o \
        blogview_renderer.o msg_renderers.o jsonview_renderer.o mailview_renderer.o bbsview_renderer.o \
        messages.o paging.o sysmsgs.o \
@@ -69,7 +69,7 @@ webcit: webserver.o context_loop.o ical_dezonify.o \
        echo LD: webcit
        $(CC) $(LDFLAGS) -o webcit $(LIBOBJS) \
        webserver.o context_loop.o cookie_conversion.o marchlist.o \
-       webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o listsub.o \
+       webcit.o auth.o sockets.o mainmenu.o serv_func.o who.o listsub.o \
        roomops.o roomlist.o roomtokens.o roomviews.o \
        messages.o msg_renderers.o paging.o sysmsgs.o \
        blogview_renderer.o jsonview_renderer.o mailview_renderer.o bbsview_renderer.o \
index f63b78f6d9bf64198cd708b17c9762b4172156bb..74d9237e94d9d47358ca47e3dcf582ddf01c4fb9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * These functions handle authentication of users to a Citadel server.
  *
- * Copyright (c) 1996-2012 by the citadel.org team
+ * Copyright (c) 1996-2021 by the citadel.org team
  *
  * This program is open source software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, version 3.
@@ -486,8 +486,7 @@ void monitor(void)
        );
        begin_burst();
 
-       wc_printf("Connection to Citadel server at %s:%s : %s\r\n",
-               ctdlhost, ctdlport,
+       wc_printf("Connection to Citadel server in %s : %s\r\n", ctdl_dir,
                (WC->connected ? "SUCCESS" : "FAIL")
        );
 
index 0d0f080b0dfed63f0a17cf48c3ff9a7b1db720a6..104945b04fda2401d74c0c8a34074e9dfea758ce 100644 (file)
 #include "webcit.h"
 #include "webserver.h"
 
-/* where to find the keys */
-#define        CTDL_CRYPTO_DIR         ctdl_key_dir
-#define CTDL_KEY_PATH          file_crpt_file_key
-#define CTDL_CSR_PATH          file_crpt_file_csr
-#define CTDL_CER_PATH          file_crpt_file_cer
-#define SIGN_DAYS              3650                    // how long our self-signed certificate should live
 
 SSL_CTX *ssl_ctx;              // Global SSL context
 char *ssl_cipher_list = DEFAULT_SSL_CIPHER_LIST;
@@ -31,70 +25,9 @@ void shutdown_ssl(void) {
 }
 
 
-void generate_key(char *keyfilename) {
-       int ret = 0;
-       RSA *rsa = NULL;
-       BIGNUM *bne = NULL;
-       int bits = 2048;
-       unsigned long e = RSA_F4;
-       FILE *fp;
-
-       if (access(keyfilename, R_OK) == 0) {           // We already have a key -- don't generate a new one.
-               return;
-       }
-
-       syslog(LOG_INFO, "crypto: generating RSA key pair");
-       // generate rsa key
-       bne = BN_new();
-       ret = BN_set_word(bne,e);
-       if (ret != 1) {
-               goto free_all;
-       }
-       rsa = RSA_new();
-       ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
-       if (ret != 1) {
-               goto free_all;
-       }
-
-       // write the key file
-       fp = fopen(keyfilename, "w");
-       if (fp != NULL) {
-               chmod(file_crpt_file_key, 0600);
-               if (PEM_write_RSAPrivateKey(fp, // the file
-                                       rsa,    // the key
-                                       NULL,   // no enc
-                                       NULL,   // no passphrase
-                                       0,      // no passphrase
-                                       NULL,   // no callback
-                                       NULL    // no callback
-               ) != 1) {
-                       syslog(LOG_ERR, "crypto: cannot write key: %s", ERR_reason_error_string(ERR_get_error()));
-                       unlink(keyfilename);
-               }
-               fclose(fp);
-       }
-
-       // Free the memory we used
-free_all:
-       RSA_free(rsa);
-       BN_free(bne);
-}
-
-
 // initialize ssl engine, load certs and initialize openssl internals
 void init_ssl(void) {
        const SSL_METHOD *ssl_method;
-       RSA *rsa=NULL;
-       X509_REQ *req = NULL;
-       X509 *cer = NULL;
-       EVP_PKEY *pk = NULL;
-       EVP_PKEY *req_pkey = NULL;
-       X509_NAME *name = NULL;
-       FILE *fp;
-       char buf[SIZ];
-       int rv = 0;
 
 #ifndef OPENSSL_NO_EGD
        if (!access("/var/run/egd-pool", F_OK)) {
@@ -122,205 +55,20 @@ void init_ssl(void) {
                return;
        }
 
-       CRYPTO_set_locking_callback(ssl_lock);
-       CRYPTO_set_id_callback(id_callback);
-
-       // Get our certificates in order.
-       // First, create the key/cert directory if it's not there already...
-       mkdir(CTDL_CRYPTO_DIR, 0700);
-
-       // Before attempting to generate keys/certificates, first try
-       // link to them from the Citadel server if it's on the same host.
-       // We ignore any error return because it either meant that there
-       // was nothing in Citadel to link from (in which case we just
-       // generate new files) or the target files already exist (which
-       // is not fatal either).
-       if (!strcasecmp(ctdlhost, "uds")) {
-               sprintf(buf, "%s/keys/citadel.key", ctdlport);
-               rv = symlink(buf, CTDL_KEY_PATH);
-               if (!rv) {
-                       syslog(LOG_DEBUG, "%s", strerror(errno));
-               }
-               sprintf(buf, "%s/keys/citadel.csr", ctdlport);
-               rv = symlink(buf, CTDL_CSR_PATH);
-               if (!rv) {
-                       syslog(LOG_DEBUG, "%s", strerror(errno));
-               }
-               sprintf(buf, "%s/keys/citadel.cer", ctdlport);
-               rv = symlink(buf, CTDL_CER_PATH);
-               if (!rv) {
-                       syslog(LOG_DEBUG, "%s", strerror(errno));
-               }
-       }
-
-       // If we still don't have a private key, generate one.
-       generate_key(CTDL_KEY_PATH);
-
-       // If there is no certificate file on disk, we will be generating a self-signed certificate
-       // in the next step.  Therefore, if we have neither a CSR nor a certificate, generate
-       // the CSR in this step so that the next step may commence.
-       if ( (access(CTDL_CER_PATH, R_OK) != 0) && (access(CTDL_CSR_PATH, R_OK) != 0) ) {
-               syslog(LOG_INFO, "Generating a certificate signing request.");
-
-               // Read our key from the file.  No, we don't just keep this
-               // in memory from the above key-generation function, because
-               // there is the possibility that the key was already on disk
-               // and we didn't just generate it now.
-               fp = fopen(CTDL_KEY_PATH, "r");
-               if (fp) {
-                       rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
-                       fclose(fp);
-               }
-
-               if (rsa) {
-                       // Create a public key from the private key
-                       if (pk=EVP_PKEY_new(), pk != NULL) {
-                               EVP_PKEY_assign_RSA(pk, rsa);
-                               if (req = X509_REQ_new(), req != NULL) {
-                                       const char *env;
-                                       // Set the public key
-                                       X509_REQ_set_pubkey(req, pk);
-                                       X509_REQ_set_version(req, 0L);
-
-                                       name = X509_REQ_get_subject_name(req);
-
-                                       // Tell it who we are
-                                       env = getenv("O");
-                                       if (env == NULL) {
-                                               env = "Organization name";
-                                       }
-
-                                       X509_NAME_add_entry_by_txt(
-                                               name, "O",
-                                               MBSTRING_ASC, 
-                                               (unsigned char*)env, 
-                                               -1, -1, 0
-                                       );
-
-                                       env = getenv("OU");
-                                       if (env == NULL) {
-                                               env = "Citadel server";
-                                       }
-
-                                       X509_NAME_add_entry_by_txt(
-                                               name, "OU",
-                                               MBSTRING_ASC, 
-                                               (unsigned char*)env, 
-                                               -1, -1, 0
-                                       );
-
-                                       env = getenv("CN");
-                                       if (env == NULL)
-                                               env = "*";
-
-                                       X509_NAME_add_entry_by_txt(
-                                               name, "CN",
-                                               MBSTRING_ASC, 
-                                               (unsigned char*)env,
-                                               -1, -1, 0
-                                       );
-                               
-                                       X509_REQ_set_subject_name(req, name);
-
-                                       // Sign the CSR
-                                       if (!X509_REQ_sign(req, pk, EVP_md5())) {
-                                               syslog(LOG_WARNING, "X509_REQ_sign(): error");
-                                       }
-                                       else {
-                                               // Write it to disk.
-                                               fp = fopen(CTDL_CSR_PATH, "w");
-                                               if (fp != NULL) {
-                                                       chmod(CTDL_CSR_PATH, 0600);
-                                                       PEM_write_X509_REQ(fp, req);
-                                                       fclose(fp);
-                                               }
-                                               else {
-                                                       syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CSR_PATH);
-                                                       ShutDownWebcit();
-                                                       exit(0);
-                                               }
-                                       }
-
-                                       X509_REQ_free(req);
-                               }
-                       }
-                       RSA_free(rsa);
-               }
-               else {
-                       syslog(LOG_WARNING, "Unable to read private key.");
-               }
-       }
-
-       // Generate a self-signed certificate if we don't have one.
-       if (access(CTDL_CER_PATH, R_OK) != 0) {
-               syslog(LOG_INFO, "Generating a self-signed certificate.\n");
 
-               // Same deal as before: always read the key from disk because
-               // it may or may not have just been generated.
-               fp = fopen(CTDL_KEY_PATH, "r");
-               if (fp) {
-                       rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
-                       fclose(fp);
-               }
+       // Now try to bind to the key and certificate.
+       // Note that we use SSL_CTX_use_certificate_chain_file() which allows
+       // the certificate file to contain intermediate certificates.
 
-               // This also holds true for the CSR.
-               req = NULL;
-               cer = NULL;
-               pk = NULL;
-               if (rsa) {
-                       if (pk=EVP_PKEY_new(), pk != NULL) {
-                               EVP_PKEY_assign_RSA(pk, rsa);
-                       }
 
-                       fp = fopen(CTDL_CSR_PATH, "r");
-                       if (fp) {
-                               req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
-                               fclose(fp);
-                       }
+       char *key_file[PATH_MAX];
+       char *cert_file[PATH_MAX];
+       snprintf(key_file, sizeof key_file, "%s/keys/citadel.key", ctdl_dir);
+       snprintf(cert_file, sizeof key_file, "%s/keys/citadel.cer", ctdl_dir);
 
-                       if (req) {
-                               if (cer = X509_new(), cer != NULL) {
-
-                                       ASN1_INTEGER_set(X509_get_serialNumber(cer), 0);
-                                       X509_set_issuer_name(cer, X509_REQ_get_subject_name(req));
-                                       X509_set_subject_name(cer, X509_REQ_get_subject_name(req));
-                                       X509_gmtime_adj(X509_get_notBefore(cer), 0);
-                                       X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
-
-                                       req_pkey = X509_REQ_get_pubkey(req);
-                                       X509_set_pubkey(cer, req_pkey);
-                                       EVP_PKEY_free(req_pkey);
-                                       
-                                       // Sign the cert
-                                       if (!X509_sign(cer, pk, EVP_md5())) {
-                                               syslog(LOG_WARNING, "X509_sign(): error");
-                                       }
-                                       else {
-                                               // Write it to disk.
-                                               fp = fopen(CTDL_CER_PATH, "w");
-                                               if (fp != NULL) {
-                                                       chmod(CTDL_CER_PATH, 0600);
-                                                       PEM_write_X509(fp, cer);
-                                                       fclose(fp);
-                                               }
-                                               else {
-                                                       syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CER_PATH);
-                                                       ShutDownWebcit();
-                                                       exit(0);
-                                               }
-                                       }
-                                       X509_free(cer);
-                               }
-                       }
-                       RSA_free(rsa);
-               }
-       }
+       SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file);
+       SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM);
 
-       // Now try to bind to the key and certificate.
-       // Note that we use SSL_CTX_use_certificate_chain_file() which allows
-       // the certificate file to contain intermediate certificates.
-       SSL_CTX_use_certificate_chain_file(ssl_ctx, CTDL_CER_PATH);
-       SSL_CTX_use_PrivateKey_file(ssl_ctx, CTDL_KEY_PATH, SSL_FILETYPE_PEM);
        if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
                syslog(LOG_WARNING, "crypto: cannot install certificate: %s", ERR_reason_error_string(ERR_get_error()));
        }
@@ -357,10 +105,10 @@ int starttls(int sock) {
                errval = SSL_get_error(newssl, retval);
                ssl_error_reason = ERR_reason_error_string(ERR_get_error());
                if (ssl_error_reason == NULL) {
-                       syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d %s", errval, retval, strerror(errval));
+                       syslog(LOG_WARNING, "first SSL_accept failed: errval=%ld, retval=%d %s", errval, retval, strerror(errval));
                }
                else {
-                       syslog(LOG_WARNING, "SSL_accept failed: %s", ssl_error_reason);
+                       syslog(LOG_WARNING, "first SSL_accept failed: %s", ssl_error_reason);
                }
                sleeeeeeeeeep(1);
                retval = SSL_accept(newssl);
@@ -372,10 +120,10 @@ int starttls(int sock) {
                errval = SSL_get_error(newssl, retval);
                ssl_error_reason = ERR_reason_error_string(ERR_get_error());
                if (ssl_error_reason == NULL) {
-                       syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d (%s)", errval, retval, strerror(errval));
+                       syslog(LOG_WARNING, "second SSL_accept failed: errval=%ld, retval=%d (%s)", errval, retval, strerror(errval));
                }
                else {
-                       syslog(LOG_WARNING, "SSL_accept failed: %s", ssl_error_reason);
+                       syslog(LOG_WARNING, "second SSL_accept failed: %s", ssl_error_reason);
                }
                SSL_free(newssl);
                newssl = NULL;
index dab21f8f88752e44bb6562a6551f84a003624178..7f26f7222051106de2811119df988fe02433d974 100644 (file)
@@ -8,13 +8,9 @@
 #include "webcit.h"
 #include "webserver.h"
 
-int is_uds = 0;
-char serv_sock_name[PATH_MAX] = "";
-
 HashList *EmbeddableMimes = NULL;
 StrBuf *EmbeddableMimeStrs = NULL;
 
-
 void SetInlinMimeRenderers(void) {
        StrBuf *Buf;
 
@@ -164,25 +160,30 @@ ServInfo *get_serv_info(StrBuf *browser_host, StrBuf *user_agent) {
 
 int GetConnected (void) {
        StrBuf *Buf;
-       wcsession *WCC = WC;
-
-       if (WCC->ReadBuf == NULL)
-               WCC->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
-       if (is_uds) /* unix domain socket */
-               WCC->serv_sock = uds_connectsock(serv_sock_name);
-       else        /* tcp socket */
-               WCC->serv_sock = tcp_connectsock(ctdlhost, ctdlport);
+
+       TRACE;
+       syslog(LOG_DEBUG, "GetConnected() has been called, and ctdl_dir is \"%s\"", ctdl_dir);
+
+       if (WC->ReadBuf == NULL) {
+               WC->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
+       }
+
+       static char serv_sock_name[PATH_MAX] = "";
+       if (IsEmptyStr(serv_sock_name)) {
+               snprintf(serv_sock_name, sizeof serv_sock_name, "%s/citadel.socket", ctdl_dir);
+       }
+       WC->serv_sock = connect_to_citadel(serv_sock_name);
        
-       if (WCC->serv_sock < 0) {
-               WCC->connected = 0;
-               FreeStrBuf(&WCC->ReadBuf);
+       if (WC->serv_sock < 0) {
+               WC->connected = 0;
+               FreeStrBuf(&WC->ReadBuf);
                return 1;
        }
        else {
                long Status;
                int short_status;
                Buf = NewStrBuf();
-               WCC->connected = 1;
+               WC->connected = 1;
                StrBuf_ServGetln(Buf);  /* get the server greeting */
                short_status = GetServerStatus(Buf, &Status);
                FreeStrBuf(&Buf);
@@ -213,18 +214,18 @@ int GetConnected (void) {
                 * unless we are following X-Forwarded-For: headers
                 * and such a header has already turned up something.
                 */
-               if ( (!follow_xff) || (StrLength(WCC->Hdr->HR.browser_host) == 0) ) {
-                       if (WCC->Hdr->HR.browser_host == NULL) {
-                               WCC->Hdr->HR.browser_host = NewStrBuf();
-                               Put(WCC->Hdr->HTTPHeaders, HKEY("FreeMeWithTheOtherHeaders"), 
-                                   WCC->Hdr->HR.browser_host, HFreeStrBuf);
+               if ( (!follow_xff) || (StrLength(WC->Hdr->HR.browser_host) == 0) ) {
+                       if (WC->Hdr->HR.browser_host == NULL) {
+                               WC->Hdr->HR.browser_host = NewStrBuf();
+                               Put(WC->Hdr->HTTPHeaders, HKEY("FreeMeWithTheOtherHeaders"), 
+                                   WC->Hdr->HR.browser_host, HFreeStrBuf);
                        }
-                       locate_host(WCC->Hdr->HR.browser_host, WCC->Hdr->http_sock);
+                       locate_host(WC->Hdr->HR.browser_host, WC->Hdr->http_sock);
                }
-               if (WCC->serv_info == NULL) {
-                       WCC->serv_info = get_serv_info(WCC->Hdr->HR.browser_host, WCC->Hdr->HR.user_agent);
+               if (WC->serv_info == NULL) {
+                       WC->serv_info = get_serv_info(WC->Hdr->HR.browser_host, WC->Hdr->HR.user_agent);
                }
-               if (WCC->serv_info == NULL){
+               if (WC->serv_info == NULL){
                        begin_burst();
                        wc_printf(_("Received unexpected answer from Citadel server; bailing out."));
                        hprintf("HTTP/1.1 502 Bad Gateway\r\n");
@@ -233,14 +234,14 @@ int GetConnected (void) {
                        end_webcit_session();
                        return 1;
                }
-               if (WCC->serv_info->serv_rev_level < MINIMUM_CIT_VERSION) {
+               if (WC->serv_info->serv_rev_level < MINIMUM_CIT_VERSION) {
                        begin_burst();
                        wc_printf(_("You are connected to a Citadel "
                                  "server running Citadel %d.%02d. \n"
                                  "In order to run this version of WebCit "
                                  "you must also have Citadel %d.%02d or"
                                  " newer.\n\n\n"),
-                               WCC->serv_info->serv_rev_level,
+                               WC->serv_info->serv_rev_level,
                                0,
                                MINIMUM_CIT_VERSION,
                                0
@@ -416,7 +417,6 @@ void server_to_text() {
  * the returned pointer.
  */
 int read_server_text(StrBuf *Buf, long *nLines) {
-       wcsession *WCC = WC;
        StrBuf *ReadBuf;
        long nRead;
        long nTotal = 0;
@@ -424,7 +424,7 @@ int read_server_text(StrBuf *Buf, long *nLines) {
        
        nlines = 0;
        ReadBuf = NewStrBuf();
-       while ((WCC->serv_sock!=-1) &&
+       while ((WC->serv_sock!=-1) &&
               (nRead = StrBuf_ServGetln(ReadBuf), (nRead >= 0) &&
                ((nRead != 3)||(strcmp(ChrPtr(ReadBuf), "000") != 0))))
        {
@@ -459,38 +459,33 @@ void tmplput_serv_ip(StrBuf *Target, WCTemplputParams *TP) {
 }
 
 void tmplput_serv_admin(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
-       StrBufAppendTemplate(Target, TP, WCC->serv_info->serv_sysadm, 0);
+       StrBufAppendTemplate(Target, TP, WC->serv_info->serv_sysadm, 0);
 }
 
 void tmplput_serv_nodename(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
-       StrBufAppendTemplate(Target, TP, WCC->serv_info->serv_nodename, 0);
+       StrBufAppendTemplate(Target, TP, WC->serv_info->serv_nodename, 0);
 }
 
 void tmplput_serv_humannode(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
-       StrBufAppendTemplate(Target, TP, WCC->serv_info->serv_humannode, 0);
+       StrBufAppendTemplate(Target, TP, WC->serv_info->serv_humannode, 0);
 }
 
 void tmplput_serv_fqdn(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
-       StrBufAppendTemplate(Target, TP, WCC->serv_info->serv_fqdn, 0);
+       StrBufAppendTemplate(Target, TP, WC->serv_info->serv_fqdn, 0);
 }
 
 void tmplput_serv_software(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
-       StrBufAppendTemplate(Target, TP, WCC->serv_info->serv_software, 0);
+       StrBufAppendTemplate(Target, TP, WC->serv_info->serv_software, 0);
 }
 
 void tmplput_serv_rev_level(StrBuf *Target, WCTemplputParams *TP) {
@@ -498,43 +493,37 @@ void tmplput_serv_rev_level(StrBuf *Target, WCTemplputParams *TP) {
        StrBufAppendPrintf(Target, "%d", WC->serv_info->serv_rev_level);
 }
 int conditional_serv_newuser_disabled(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return 0;
-       return WCC->serv_info->serv_newuser_disabled != 0;
+       return WC->serv_info->serv_newuser_disabled != 0;
 }
 
 int conditional_serv_supports_guest(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-        if (WCC->serv_info == NULL)
+        if (WC->serv_info == NULL)
                return 0;
-        return WCC->serv_info->serv_supports_guest != 0;
+        return WC->serv_info->serv_supports_guest != 0;
 }
 
 int conditional_serv_supports_openid(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return 0;
-       return WCC->serv_info->serv_supports_openid != 0;
+       return WC->serv_info->serv_supports_openid != 0;
 }
 
 int conditional_serv_fulltext_enabled(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return 0;
-       return WCC->serv_info->serv_fulltext_enabled != 0;
+       return WC->serv_info->serv_fulltext_enabled != 0;
 }
 
 int conditional_serv_ldap_enabled(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return 0;
-       return WCC->serv_info->serv_supports_ldap != 0;
+       return WC->serv_info->serv_supports_ldap != 0;
 }
 
 void tmplput_serv_bbs_city(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if (WCC->serv_info == NULL)
+       if (WC->serv_info == NULL)
                return;
        StrBufAppendTemplate(Target, TP, WC->serv_info->serv_bbs_city, 0);
 }
@@ -573,9 +562,8 @@ void tmplput_mesg(StrBuf *Target, WCTemplputParams *TP) {
 }
 
 void tmplput_site_prefix(StrBuf *Target, WCTemplputParams *TP) {
-       wcsession *WCC = WC;
-       if ((WCC != NULL) && (WCC->Hdr->HostHeader != NULL)) {
-               StrBufAppendTemplate(Target, TP, WCC->Hdr->HostHeader, 0);
+       if ((WC != NULL) && (WC->Hdr->HostHeader != NULL)) {
+               StrBufAppendTemplate(Target, TP, WC->Hdr->HostHeader, 0);
        }
 }
 
@@ -624,10 +612,6 @@ void
 InitModule_SERVFUNC
 (void)
 {
-       is_uds = strcasecmp(ctdlhost, "uds") == 0;
-       if (is_uds)
-               snprintf(serv_sock_name, PATH_MAX, "%s/citadel.socket", ctdlport);
-
        RegisterConditional("COND:SERV:OPENID", 2, conditional_serv_supports_openid, CTX_NONE);
        RegisterConditional("COND:SERV:NEWU", 2, conditional_serv_newuser_disabled, CTX_NONE);
        RegisterConditional("COND:SERV:FULLTEXT_ENABLED", 2, conditional_serv_fulltext_enabled, CTX_NONE);
diff --git a/webcit/sockets.c b/webcit/sockets.c
new file mode 100644 (file)
index 0000000..57ca654
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * Copyright (c) 1987-2021 by the citadel.org team
+ *
+ * This program is open source software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 3.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Uncomment this to log all communications with the Citadel server
+#define SERV_TRACE 1
+ */
+
+#include "webcit.h"
+#include "webserver.h"
+
+long MaxRead = -1; /* should we do READ scattered or all at once? */
+
+/*
+ * register the timeout
+ */
+RETSIGTYPE timeout(int signum) {
+       syslog(LOG_WARNING, "Connection timed out; unable to reach citserver\n");
+       /* no exit here, since we need to server the connection unreachable thing. exit(3); */
+}
+
+
+/*
+ * Client side - connect to a unix domain socket
+ */
+int connect_to_citadel(char *sockpath) {
+       struct sockaddr_un addr;
+       int s;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0) {
+               syslog(LOG_WARNING, "Can't create socket [%s]: %s\n", sockpath, strerror(errno));
+               return(-1);
+       }
+
+       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               syslog(LOG_WARNING, "Can't connect [%s]: %s\n", sockpath, strerror(errno));
+               close(s);
+               return(-1);
+       }
+       return s;
+}
+
+
+/*
+ *  input string from pipe
+ */
+int serv_getln(char *strbuf, int bufsize) {
+       int len;
+
+       *strbuf = '\0';
+       StrBuf_ServGetln(WC->MigrateReadLineBuf);
+       len = StrLength(WC->MigrateReadLineBuf);
+       if (len > bufsize)
+               len = bufsize - 1;
+       memcpy(strbuf, ChrPtr(WC->MigrateReadLineBuf), len);
+       FlushStrBuf(WC->MigrateReadLineBuf);
+       strbuf[len] = '\0';
+#ifdef SERV_TRACE
+       syslog(LOG_DEBUG, "%3d<<<%s\n", WC->serv_sock, strbuf);
+#endif
+       return len;
+}
+
+
+int StrBuf_ServGetln(StrBuf *buf) {
+       const char *ErrStr = NULL;
+       int rc;
+       
+       if (!WC->connected)
+               return -1;
+
+       FlushStrBuf(buf);
+       rc = StrBufTCP_read_buffered_line_fast(buf, 
+                                              WC->ReadBuf, 
+                                              &WC->ReadPos, 
+                                              &WC->serv_sock, 
+                                              5, 1, 
+                                              &ErrStr);
+       if (rc < 0)
+       {
+               syslog(LOG_INFO, "StrBuf_ServGetln(): Server connection broken: %s\n",
+                       (ErrStr)?ErrStr:"");
+               wc_backtrace(LOG_INFO);
+               if (WC->serv_sock > 0) close(WC->serv_sock);
+               WC->serv_sock = (-1);
+               WC->connected = 0;
+               WC->logged_in = 0;
+       }
+#ifdef SERV_TRACE
+       else 
+       {
+               long pos = 0;
+               if (WC->ReadPos != NULL)
+                       pos = WC->ReadPos - ChrPtr(WC->ReadBuf);
+               syslog(LOG_DEBUG, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf));
+       }
+#endif
+       return rc;
+}
+
+int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize) {
+       const char *ErrStr;
+       int rc;
+       
+       rc = StrBufReadBLOBBuffered(buf, 
+                                   WC->ReadBuf, 
+                                   &WC->ReadPos,
+                                   &WC->serv_sock, 
+                                   1, 
+                                   BlobSize, 
+                                   NNN_TERM,
+                                   &ErrStr);
+       if (rc < 0) {
+               syslog(LOG_INFO, "StrBuf_ServGetBLOBBuffered(): Server connection broken: %s\n",
+                       (ErrStr)?ErrStr:"");
+               wc_backtrace(LOG_INFO);
+               if (WC->serv_sock > 0) close(WC->serv_sock);
+               WC->serv_sock = (-1);
+               WC->connected = 0;
+               WC->logged_in = 0;
+       }
+#ifdef SERV_TRACE
+        else
+                syslog(LOG_DEBUG, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
+#endif
+
+       return rc;
+}
+
+int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize) {
+       const char *ErrStr;
+       int rc;
+       
+       WC->ReadPos = NULL;
+       rc = StrBufReadBLOB(buf, &WC->serv_sock, 1, BlobSize, &ErrStr);
+       if (rc < 0) {
+               syslog(LOG_INFO, "StrBuf_ServGetBLOB(): Server connection broken: %s\n",
+                       (ErrStr)?ErrStr:"");
+               wc_backtrace(LOG_INFO);
+               if (WC->serv_sock > 0) close(WC->serv_sock);
+               WC->serv_sock = (-1);
+               WC->connected = 0;
+               WC->logged_in = 0;
+       }
+#ifdef SERV_TRACE
+        else
+                syslog(LOG_DEBUG, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
+#endif
+
+       return rc;
+}
+
+
+void FlushReadBuf (void) {
+       long len;
+       const char *pch;
+       const char *pche;
+
+       len = StrLength(WC->ReadBuf);
+       if ((len > 0) && (WC->ReadPos != NULL) && (WC->ReadPos != StrBufNOTNULL)) {
+               pch = ChrPtr(WC->ReadBuf);
+               pche = pch + len;
+               if (WC->ReadPos != pche) {
+                       syslog(LOG_ERR,
+                               "ERROR: somebody didn't eat his soup! Remaing Chars: %ld [%s]\n", 
+                               (long)(pche - WC->ReadPos),
+                               pche
+                       );
+                       syslog(LOG_ERR, 
+                               "--------------------------------------------------------------------------------\n"
+                               "Whole buf: [%s]\n"
+                               "--------------------------------------------------------------------------------\n", 
+                               pch);
+                       AppendImportantMessage(HKEY("Suppenkasper alert! watch your webcit logfile and get connected to your favourite opensource Crew."));
+               }
+       }
+
+       FlushStrBuf(WC->ReadBuf);
+       WC->ReadPos = NULL;
+
+
+}
+
+
+/*
+ *  send binary to server
+ *  buf the buffer to write to citadel server
+ *  nbytes how many bytes to send to citadel server
+ */
+int serv_write(const char *buf, int nbytes) {
+       int bytes_written = 0;
+       int retval;
+
+       FlushReadBuf();
+       while (bytes_written < nbytes) {
+               retval = write(WC->serv_sock, &buf[bytes_written], nbytes - bytes_written);
+               if (retval < 1) {
+                       const char *ErrStr = strerror(errno);
+                       syslog(LOG_INFO, "serv_write(): Server connection broken: %s\n", (ErrStr)?ErrStr:"");
+                       if (WC->serv_sock > 0) close(WC->serv_sock);
+                       WC->serv_sock = (-1);
+                       WC->connected = 0;
+                       WC->logged_in = 0;
+                       return 0;
+               }
+               bytes_written = bytes_written + retval;
+       }
+       return 1;
+}
+
+
+/*
+ *  send line to server
+ *  string the line to send to the citadel server
+ */
+int serv_puts(const char *string) {
+#ifdef SERV_TRACE
+       syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, string);
+#endif
+       FlushReadBuf();
+
+       if (!serv_write(string, strlen(string)))
+               return 0;
+       return serv_write("\n", 1);
+}
+
+/*
+ *  send line to server
+ *  string the line to send to the citadel server
+ */
+int serv_putbuf(const StrBuf *string) {
+#ifdef SERV_TRACE
+       syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string));
+#endif
+       FlushReadBuf();
+
+       if (!serv_write(ChrPtr(string), StrLength(string)))
+               return 0;
+       return serv_write("\n", 1);
+}
+
+
+/*
+ *  convenience function to send stuff to the server
+ *  format the formatstring
+ *  ... the entities to insert into format 
+ */
+int serv_printf(const char *format,...) {
+       va_list arg_ptr;
+       char buf[SIZ];
+       size_t len;
+       int rc;
+
+       FlushReadBuf();
+
+       va_start(arg_ptr, format);
+       vsnprintf(buf, sizeof buf, format, arg_ptr);
+       va_end(arg_ptr);
+
+       len = strlen(buf);
+       buf[len++] = '\n';
+       buf[len] = '\0';
+       rc = serv_write(buf, len);
+#ifdef SERV_TRACE
+       syslog(LOG_DEBUG, ">>>%s", buf);
+#endif
+       return rc;
+}
+
+
+/*
+ * Read binary data from server into memory using a series of server READ commands.
+ * returns the read content as StrBuf
+ */
+int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) {
+       size_t bytes_read = 0;
+       size_t this_block = 0;
+       int rc = 6;
+       int ServerRc = 6;
+
+       if (Ret == NULL) {
+               return -1;
+       }
+
+       while ((bytes_read < total_len) && (ServerRc == 6)) {
+
+               if (WC->serv_sock==-1) {
+                       FlushStrBuf(Ret); 
+                       return -1; 
+               }
+
+               serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read);
+               if ( (rc = StrBuf_ServGetln(Buf) > 0) && (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) {
+                       if (rc < 0)
+                               return rc;
+                       StrBufCutLeft(Buf, 4);
+                       this_block = StrTol(Buf);
+                       rc = StrBuf_ServGetBLOBBuffered(Ret, this_block);
+                       if (rc < 0) {
+                               syslog(LOG_INFO, "Server connection broken during download\n");
+                               wc_backtrace(LOG_INFO);
+                               if (WC->serv_sock > 0) close(WC->serv_sock);
+                               WC->serv_sock = (-1);
+                               WC->connected = 0;
+                               WC->logged_in = 0;
+                               return rc;
+                       }
+                       bytes_read += rc;
+               }
+       }
+
+       return StrLength(Ret);
+}
+
+
+int client_write(StrBuf *ThisBuf) {
+        const char *ptr, *eptr;
+        long count;
+       ssize_t res = 0;
+        fd_set wset;
+        int fdflags;
+
+       ptr = ChrPtr(ThisBuf);
+       count = StrLength(ThisBuf);
+       eptr = ptr + count;
+
+       fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
+
+        while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
+                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+                        FD_ZERO(&wset);
+                        FD_SET(WC->Hdr->http_sock, &wset);
+                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
+                                syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno));
+                                return -1;
+                        }
+                }
+
+                if ((WC->Hdr->http_sock == -1) || ((res = write(WC->Hdr->http_sock, ptr, count)), (res == -1))) {
+                        syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno));
+                       wc_backtrace(LOG_INFO);
+                        return -1;
+                }
+                count -= res;
+               ptr += res;
+        }
+       return 0;
+}
+
+
+int read_serv_chunk( StrBuf *Buf, size_t total_len, size_t *bytes_read) {
+       int rc;
+       int ServerRc;
+
+       serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, *bytes_read, total_len-(*bytes_read));
+       if ( (rc = StrBuf_ServGetln(Buf) > 0) && (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) {
+               size_t this_block = 0;
+
+               if (rc < 0)
+                       return rc;
+
+               StrBufCutLeft(Buf, 4);
+               this_block = StrTol(Buf);
+               rc = StrBuf_ServGetBLOBBuffered(WC->WBuf, this_block);
+               if (rc < 0) {
+                       syslog(LOG_INFO, "Server connection broken during download\n");
+                       wc_backtrace(LOG_INFO);
+                       if (WC->serv_sock > 0) close(WC->serv_sock);
+                       WC->serv_sock = (-1);
+                       WC->connected = 0;
+                       WC->logged_in = 0;
+                       return rc;
+               }
+               *bytes_read += rc;
+       }
+       return 6;
+}
+
+static inline int send_http(StrBuf *Buf) {
+#ifdef HAVE_OPENSSL
+       if (is_https)
+               return client_write_ssl(Buf);
+       else
+#endif
+               return client_write(Buf);
+}
+/*
+ * Read binary data from server into memory using a series of server READ commands.
+ * returns the read content as StrBuf
+ */
+void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime) {
+       int ServerRc = 6;
+       size_t bytes_read = 0;
+       int first = 1;
+       int client_con_state = 0;
+       int chunked = 0;
+       int is_gzip = 0;
+       const char *Err = NULL;
+       StrBuf *BufHeader = NULL;
+       StrBuf *Buf;
+       StrBuf *pBuf = NULL;
+       vStreamT *SC = NULL;
+       IOBuffer ReadBuffer;
+       IOBuffer WriteBuffer;
+       
+
+       Buf = NewStrBuf();
+
+       if (WC->Hdr->HaveRange) {
+               WC->Hdr->HaveRange++;
+               WC->Hdr->TotalBytes = total_len;
+               /* open range? or beyound file border? correct the numbers. */
+               if ((WC->Hdr->RangeTil == -1) || (WC->Hdr->RangeTil>= total_len))
+                       WC->Hdr->RangeTil = total_len - 1;
+               bytes_read = WC->Hdr->RangeStart;
+               total_len = WC->Hdr->RangeTil;
+       }
+       else
+               chunked = total_len > SIZ * 10; /* TODO: disallow for HTTP / 1.0 */
+
+       if (chunked) {
+               BufHeader = NewStrBuf();
+       }
+
+       if ((detect_mime != 0) && (bytes_read != 0)) {
+               /* need to read first chunk to detect mime, though the client doesn't care */
+               size_t bytes_read = 0;
+               const char *CT;
+
+               ServerRc = read_serv_chunk(
+                       Buf,
+                       total_len,
+                       &bytes_read);
+
+               if (ServerRc != 6)
+               {
+                       FreeStrBuf(&BufHeader);
+                       FreeStrBuf(&Buf);
+                       return;
+               }
+               CT = GuessMimeType(SKEY(WC->WBuf));
+               FlushStrBuf(WC->WBuf);
+               StrBufPlain(MimeType, CT, -1);
+               CheckGZipCompressionAllowed(SKEY(MimeType));
+               detect_mime = 0;
+               FreeStrBuf(&Buf);
+       }
+
+       memset(&WriteBuffer, 0, sizeof(IOBuffer));
+       if (chunked && !DisableGzip && WC->Hdr->HR.gzip_ok) {
+               is_gzip = 1;
+               SC = StrBufNewStreamContext (eZLibEncode, &Err);
+               if (SC == NULL) {
+                       syslog(LOG_ERR, "Error while initializing stream context: %s", Err);
+                       FreeStrBuf(&Buf);
+                       return;
+               }
+
+               memset(&ReadBuffer, 0, sizeof(IOBuffer));
+               ReadBuffer.Buf = WC->WBuf;
+
+               WriteBuffer.Buf = NewStrBufPlain(NULL, SIZ*2);;
+               pBuf = WriteBuffer.Buf;
+       }
+       else {
+               pBuf = WC->WBuf;
+       }
+
+       if (!detect_mime) {
+               http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
+               
+               if (send_http(WC->HBuf) < 0) {
+                       FreeStrBuf(&Buf);
+                       FreeStrBuf(&WriteBuffer.Buf);
+                       FreeStrBuf(&BufHeader);
+                       if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
+                               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
+                       }
+                       return;
+               }
+       }
+
+       while ((bytes_read < total_len) && (ServerRc == 6) && (client_con_state == 0)) {
+
+               if (WC->serv_sock==-1) {
+                       FlushStrBuf(WC->WBuf); 
+                       FreeStrBuf(&Buf);
+                       FreeStrBuf(&WriteBuffer.Buf);
+                       FreeStrBuf(&BufHeader);
+                       StrBufDestroyStreamContext(eZLibEncode, &SC, &Err);
+                       if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
+                               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
+                       }
+                       return;
+               }
+
+               ServerRc = read_serv_chunk(
+                       Buf,
+                       total_len,
+                       &bytes_read);
+               if (ServerRc != 6)
+                       break;
+
+               if (detect_mime) {
+                       const char *CT;
+                       detect_mime = 0;
+                       
+                       CT = GuessMimeType(SKEY(WC->WBuf));
+                       StrBufPlain(MimeType, CT, -1);
+                       if (is_gzip) {
+                               CheckGZipCompressionAllowed(SKEY(MimeType));
+                               is_gzip = WC->Hdr->HR.gzip_ok;
+                       }
+                       http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
+                       
+                       client_con_state = send_http(WC->HBuf);
+               }
+
+               if (is_gzip) {
+                       int done = (bytes_read == total_len);
+                       while ((IOBufferStrLength(&ReadBuffer) > 0) && (client_con_state == 0)) {
+                               int rc;
+
+                               do {
+                                       rc = StrBufStreamTranscode(eZLibEncode, &WriteBuffer, &ReadBuffer, NULL, -1, SC, done, &Err);
+
+                                       if (StrLength (pBuf) > 0) {
+                                               StrBufPrintf(BufHeader, "%s%x\r\n", 
+                                                    (first)?"":"\r\n",
+                                                            StrLength (pBuf));
+                                               first = 0;
+                                               client_con_state = send_http(BufHeader);
+                                               if (client_con_state == 0) {
+                                                       client_con_state = send_http(pBuf);
+                                               }
+                                               FlushStrBuf(pBuf);
+                                       }
+                               } while ((rc == 1) && (StrLength(pBuf) > 0));
+                       }
+                       FlushStrBuf(WC->WBuf);
+               }
+               else {
+                       if ((chunked) && (client_con_state == 0)) {
+                               StrBufPrintf(BufHeader, "%s%x\r\n", 
+                                            (first)?"":"\r\n",
+                                            StrLength (pBuf));
+                               first = 0;
+                               client_con_state = send_http(BufHeader);
+                       }
+
+                       if (client_con_state == 0)
+                               client_con_state = send_http(pBuf);
+
+                       FlushStrBuf(pBuf);
+               }
+       }
+
+       if (SC && StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
+               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
+       }
+       FreeStrBuf(&WriteBuffer.Buf);
+       if ((chunked) && (client_con_state == 0)) {
+               StrBufPlain(BufHeader, HKEY("\r\n0\r\n\r\n"));
+               if (send_http(BufHeader) < 0) {
+                       FreeStrBuf(&Buf);
+                       FreeStrBuf(&BufHeader);
+                       return;
+               }
+       }
+       FreeStrBuf(&BufHeader);
+       FreeStrBuf(&Buf);
+}
+
+int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target) {
+       const char *Error;
+#ifdef HAVE_OPENSSL
+       const char *pch, *pchs;
+       int rlen, len, retval = 0;
+
+       if (is_https) {
+               int ntries = 0;
+               if (StrLength(Hdr->ReadBuf) > 0) {
+                       pchs = ChrPtr(Hdr->ReadBuf);
+                       pch = strchr(pchs, '\n');
+                       if (pch != NULL) {
+                               rlen = 0;
+                               len = pch - pchs;
+                               if (len > 0 && (*(pch - 1) == '\r') )
+                                       rlen ++;
+                               StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
+                               StrBufCutLeft(Hdr->ReadBuf, len + 1);
+                               return len - rlen;
+                       }
+               }
+
+               while (retval == 0) { 
+                       pch = NULL;
+                       pchs = ChrPtr(Hdr->ReadBuf);
+                       if (*pchs != '\0')
+                               pch = strchr(pchs, '\n');
+                       if (pch == NULL) {
+                               retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING);
+                               pchs = ChrPtr(Hdr->ReadBuf);
+                               pch = strchr(pchs, '\n');
+                               if (pch == NULL)
+                                       retval = 0;
+                       }
+                       if (retval == 0) {
+                               sleeeeeeeeeep(1);
+                               ntries ++;
+                       }
+                       if (ntries > 10)
+                               return 0;
+               }
+               if ((retval > 0) && (pch != NULL)) {
+                       rlen = 0;
+                       len = pch - pchs;
+                       if (len > 0 && (*(pch - 1) == '\r') )
+                               rlen ++;
+                       StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
+                       StrBufCutLeft(Hdr->ReadBuf, len + 1);
+                       return len - rlen;
+
+               }
+               else 
+                       return -1;
+       }
+       else 
+#endif
+               return StrBufTCP_read_buffered_line_fast(Target, 
+                                                        Hdr->ReadBuf,
+                                                        &Hdr->Pos,
+                                                        &Hdr->http_sock,
+                                                        5,
+                                                        1,
+                                                        &Error);
+}
+
+
+/* 
+ * This is a generic function to set up a master socket for listening on
+ * a TCP port.  The server shuts down if the bind fails.  (IPv4/IPv6 version)
+ *
+ * ip_addr     IP address to bind
+ * port_number port number to bind
+ * queue_len   number of incoming connections to allow in the queue
+ */
+int webcit_tcp_server(const char *ip_addr, int port_number, int queue_len) {
+       const char *ipv4broadcast = "0.0.0.0";
+       int IsDefault = 0;
+       struct protoent *p;
+       struct sockaddr_in6 sin6;
+       struct sockaddr_in sin4;
+       int s, i, b;
+       int ip_version = 6;
+
+retry:
+       memset(&sin6, 0, sizeof(sin6));
+       memset(&sin4, 0, sizeof(sin4));
+       sin6.sin6_family = AF_INET6;
+       sin4.sin_family = AF_INET;
+
+       if (    (ip_addr == NULL)                                                       /* any IPv6 */
+               || (IsEmptyStr(ip_addr))
+               || (!strcmp(ip_addr, "*"))
+       ) {
+               IsDefault = 1;
+               ip_version = 6;
+               sin6.sin6_addr = in6addr_any;
+       }
+       else if (!strcmp(ip_addr, "0.0.0.0"))                                           /* any IPv4 */
+       {
+               ip_version = 4;
+               sin4.sin_addr.s_addr = INADDR_ANY;
+       }
+       else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':')))                     /* specific IPv4 */
+       {
+               ip_version = 4;
+               if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
+                       syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
+                       return (-WC_EXIT_BIND);
+               }
+       }
+       else                                                                            /* specific IPv6 */
+       {
+               ip_version = 6;
+               if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
+                       syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
+                       return (-WC_EXIT_BIND);
+               }
+       }
+
+       if (port_number == 0) {
+               syslog(LOG_WARNING, "Cannot start: no port number specified.\n");
+               return (-WC_EXIT_BIND);
+       }
+       sin6.sin6_port = htons((u_short) port_number);
+       sin4.sin_port = htons((u_short) port_number);
+
+       p = getprotobyname("tcp");
+
+       s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
+       if (s < 0) {
+               if (IsDefault && (errno == EAFNOSUPPORT))
+               {
+                       s = 0;
+                       ip_addr = ipv4broadcast;
+                       goto retry;
+               }
+               syslog(LOG_WARNING, "Can't create a listening socket: %s\n", strerror(errno));
+               return (-WC_EXIT_BIND);
+       }
+       /* Set some socket options that make sense. */
+       i = 1;
+       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+
+       if (ip_version == 6) {
+               b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
+       }
+       else {
+               b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
+       }
+
+       if (b < 0) {
+               syslog(LOG_ERR, "Can't bind: %s\n", strerror(errno));
+               close(s);
+               return (-WC_EXIT_BIND);
+       }
+
+       if (listen(s, queue_len) < 0) {
+               syslog(LOG_ERR, "Can't listen: %s\n", strerror(errno));
+               close(s);
+               return (-WC_EXIT_BIND);
+       }
+       return (s);
+}
+
+
+/*
+ * Create a Unix domain socket and listen on it
+ * sockpath - file name of the unix domain socket
+ * queue_len - Number of incoming connections to allow in the queue
+ */
+int webcit_uds_server(char *sockpath, int queue_len) {
+       struct sockaddr_un addr;
+       int s;
+       int i;
+       int actual_queue_len;
+
+       actual_queue_len = queue_len;
+       if (actual_queue_len < 5) actual_queue_len = 5;
+
+       i = unlink(sockpath);
+       if ((i != 0) && (errno != ENOENT)) {
+               syslog(LOG_WARNING, "webcit: can't unlink %s: %s\n",
+                       sockpath, strerror(errno));
+               return (-WC_EXIT_BIND);
+       }
+
+       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) {
+               syslog(LOG_WARNING, "webcit: Can't create a unix domain socket: %s\n", strerror(errno));
+               return (-WC_EXIT_BIND);
+       }
+
+       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+               syslog(LOG_WARNING, "webcit: Can't bind: %s\n", strerror(errno));
+               close(s);
+               return (-WC_EXIT_BIND);
+       }
+
+       if (listen(s, actual_queue_len) < 0) {
+               syslog(LOG_WARNING, "webcit: Can't listen: %s\n", strerror(errno));
+               close(s);
+               return (-WC_EXIT_BIND);
+       }
+
+       chmod(sockpath, 0777);
+       return(s);
+}
+
+
+/*
+ * Read data from the client socket.
+ *
+ * sock                socket fd to read from
+ * buf         buffer to read into 
+ * bytes       number of bytes to read
+ * timeout     Number of seconds to wait before timing out
+ *
+ * Possible return values:
+ *      1       Requested number of bytes has been read.
+ *      0       Request timed out.
+ *     -1      Connection is broken, or other error.
+ */
+int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout) {
+       const char *Error;
+       int retval = 0;
+
+#ifdef HAVE_OPENSSL
+       if (is_https) {
+               long bufremain = 0;
+               long baselen;
+
+               baselen = StrLength(Target);
+
+               if (Hdr->Pos == NULL) {
+                       Hdr->Pos = ChrPtr(Hdr->ReadBuf);
+               }
+
+               if (StrLength(Hdr->ReadBuf) > 0) {
+                       bufremain = StrLength(Hdr->ReadBuf) - (Hdr->Pos - ChrPtr(Hdr->ReadBuf));
+                       
+                       if (bytes < bufremain)
+                               bufremain = bytes;
+                       StrBufAppendBufPlain(Target, Hdr->Pos, bufremain, 0);
+                       StrBufCutLeft(Hdr->ReadBuf, bufremain);
+               }
+
+               if (bytes > bufremain) {
+                       while ((StrLength(Hdr->ReadBuf) + StrLength(Target) < bytes + baselen) &&
+                              (retval >= 0))
+                               retval = client_read_sslbuffer(Hdr->ReadBuf, timeout);
+                       if (retval >= 0) {
+                               StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */
+                               return 1;
+                       }
+                       else {
+                               syslog(LOG_INFO, "client_read_ssl() failed\n");
+                               return -1;
+                       }
+               }
+               else 
+                       return 1;
+       }
+#endif
+       retval = StrBufReadBLOBBuffered(Target, 
+                                       Hdr->ReadBuf, 
+                                       &Hdr->Pos, 
+                                       &Hdr->http_sock, 
+                                       1, 
+                                       bytes,
+                                       O_TERM,
+                                       &Error);
+       if (retval < 0) {
+               syslog(LOG_INFO, "client_read() failed: %s\n", Error);
+               wc_backtrace(LOG_DEBUG);
+               return retval;
+       }
+
+       return 1;
+}
+
+
+/*
+ * Begin buffering HTTP output so we can transmit it all in one write operation later.
+ */
+void begin_burst(void)
+{
+       if (WC->WBuf == NULL) {
+               WC->WBuf = NewStrBufPlain(NULL, 32768);
+       }
+}
+
+
+/*
+ * Finish buffering HTTP output.  [Compress using zlib and] output with a Content-Length: header.
+ */
+long end_burst(void)
+{
+        const char *ptr, *eptr;
+        long count;
+       ssize_t res = 0;
+        fd_set wset;
+        int fdflags;
+
+       if (!DisableGzip && (WC->Hdr->HR.gzip_ok))
+       {
+               if (CompressBuffer(WC->WBuf) > 0)
+                       hprintf("Content-encoding: gzip\r\n");
+               else {
+                       syslog(LOG_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno));
+                       wc_backtrace(LOG_INFO);
+               }
+       }
+
+       if (WC->WFBuf != NULL) {
+               WildFireSerializePayload(WC->WFBuf, WC->HBuf, &WC->Hdr->nWildfireHeaders, NULL);
+               FreeStrBuf(&WC->WFBuf);
+       }
+
+       if (WC->Hdr->HR.prohibit_caching)
+               hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
+       hprintf("Content-length: %d\r\n\r\n", StrLength(WC->WBuf));
+
+       ptr = ChrPtr(WC->HBuf);
+       count = StrLength(WC->HBuf);
+       eptr = ptr + count;
+
+#ifdef HAVE_OPENSSL
+       if (is_https) {
+               client_write_ssl(WC->HBuf);
+               client_write_ssl(WC->WBuf);
+               return (count);
+       }
+#endif
+
+       if (WC->Hdr->http_sock == -1) {
+               return -1;
+       }
+       fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
+
+       while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
+                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+                        FD_ZERO(&wset);
+                        FD_SET(WC->Hdr->http_sock, &wset);
+                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
+                                syslog(LOG_DEBUG, "client_write: Socket select failed (%s)\n", strerror(errno));
+                                return -1;
+                        }
+                }
+
+                if ((WC->Hdr->http_sock == -1) || 
+                   (res = write(WC->Hdr->http_sock, 
+                                ptr,
+                                count)) == -1) {
+                        syslog(LOG_DEBUG, "client_write: Socket write failed (%s)\n", strerror(errno));
+                       wc_backtrace(LOG_INFO);
+                        return res;
+                }
+                count -= res;
+               ptr += res;
+        }
+
+       ptr = ChrPtr(WC->WBuf);
+       count = StrLength(WC->WBuf);
+       eptr = ptr + count;
+
+        while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
+                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+                        FD_ZERO(&wset);
+                        FD_SET(WC->Hdr->http_sock, &wset);
+                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
+                                syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno));
+                                return -1;
+                        }
+                }
+
+                if ((WC->Hdr->http_sock == -1) || 
+                   (res = write(WC->Hdr->http_sock, 
+                                ptr,
+                                count)) == -1) {
+                        syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno));
+                       wc_backtrace(LOG_INFO);
+                        return res;
+                }
+                count -= res;
+               ptr += res;
+        }
+
+       return StrLength(WC->WBuf);
+}
+
+
+/*
+ * lingering_close() a`la Apache. see
+ * http://httpd.apache.org/docs/2.0/misc/fin_wait_2.html for rationale
+ */
+int lingering_close(int fd)
+{
+       char buf[SIZ];
+       int i;
+       fd_set set;
+       struct timeval tv, start;
+
+       gettimeofday(&start, NULL);
+       if (fd == -1)
+               return -1;
+       shutdown(fd, 1);
+       do {
+               do {
+                       gettimeofday(&tv, NULL);
+                       tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
+                       tv.tv_usec = start.tv_usec - tv.tv_usec;
+                       if (tv.tv_usec < 0) {
+                               tv.tv_sec--;
+                               tv.tv_usec += 1000000;
+                       }
+                       FD_ZERO(&set);
+                       FD_SET(fd, &set);
+                       i = select(fd + 1, &set, NULL, NULL, &tv);
+               } while (i == -1 && errno == EINTR);
+
+               if (i <= 0)
+                       break;
+
+               i = read(fd, buf, sizeof buf);
+       } while (i != 0 && (i != -1 || errno == EINTR));
+
+       return close(fd);
+}
+
+void
+HttpNewModule_TCPSOCKETS
+(ParsedHttpHdrs *httpreq)
+{
+
+       httpreq->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
+}
+
+void
+HttpDetachModule_TCPSOCKETS
+(ParsedHttpHdrs *httpreq)
+{
+
+       FlushStrBuf(httpreq->ReadBuf);
+       ReAdjustEmptyBuf(httpreq->ReadBuf, 4 * SIZ, SIZ);
+}
+
+void
+HttpDestroyModule_TCPSOCKETS
+(ParsedHttpHdrs *httpreq)
+{
+
+       FreeStrBuf(&httpreq->ReadBuf);
+}
+
+
+void
+SessionNewModule_TCPSOCKETS
+(wcsession *sess)
+{
+       sess->CLineBuf = NewStrBuf();
+       sess->MigrateReadLineBuf = NewStrBuf();
+}
+
+void 
+SessionDestroyModule_TCPSOCKETS
+(wcsession *sess)
+{
+       FreeStrBuf(&sess->CLineBuf);
+       FreeStrBuf(&sess->ReadBuf);
+       sess->connected = 0;
+       sess->ReadPos = NULL;
+       FreeStrBuf(&sess->MigrateReadLineBuf);
+       if (sess->serv_sock > 0) {
+               syslog(LOG_DEBUG, "Closing socket %d", sess->serv_sock);
+               close(sess->serv_sock);
+       }
+       sess->serv_sock = -1;
+}
diff --git a/webcit/sockets.h b/webcit/sockets.h
new file mode 100644 (file)
index 0000000..340e71e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996-2013 by the citadel.org team
+ *
+ * This program is open source software.  You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+int connect_to_citadel(char *);
+int connectsock(char *, char *);
+int serv_getln(char *strbuf, int bufsize);
+int StrBuf_ServGetln(StrBuf *buf);
+
+/*
+ * parse & check the server reply 
+ *
+ * Line                the line containing the server reply
+ * FullState   if you need more than just the major number, this is returns it. Ignored if NULL.
+ * PutImportantMessage if you want to forward the text part of the server reply to the user, specify 1; 
+ *             the result will be put into the 'Important Message' framework.
+ * MajorOK     in case of which major number not to put the ImportantMessage? 0 for all.
+ *
+ * returns the most significant digit of the server status
+ */
+
+int GetServerStatusMsg(StrBuf *Line, long* FullState, int PutImportantMessage, int MajorOK);
+
+/*
+ * to migrate old calls.... 
+ */
+#define GetServerStatus(a, b) GetServerStatusMsg(a, b, 0, 0)
+
+int serv_puts(const char *string);
+
+int serv_write(const char *buf, int nbytes);
+int serv_putbuf(const StrBuf *string);
+int serv_printf(const char *format,...)__attribute__((__format__(__printf__,1,2)));
+int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf);
+void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime);
+int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize);
+int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize);
+int read_server_text(StrBuf *Buf, long *nLines);
+
+void text_to_server(char *ptr);
+void text_to_server_qp(const StrBuf *SendMeEncoded);
+void server_to_text(void);
+int lingering_close(int fd);
index e5fcc2a80b71f09031eef57a115fb78cf3f2f468..0c58118a0847a8abb035d3c870d814a073d9bf27 100644 (file)
@@ -64,10 +64,6 @@ extern void *context_loop(ParsedHttpHdrs *Hdr);
 extern void *housekeeping_loop(void);
 extern void do_housekeeping(void);
 
-char ctdl_key_dir[PATH_MAX]=SSL_DIR;
-char file_crpt_file_key[PATH_MAX]="";
-char file_crpt_file_csr[PATH_MAX]="";
-char file_crpt_file_cer[PATH_MAX]="";
 char file_etc_mimelist[PATH_MAX]="";
 
 char etc_dir[PATH_MAX];
@@ -520,20 +516,6 @@ webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdi
        StripSlashes(static_icon_dir, 1);
        StripSlashes(static_local_dir, 1);
 
-       snprintf(file_crpt_file_key,
-                sizeof file_crpt_file_key, 
-                "%s/citadel.key",
-                ctdl_key_dir);
-       snprintf(file_crpt_file_csr,
-                sizeof file_crpt_file_csr, 
-                "%s/citadel.csr",
-                ctdl_key_dir);
-       snprintf(file_crpt_file_cer,
-                sizeof file_crpt_file_cer, 
-                "%s/citadel.cer",
-                ctdl_key_dir);
-
-
        basedir=ETCDIR;
        COMPUTE_DIRECTORY(etc_dir);
        StripSlashes(etc_dir, 1);
diff --git a/webcit/tcp_sockets.c b/webcit/tcp_sockets.c
deleted file mode 100644 (file)
index ff07fc6..0000000
+++ /dev/null
@@ -1,1224 +0,0 @@
-/*
- * Copyright (c) 1987-2021 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 3.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * Uncomment this to log all communications with the Citadel server
-#define SERV_TRACE 1
- */
-
-#include "webcit.h"
-#include "webserver.h"
-
-long MaxRead = -1; /* should we do READ scattered or all at once? */
-
-/*
- * register the timeout
- */
-RETSIGTYPE timeout(int signum)
-{
-       syslog(LOG_WARNING, "Connection timed out; unable to reach citserver\n");
-       /* no exit here, since we need to server the connection unreachable thing. exit(3); */
-}
-
-
-/*
- * Client side - connect to a unix domain socket
- */
-int uds_connectsock(char *sockpath)
-{
-       struct sockaddr_un addr;
-       int s;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
-
-       s = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (s < 0) {
-               syslog(LOG_WARNING, "Can't create socket [%s]: %s\n", sockpath, strerror(errno));
-               return(-1);
-       }
-
-       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               syslog(LOG_WARNING, "Can't connect [%s]: %s\n", sockpath, strerror(errno));
-               close(s);
-               return(-1);
-       }
-       return s;
-}
-
-
-/*
- * TCP client - connect to a host/port 
- */
-int tcp_connectsock(char *host, char *service)
-{
-       struct in6_addr serveraddr;
-       struct addrinfo hints;
-       struct addrinfo *res = NULL;
-       struct addrinfo *ai = NULL;
-       int rc = (-1);
-       int s = (-1);
-
-       if ((host == NULL) || IsEmptyStr(host))
-               return (-1);
-       if ((service == NULL) || IsEmptyStr(service))
-               return (-1);
-
-       syslog(LOG_DEBUG, "tcp_connectsock(%s,%s)\n", host, service);
-
-       memset(&hints, 0x00, sizeof(hints));
-       hints.ai_flags = AI_NUMERICSERV;
-       hints.ai_family = AF_UNSPEC;
-       hints.ai_socktype = SOCK_STREAM;
-
-       /*
-        * Handle numeric IPv4 and IPv6 addresses
-        */
-       rc = inet_pton(AF_INET, host, &serveraddr);
-       if (rc == 1) {                                          /* dotted quad */
-               hints.ai_family = AF_INET;
-               hints.ai_flags |= AI_NUMERICHOST;
-       } else {
-               rc = inet_pton(AF_INET6, host, &serveraddr);
-               if (rc == 1) {                                  /* IPv6 address */
-                       hints.ai_family = AF_INET6;
-                       hints.ai_flags |= AI_NUMERICHOST;
-               }
-       }
-
-       /* Begin the connection process */
-
-       rc = getaddrinfo(host, service, &hints, &res);
-       if (rc != 0) {
-               syslog(LOG_DEBUG, "%s: %s\n", host, gai_strerror(rc));
-               freeaddrinfo(res);
-               return(-1);
-       }
-
-       /*
-        * Try all available addresses until we connect to one or until we run out.
-        */
-       for (ai = res; ai != NULL; ai = ai->ai_next) {
-
-               if (ai->ai_family == AF_INET) syslog(LOG_DEBUG, "Trying IPv4\n");
-               else if (ai->ai_family == AF_INET6) syslog(LOG_DEBUG, "Trying IPv6\n");
-               else syslog(LOG_WARNING, "This is going to fail.\n");
-
-               s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-               if (s < 0) {
-                       syslog(LOG_WARNING, "socket() failed: %s\n", strerror(errno));
-                       freeaddrinfo(res);
-                       return(-1);
-               }
-               rc = connect(s, ai->ai_addr, ai->ai_addrlen);
-               if (rc >= 0) {
-                       int fdflags;
-                       freeaddrinfo(res);
-
-                       fdflags = fcntl(rc, F_GETFL);
-                       if (fdflags < 0) {
-                               syslog(LOG_ERR,
-                                      "unable to get socket %d flags! %s \n",
-                                      rc,
-                                      strerror(errno));
-                               close(rc);
-                               return -1;
-                       }
-                       fdflags = fdflags | O_NONBLOCK;
-                       if (fcntl(rc, F_SETFL, fdflags) < 0) {
-                               syslog(LOG_ERR,
-                                      "unable to set socket %d nonblocking flags! %s \n",
-                                      rc,
-                                      strerror(errno));
-                               close(s);
-                               return -1;
-                       }
-
-                       return(s);
-               }
-               else {
-                       syslog(LOG_WARNING, "connect() failed: %s\n", strerror(errno));
-                       close(s);
-               }
-       }
-        freeaddrinfo(res);
-       return(-1);
-}
-
-
-/*
- *  input string from pipe
- */
-int serv_getln(char *strbuf, int bufsize)
-{
-       int len;
-
-       *strbuf = '\0';
-       StrBuf_ServGetln(WC->MigrateReadLineBuf);
-       len = StrLength(WC->MigrateReadLineBuf);
-       if (len > bufsize)
-               len = bufsize - 1;
-       memcpy(strbuf, ChrPtr(WC->MigrateReadLineBuf), len);
-       FlushStrBuf(WC->MigrateReadLineBuf);
-       strbuf[len] = '\0';
-#ifdef SERV_TRACE
-       syslog(LOG_DEBUG, "%3d<<<%s\n", WC->serv_sock, strbuf);
-#endif
-       return len;
-}
-
-
-int StrBuf_ServGetln(StrBuf *buf)
-{
-       const char *ErrStr = NULL;
-       int rc;
-       
-       if (!WC->connected)
-               return -1;
-
-       FlushStrBuf(buf);
-       rc = StrBufTCP_read_buffered_line_fast(buf, 
-                                              WC->ReadBuf, 
-                                              &WC->ReadPos, 
-                                              &WC->serv_sock, 
-                                              5, 1, 
-                                              &ErrStr);
-       if (rc < 0)
-       {
-               syslog(LOG_INFO, "StrBuf_ServGetln(): Server connection broken: %s\n",
-                       (ErrStr)?ErrStr:"");
-               wc_backtrace(LOG_INFO);
-               if (WC->serv_sock > 0) close(WC->serv_sock);
-               WC->serv_sock = (-1);
-               WC->connected = 0;
-               WC->logged_in = 0;
-       }
-#ifdef SERV_TRACE
-       else 
-       {
-               long pos = 0;
-               if (WC->ReadPos != NULL)
-                       pos = WC->ReadPos - ChrPtr(WC->ReadBuf);
-               syslog(LOG_DEBUG, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf));
-       }
-#endif
-       return rc;
-}
-
-int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize)
-{
-       const char *ErrStr;
-       int rc;
-       
-       rc = StrBufReadBLOBBuffered(buf, 
-                                   WC->ReadBuf, 
-                                   &WC->ReadPos,
-                                   &WC->serv_sock, 
-                                   1, 
-                                   BlobSize, 
-                                   NNN_TERM,
-                                   &ErrStr);
-       if (rc < 0)
-       {
-               syslog(LOG_INFO, "StrBuf_ServGetBLOBBuffered(): Server connection broken: %s\n",
-                       (ErrStr)?ErrStr:"");
-               wc_backtrace(LOG_INFO);
-               if (WC->serv_sock > 0) close(WC->serv_sock);
-               WC->serv_sock = (-1);
-               WC->connected = 0;
-               WC->logged_in = 0;
-       }
-#ifdef SERV_TRACE
-        else
-                syslog(LOG_DEBUG, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
-#endif
-
-       return rc;
-}
-
-int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize)
-{
-       const char *ErrStr;
-       int rc;
-       
-       WC->ReadPos = NULL;
-       rc = StrBufReadBLOB(buf, &WC->serv_sock, 1, BlobSize, &ErrStr);
-       if (rc < 0)
-       {
-               syslog(LOG_INFO, "StrBuf_ServGetBLOB(): Server connection broken: %s\n",
-                       (ErrStr)?ErrStr:"");
-               wc_backtrace(LOG_INFO);
-               if (WC->serv_sock > 0) close(WC->serv_sock);
-               WC->serv_sock = (-1);
-               WC->connected = 0;
-               WC->logged_in = 0;
-       }
-#ifdef SERV_TRACE
-        else
-                syslog(LOG_DEBUG, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
-#endif
-
-       return rc;
-}
-
-
-void FlushReadBuf (void)
-{
-       long len;
-       const char *pch;
-       const char *pche;
-
-       len = StrLength(WC->ReadBuf);
-       if ((len > 0) &&
-           (WC->ReadPos != NULL) && 
-           (WC->ReadPos != StrBufNOTNULL))
-               
-       {
-               pch = ChrPtr(WC->ReadBuf);
-               pche = pch + len;
-               if (WC->ReadPos != pche)
-               {
-                       syslog(LOG_ERR,
-                               "ERROR: somebody didn't eat his soup! Remaing Chars: %ld [%s]\n", 
-                               (long)(pche - WC->ReadPos),
-                               pche
-                       );
-                       syslog(LOG_ERR, 
-                               "--------------------------------------------------------------------------------\n"
-                               "Whole buf: [%s]\n"
-                               "--------------------------------------------------------------------------------\n", 
-                               pch);
-                       AppendImportantMessage(HKEY("Suppenkasper alert! watch your webcit logfile and get connected to your favourite opensource Crew."));
-               }
-       }
-
-       FlushStrBuf(WC->ReadBuf);
-       WC->ReadPos = NULL;
-
-
-}
-
-
-/*
- *  send binary to server
- *  buf the buffer to write to citadel server
- *  nbytes how many bytes to send to citadel server
- */
-int serv_write(const char *buf, int nbytes)
-{
-       int bytes_written = 0;
-       int retval;
-
-       FlushReadBuf();
-       while (bytes_written < nbytes) {
-               retval = write(WC->serv_sock, &buf[bytes_written],
-                              nbytes - bytes_written);
-               if (retval < 1) {
-                       const char *ErrStr = strerror(errno);
-                       syslog(LOG_INFO, "serv_write(): Server connection broken: %s\n",
-                               (ErrStr)?ErrStr:"");
-                       if (WC->serv_sock > 0) close(WC->serv_sock);
-                       WC->serv_sock = (-1);
-                       WC->connected = 0;
-                       WC->logged_in = 0;
-                       return 0;
-               }
-               bytes_written = bytes_written + retval;
-       }
-       return 1;
-}
-
-
-/*
- *  send line to server
- *  string the line to send to the citadel server
- */
-int serv_puts(const char *string)
-{
-#ifdef SERV_TRACE
-       syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, string);
-#endif
-       FlushReadBuf();
-
-       if (!serv_write(string, strlen(string)))
-               return 0;
-       return serv_write("\n", 1);
-}
-
-/*
- *  send line to server
- *  string the line to send to the citadel server
- */
-int serv_putbuf(const StrBuf *string)
-{
-#ifdef SERV_TRACE
-       syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string));
-#endif
-       FlushReadBuf();
-
-       if (!serv_write(ChrPtr(string), StrLength(string)))
-               return 0;
-       return serv_write("\n", 1);
-}
-
-
-/*
- *  convenience function to send stuff to the server
- *  format the formatstring
- *  ... the entities to insert into format 
- */
-int serv_printf(const char *format,...)
-{
-       va_list arg_ptr;
-       char buf[SIZ];
-       size_t len;
-       int rc;
-
-       FlushReadBuf();
-
-       va_start(arg_ptr, format);
-       vsnprintf(buf, sizeof buf, format, arg_ptr);
-       va_end(arg_ptr);
-
-       len = strlen(buf);
-       buf[len++] = '\n';
-       buf[len] = '\0';
-       rc = serv_write(buf, len);
-#ifdef SERV_TRACE
-       syslog(LOG_DEBUG, ">>>%s", buf);
-#endif
-       return rc;
-}
-
-
-/*
- * Read binary data from server into memory using a series of server READ commands.
- * returns the read content as StrBuf
- */
-int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) 
-{
-       size_t bytes_read = 0;
-       size_t this_block = 0;
-       int rc = 6;
-       int ServerRc = 6;
-
-       if (Ret == NULL) {
-               return -1;
-       }
-
-       while ((bytes_read < total_len) && (ServerRc == 6)) {
-
-               if (WC->serv_sock==-1) {
-                       FlushStrBuf(Ret); 
-                       return -1; 
-               }
-
-               serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read);
-               if ( (rc = StrBuf_ServGetln(Buf) > 0) &&
-                    (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) 
-               {
-                       if (rc < 0)
-                               return rc;
-                       StrBufCutLeft(Buf, 4);
-                       this_block = StrTol(Buf);
-                       rc = StrBuf_ServGetBLOBBuffered(Ret, this_block);
-                       if (rc < 0) {
-                               syslog(LOG_INFO, "Server connection broken during download\n");
-                               wc_backtrace(LOG_INFO);
-                               if (WC->serv_sock > 0) close(WC->serv_sock);
-                               WC->serv_sock = (-1);
-                               WC->connected = 0;
-                               WC->logged_in = 0;
-                               return rc;
-                       }
-                       bytes_read += rc;
-               }
-       }
-
-       return StrLength(Ret);
-}
-
-
-int client_write(StrBuf *ThisBuf)
-{
-        const char *ptr, *eptr;
-        long count;
-       ssize_t res = 0;
-        fd_set wset;
-        int fdflags;
-
-       ptr = ChrPtr(ThisBuf);
-       count = StrLength(ThisBuf);
-       eptr = ptr + count;
-
-       fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
-
-        while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
-                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
-                        FD_ZERO(&wset);
-                        FD_SET(WC->Hdr->http_sock, &wset);
-                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
-                                syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno));
-                                return -1;
-                        }
-                }
-
-                if ((WC->Hdr->http_sock == -1) || 
-                   ((res = write(WC->Hdr->http_sock, ptr, count)),
-                    (res == -1)))
-               {
-                        syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno));
-                       wc_backtrace(LOG_INFO);
-                        return -1;
-                }
-                count -= res;
-               ptr += res;
-        }
-       return 0;
-}
-
-
-int
-read_serv_chunk(
-
-       StrBuf *Buf,
-       size_t total_len,
-       size_t *bytes_read
-       )
-{
-       int rc;
-       int ServerRc;
-
-       serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, *bytes_read, total_len-(*bytes_read));
-       if ( (rc = StrBuf_ServGetln(Buf) > 0) &&
-            (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) 
-       {
-               size_t this_block = 0;
-
-               if (rc < 0)
-                       return rc;
-
-               StrBufCutLeft(Buf, 4);
-               this_block = StrTol(Buf);
-               rc = StrBuf_ServGetBLOBBuffered(WC->WBuf, this_block);
-               if (rc < 0) {
-                       syslog(LOG_INFO, "Server connection broken during download\n");
-                       wc_backtrace(LOG_INFO);
-                       if (WC->serv_sock > 0) close(WC->serv_sock);
-                       WC->serv_sock = (-1);
-                       WC->connected = 0;
-                       WC->logged_in = 0;
-                       return rc;
-               }
-               *bytes_read += rc;
-       }
-       return 6;
-}
-
-static inline int send_http(StrBuf *Buf)
-{
-#ifdef HAVE_OPENSSL
-       if (is_https)
-               return client_write_ssl(Buf);
-       else
-#endif
-               return client_write(Buf);
-}
-/*
- * Read binary data from server into memory using a series of server READ commands.
- * returns the read content as StrBuf
- */
-void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime)
-{
-       int ServerRc = 6;
-       size_t bytes_read = 0;
-       int first = 1;
-       int client_con_state = 0;
-       int chunked = 0;
-       int is_gzip = 0;
-       const char *Err = NULL;
-       StrBuf *BufHeader = NULL;
-       StrBuf *Buf;
-       StrBuf *pBuf = NULL;
-       vStreamT *SC = NULL;
-       IOBuffer ReadBuffer;
-       IOBuffer WriteBuffer;
-       
-
-       Buf = NewStrBuf();
-
-       if (WC->Hdr->HaveRange)
-       {
-               WC->Hdr->HaveRange++;
-               WC->Hdr->TotalBytes = total_len;
-               /* open range? or beyound file border? correct the numbers. */
-               if ((WC->Hdr->RangeTil == -1) || (WC->Hdr->RangeTil>= total_len))
-                       WC->Hdr->RangeTil = total_len - 1;
-               bytes_read = WC->Hdr->RangeStart;
-               total_len = WC->Hdr->RangeTil;
-       }
-       else
-               chunked = total_len > SIZ * 10; /* TODO: disallow for HTTP / 1.0 */
-
-       if (chunked)
-       {
-               BufHeader = NewStrBuf();
-       }
-
-       if ((detect_mime != 0) && (bytes_read != 0))
-       {
-               /* need to read first chunk to detect mime, though the client doesn't care */
-               size_t bytes_read = 0;
-               const char *CT;
-
-               ServerRc = read_serv_chunk(
-                       Buf,
-                       total_len,
-                       &bytes_read);
-
-               if (ServerRc != 6)
-               {
-                       FreeStrBuf(&BufHeader);
-                       FreeStrBuf(&Buf);
-                       return;
-               }
-               CT = GuessMimeType(SKEY(WC->WBuf));
-               FlushStrBuf(WC->WBuf);
-               StrBufPlain(MimeType, CT, -1);
-               CheckGZipCompressionAllowed(SKEY(MimeType));
-               detect_mime = 0;
-               FreeStrBuf(&Buf);
-       }
-
-       memset(&WriteBuffer, 0, sizeof(IOBuffer));
-       if (chunked && !DisableGzip && WC->Hdr->HR.gzip_ok)
-       {
-               is_gzip = 1;
-               SC = StrBufNewStreamContext (eZLibEncode, &Err);
-               if (SC == NULL) {
-                       syslog(LOG_ERR, "Error while initializing stream context: %s", Err);
-                       FreeStrBuf(&Buf);
-                       return;
-               }
-
-               memset(&ReadBuffer, 0, sizeof(IOBuffer));
-               ReadBuffer.Buf = WC->WBuf;
-
-               WriteBuffer.Buf = NewStrBufPlain(NULL, SIZ*2);;
-               pBuf = WriteBuffer.Buf;
-       }
-       else
-       {
-               pBuf = WC->WBuf;
-       }
-
-       if (!detect_mime)
-       {
-               http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
-               
-               if (send_http(WC->HBuf) < 0)
-               {
-                       FreeStrBuf(&Buf);
-                       FreeStrBuf(&WriteBuffer.Buf);
-                       FreeStrBuf(&BufHeader);
-                       if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
-                               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
-                       }
-                       return;
-               }
-       }
-
-       while ((bytes_read < total_len) &&
-              (ServerRc == 6) &&
-              (client_con_state == 0))
-       {
-
-               if (WC->serv_sock==-1) {
-                       FlushStrBuf(WC->WBuf); 
-                       FreeStrBuf(&Buf);
-                       FreeStrBuf(&WriteBuffer.Buf);
-                       FreeStrBuf(&BufHeader);
-                       StrBufDestroyStreamContext(eZLibEncode, &SC, &Err);
-                       if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
-                               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
-                       }
-                       return;
-               }
-
-               ServerRc = read_serv_chunk(
-                       Buf,
-                       total_len,
-                       &bytes_read);
-               if (ServerRc != 6)
-                       break;
-
-               if (detect_mime)
-               {
-                       const char *CT;
-                       detect_mime = 0;
-                       
-                       CT = GuessMimeType(SKEY(WC->WBuf));
-                       StrBufPlain(MimeType, CT, -1);
-                       if (is_gzip) {
-                               CheckGZipCompressionAllowed(SKEY(MimeType));
-                               is_gzip = WC->Hdr->HR.gzip_ok;
-                       }
-                       http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
-                       
-                       client_con_state = send_http(WC->HBuf);
-               }
-
-               if (is_gzip)
-               {
-                       int done = (bytes_read == total_len);
-                       while ((IOBufferStrLength(&ReadBuffer) > 0) && (client_con_state == 0)) {
-                               int rc;
-
-                               do {
-                                       rc = StrBufStreamTranscode(eZLibEncode, &WriteBuffer, &ReadBuffer, NULL, -1, SC, done, &Err);
-
-                                       if (StrLength (pBuf) > 0) {
-                                               StrBufPrintf(BufHeader, "%s%x\r\n", 
-                                                    (first)?"":"\r\n",
-                                                            StrLength (pBuf));
-                                               first = 0;
-                                               client_con_state = send_http(BufHeader);
-                                               if (client_con_state == 0) {
-                                                       client_con_state = send_http(pBuf);
-                                               }
-                                               FlushStrBuf(pBuf);
-                                       }
-                               } while ((rc == 1) && (StrLength(pBuf) > 0));
-                       }
-                       FlushStrBuf(WC->WBuf);
-               }
-               else {
-                       if ((chunked) && (client_con_state == 0))
-                       {
-                               StrBufPrintf(BufHeader, "%s%x\r\n", 
-                                            (first)?"":"\r\n",
-                                            StrLength (pBuf));
-                               first = 0;
-                               client_con_state = send_http(BufHeader);
-                       }
-
-                       if (client_con_state == 0)
-                               client_con_state = send_http(pBuf);
-
-                       FlushStrBuf(pBuf);
-               }
-       }
-
-       if (SC && StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
-               syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
-       }
-       FreeStrBuf(&WriteBuffer.Buf);
-       if ((chunked) && (client_con_state == 0))
-       {
-               StrBufPlain(BufHeader, HKEY("\r\n0\r\n\r\n"));
-               if (send_http(BufHeader) < 0)
-               {
-                       FreeStrBuf(&Buf);
-                       FreeStrBuf(&BufHeader);
-                       return;
-               }
-       }
-       FreeStrBuf(&BufHeader);
-       FreeStrBuf(&Buf);
-}
-
-int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target)
-{
-       const char *Error;
-#ifdef HAVE_OPENSSL
-       const char *pch, *pchs;
-       int rlen, len, retval = 0;
-
-       if (is_https) {
-               int ntries = 0;
-               if (StrLength(Hdr->ReadBuf) > 0)
-               {
-                       pchs = ChrPtr(Hdr->ReadBuf);
-                       pch = strchr(pchs, '\n');
-                       if (pch != NULL) {
-                               rlen = 0;
-                               len = pch - pchs;
-                               if (len > 0 && (*(pch - 1) == '\r') )
-                                       rlen ++;
-                               StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
-                               StrBufCutLeft(Hdr->ReadBuf, len + 1);
-                               return len - rlen;
-                       }
-               }
-
-               while (retval == 0) { 
-                               pch = NULL;
-                               pchs = ChrPtr(Hdr->ReadBuf);
-                               if (*pchs != '\0')
-                                       pch = strchr(pchs, '\n');
-                               if (pch == NULL) {
-                                       retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING);
-                                       pchs = ChrPtr(Hdr->ReadBuf);
-                                       pch = strchr(pchs, '\n');
-                                       if (pch == NULL)
-                                               retval = 0;
-                               }
-                               if (retval == 0) {
-                                       sleeeeeeeeeep(1);
-                                       ntries ++;
-                               }
-                               if (ntries > 10)
-                                       return 0;
-               }
-               if ((retval > 0) && (pch != NULL)) {
-                       rlen = 0;
-                       len = pch - pchs;
-                       if (len > 0 && (*(pch - 1) == '\r') )
-                               rlen ++;
-                       StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
-                       StrBufCutLeft(Hdr->ReadBuf, len + 1);
-                       return len - rlen;
-
-               }
-               else 
-                       return -1;
-       }
-       else 
-#endif
-               return StrBufTCP_read_buffered_line_fast(Target, 
-                                                        Hdr->ReadBuf,
-                                                        &Hdr->Pos,
-                                                        &Hdr->http_sock,
-                                                        5,
-                                                        1,
-                                                        &Error);
-}
-
-
-/* 
- * This is a generic function to set up a master socket for listening on
- * a TCP port.  The server shuts down if the bind fails.  (IPv4/IPv6 version)
- *
- * ip_addr     IP address to bind
- * port_number port number to bind
- * queue_len   number of incoming connections to allow in the queue
- */
-int webcit_tcp_server(const char *ip_addr, int port_number, int queue_len)
-{
-       const char *ipv4broadcast = "0.0.0.0";
-       int IsDefault = 0;
-       struct protoent *p;
-       struct sockaddr_in6 sin6;
-       struct sockaddr_in sin4;
-       int s, i, b;
-       int ip_version = 6;
-
-retry:
-       memset(&sin6, 0, sizeof(sin6));
-       memset(&sin4, 0, sizeof(sin4));
-       sin6.sin6_family = AF_INET6;
-       sin4.sin_family = AF_INET;
-
-       if (    (ip_addr == NULL)                                                       /* any IPv6 */
-               || (IsEmptyStr(ip_addr))
-               || (!strcmp(ip_addr, "*"))
-       ) {
-               IsDefault = 1;
-               ip_version = 6;
-               sin6.sin6_addr = in6addr_any;
-       }
-       else if (!strcmp(ip_addr, "0.0.0.0"))                                           /* any IPv4 */
-       {
-               ip_version = 4;
-               sin4.sin_addr.s_addr = INADDR_ANY;
-       }
-       else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':')))                     /* specific IPv4 */
-       {
-               ip_version = 4;
-               if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
-                       syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
-                       return (-WC_EXIT_BIND);
-               }
-       }
-       else                                                                            /* specific IPv6 */
-       {
-               ip_version = 6;
-               if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
-                       syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
-                       return (-WC_EXIT_BIND);
-               }
-       }
-
-       if (port_number == 0) {
-               syslog(LOG_WARNING, "Cannot start: no port number specified.\n");
-               return (-WC_EXIT_BIND);
-       }
-       sin6.sin6_port = htons((u_short) port_number);
-       sin4.sin_port = htons((u_short) port_number);
-
-       p = getprotobyname("tcp");
-
-       s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
-       if (s < 0) {
-               if (IsDefault && (errno == EAFNOSUPPORT))
-               {
-                       s = 0;
-                       ip_addr = ipv4broadcast;
-                       goto retry;
-               }
-               syslog(LOG_WARNING, "Can't create a listening socket: %s\n", strerror(errno));
-               return (-WC_EXIT_BIND);
-       }
-       /* Set some socket options that make sense. */
-       i = 1;
-       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
-
-       if (ip_version == 6) {
-               b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
-       }
-       else {
-               b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
-       }
-
-       if (b < 0) {
-               syslog(LOG_ERR, "Can't bind: %s\n", strerror(errno));
-               close(s);
-               return (-WC_EXIT_BIND);
-       }
-
-       if (listen(s, queue_len) < 0) {
-               syslog(LOG_ERR, "Can't listen: %s\n", strerror(errno));
-               close(s);
-               return (-WC_EXIT_BIND);
-       }
-       return (s);
-}
-
-
-/*
- * Create a Unix domain socket and listen on it
- * sockpath - file name of the unix domain socket
- * queue_len - Number of incoming connections to allow in the queue
- */
-int webcit_uds_server(char *sockpath, int queue_len) {
-       struct sockaddr_un addr;
-       int s;
-       int i;
-       int actual_queue_len;
-
-       actual_queue_len = queue_len;
-       if (actual_queue_len < 5) actual_queue_len = 5;
-
-       i = unlink(sockpath);
-       if ((i != 0) && (errno != ENOENT)) {
-               syslog(LOG_WARNING, "webcit: can't unlink %s: %s\n",
-                       sockpath, strerror(errno));
-               return (-WC_EXIT_BIND);
-       }
-
-       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) {
-               syslog(LOG_WARNING, "webcit: Can't create a unix domain socket: %s\n", strerror(errno));
-               return (-WC_EXIT_BIND);
-       }
-
-       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-               syslog(LOG_WARNING, "webcit: Can't bind: %s\n", strerror(errno));
-               close(s);
-               return (-WC_EXIT_BIND);
-       }
-
-       if (listen(s, actual_queue_len) < 0) {
-               syslog(LOG_WARNING, "webcit: Can't listen: %s\n", strerror(errno));
-               close(s);
-               return (-WC_EXIT_BIND);
-       }
-
-       chmod(sockpath, 0777);
-       return(s);
-}
-
-
-/*
- * Read data from the client socket.
- *
- * sock                socket fd to read from
- * buf         buffer to read into 
- * bytes       number of bytes to read
- * timeout     Number of seconds to wait before timing out
- *
- * Possible return values:
- *      1       Requested number of bytes has been read.
- *      0       Request timed out.
- *     -1      Connection is broken, or other error.
- */
-int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout) {
-       const char *Error;
-       int retval = 0;
-
-#ifdef HAVE_OPENSSL
-       if (is_https) {
-               long bufremain = 0;
-               long baselen;
-
-               baselen = StrLength(Target);
-
-               if (Hdr->Pos == NULL) {
-                       Hdr->Pos = ChrPtr(Hdr->ReadBuf);
-               }
-
-               if (StrLength(Hdr->ReadBuf) > 0) {
-                       bufremain = StrLength(Hdr->ReadBuf) - (Hdr->Pos - ChrPtr(Hdr->ReadBuf));
-                       
-                       if (bytes < bufremain)
-                               bufremain = bytes;
-                       StrBufAppendBufPlain(Target, Hdr->Pos, bufremain, 0);
-                       StrBufCutLeft(Hdr->ReadBuf, bufremain);
-               }
-
-               if (bytes > bufremain) {
-                       while ((StrLength(Hdr->ReadBuf) + StrLength(Target) < bytes + baselen) &&
-                              (retval >= 0))
-                               retval = client_read_sslbuffer(Hdr->ReadBuf, timeout);
-                       if (retval >= 0) {
-                               StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */
-                               return 1;
-                       }
-                       else {
-                               syslog(LOG_INFO, "client_read_ssl() failed\n");
-                               return -1;
-                       }
-               }
-               else 
-                       return 1;
-       }
-#endif
-       retval = StrBufReadBLOBBuffered(Target, 
-                                       Hdr->ReadBuf, 
-                                       &Hdr->Pos, 
-                                       &Hdr->http_sock, 
-                                       1, 
-                                       bytes,
-                                       O_TERM,
-                                       &Error);
-       if (retval < 0) {
-               syslog(LOG_INFO, "client_read() failed: %s\n", Error);
-               wc_backtrace(LOG_DEBUG);
-               return retval;
-       }
-
-       return 1;
-}
-
-
-/*
- * Begin buffering HTTP output so we can transmit it all in one write operation later.
- */
-void begin_burst(void)
-{
-       if (WC->WBuf == NULL) {
-               WC->WBuf = NewStrBufPlain(NULL, 32768);
-       }
-}
-
-
-/*
- * Finish buffering HTTP output.  [Compress using zlib and] output with a Content-Length: header.
- */
-long end_burst(void)
-{
-        const char *ptr, *eptr;
-        long count;
-       ssize_t res = 0;
-        fd_set wset;
-        int fdflags;
-
-       if (!DisableGzip && (WC->Hdr->HR.gzip_ok))
-       {
-               if (CompressBuffer(WC->WBuf) > 0)
-                       hprintf("Content-encoding: gzip\r\n");
-               else {
-                       syslog(LOG_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno));
-                       wc_backtrace(LOG_INFO);
-               }
-       }
-
-       if (WC->WFBuf != NULL) {
-               WildFireSerializePayload(WC->WFBuf, WC->HBuf, &WC->Hdr->nWildfireHeaders, NULL);
-               FreeStrBuf(&WC->WFBuf);
-       }
-
-       if (WC->Hdr->HR.prohibit_caching)
-               hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
-       hprintf("Content-length: %d\r\n\r\n", StrLength(WC->WBuf));
-
-       ptr = ChrPtr(WC->HBuf);
-       count = StrLength(WC->HBuf);
-       eptr = ptr + count;
-
-#ifdef HAVE_OPENSSL
-       if (is_https) {
-               client_write_ssl(WC->HBuf);
-               client_write_ssl(WC->WBuf);
-               return (count);
-       }
-#endif
-
-       if (WC->Hdr->http_sock == -1) {
-               return -1;
-       }
-       fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
-
-       while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
-                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
-                        FD_ZERO(&wset);
-                        FD_SET(WC->Hdr->http_sock, &wset);
-                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
-                                syslog(LOG_DEBUG, "client_write: Socket select failed (%s)\n", strerror(errno));
-                                return -1;
-                        }
-                }
-
-                if ((WC->Hdr->http_sock == -1) || 
-                   (res = write(WC->Hdr->http_sock, 
-                                ptr,
-                                count)) == -1) {
-                        syslog(LOG_DEBUG, "client_write: Socket write failed (%s)\n", strerror(errno));
-                       wc_backtrace(LOG_INFO);
-                        return res;
-                }
-                count -= res;
-               ptr += res;
-        }
-
-       ptr = ChrPtr(WC->WBuf);
-       count = StrLength(WC->WBuf);
-       eptr = ptr + count;
-
-        while ((ptr < eptr) && (WC->Hdr->http_sock != -1)) {
-                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
-                        FD_ZERO(&wset);
-                        FD_SET(WC->Hdr->http_sock, &wset);
-                        if (select(WC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
-                                syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno));
-                                return -1;
-                        }
-                }
-
-                if ((WC->Hdr->http_sock == -1) || 
-                   (res = write(WC->Hdr->http_sock, 
-                                ptr,
-                                count)) == -1) {
-                        syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno));
-                       wc_backtrace(LOG_INFO);
-                        return res;
-                }
-                count -= res;
-               ptr += res;
-        }
-
-       return StrLength(WC->WBuf);
-}
-
-
-/*
- * lingering_close() a`la Apache. see
- * http://httpd.apache.org/docs/2.0/misc/fin_wait_2.html for rationale
- */
-int lingering_close(int fd)
-{
-       char buf[SIZ];
-       int i;
-       fd_set set;
-       struct timeval tv, start;
-
-       gettimeofday(&start, NULL);
-       if (fd == -1)
-               return -1;
-       shutdown(fd, 1);
-       do {
-               do {
-                       gettimeofday(&tv, NULL);
-                       tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
-                       tv.tv_usec = start.tv_usec - tv.tv_usec;
-                       if (tv.tv_usec < 0) {
-                               tv.tv_sec--;
-                               tv.tv_usec += 1000000;
-                       }
-                       FD_ZERO(&set);
-                       FD_SET(fd, &set);
-                       i = select(fd + 1, &set, NULL, NULL, &tv);
-               } while (i == -1 && errno == EINTR);
-
-               if (i <= 0)
-                       break;
-
-               i = read(fd, buf, sizeof buf);
-       } while (i != 0 && (i != -1 || errno == EINTR));
-
-       return close(fd);
-}
-
-void
-HttpNewModule_TCPSOCKETS
-(ParsedHttpHdrs *httpreq)
-{
-
-       httpreq->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
-}
-
-void
-HttpDetachModule_TCPSOCKETS
-(ParsedHttpHdrs *httpreq)
-{
-
-       FlushStrBuf(httpreq->ReadBuf);
-       ReAdjustEmptyBuf(httpreq->ReadBuf, 4 * SIZ, SIZ);
-}
-
-void
-HttpDestroyModule_TCPSOCKETS
-(ParsedHttpHdrs *httpreq)
-{
-
-       FreeStrBuf(&httpreq->ReadBuf);
-}
-
-
-void
-SessionNewModule_TCPSOCKETS
-(wcsession *sess)
-{
-       sess->CLineBuf = NewStrBuf();
-       sess->MigrateReadLineBuf = NewStrBuf();
-}
-
-void 
-SessionDestroyModule_TCPSOCKETS
-(wcsession *sess)
-{
-       FreeStrBuf(&sess->CLineBuf);
-       FreeStrBuf(&sess->ReadBuf);
-       sess->connected = 0;
-       sess->ReadPos = NULL;
-       FreeStrBuf(&sess->MigrateReadLineBuf);
-       if (sess->serv_sock > 0) {
-               syslog(LOG_DEBUG, "Closing socket %d", sess->serv_sock);
-               close(sess->serv_sock);
-       }
-       sess->serv_sock = -1;
-}
diff --git a/webcit/tcp_sockets.h b/webcit/tcp_sockets.h
deleted file mode 100644 (file)
index cb4987c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 1996-2013 by the citadel.org team
- *
- * This program is open source software.  You can redistribute it and/or
- * modify it under the terms of the GNU General Public License, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-int uds_connectsock(char *);
-int tcp_connectsock(char *, char *);
-int serv_getln(char *strbuf, int bufsize);
-int StrBuf_ServGetln(StrBuf *buf);
-
-/*
- * parse & check the server reply 
- *
- * Line                the line containing the server reply
- * FullState   if you need more than just the major number, this is returns it. Ignored if NULL.
- * PutImportantMessage if you want to forward the text part of the server reply to the user, specify 1; 
- *             the result will be put into the 'Important Message' framework.
- * MajorOK     in case of which major number not to put the ImportantMessage? 0 for all.
- *
- * returns the most significant digit of the server status
- */
-
-int GetServerStatusMsg(StrBuf *Line, long* FullState, int PutImportantMessage, int MajorOK);
-
-/*
- * to migrate old calls.... 
- */
-#define GetServerStatus(a, b) GetServerStatusMsg(a, b, 0, 0)
-
-int serv_puts(const char *string);
-
-int serv_write(const char *buf, int nbytes);
-int serv_putbuf(const StrBuf *string);
-int serv_printf(const char *format,...)__attribute__((__format__(__printf__,1,2)));
-int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf);
-void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime);
-int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize);
-int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize);
-int read_server_text(StrBuf *Buf, long *nLines);
-
-void text_to_server(char *ptr);
-void text_to_server_qp(const StrBuf *SendMeEncoded);
-void server_to_text(void);
-int lingering_close(int fd);
index f625e1da1798074c7b6595054839780cae861107..955458e2aec7319bcf2851fb1e79cc5a6c7d0d87 100644 (file)
@@ -87,7 +87,7 @@ typedef struct wcsession wcsession;
 #include "roomops.h"
 #include "preferences.h"
 
-#include "tcp_sockets.h"
+#include "sockets.h"
 #include "utils.h"
 #ifdef HAVE_OPENSSL
 /* Work around RedHat's b0rken OpenSSL includes */
@@ -122,20 +122,19 @@ extern char *ssl_cipher_list;
 #undef memcpy
 #endif
 
-#define SLEEPING               180             /* TCP connection timeout */
-#define WEBCIT_TIMEOUT         900             /* WebCit session timeout */
-#define PORT_NUM               80              /* port number to listen on */
+#define SLEEPING               180                     /* TCP connection timeout */
+#define WEBCIT_TIMEOUT         900                     /* WebCit session timeout */
+#define PORT_NUM               80                      /* port number to listen on */
 #define DEVELOPER_ID           0
 #define CLIENT_ID              4
 #define CLIENT_VERSION 941             /* This version of WebCit */
-#define MINIMUM_CIT_VERSION    931             /* Minimum required version of Citadel server */
-#define        LIBCITADEL_MIN          931             /* Minimum required version of libcitadel */
-#define DEFAULT_HOST           "localhost"     /* Default Citadel server */
-#define DEFAULT_PORT           "504"
-#define TARGET                 "webcit01"      /* Window target for inline URL's */
-#define HOUSEKEEPING           15              /* Housekeeping frequency */
+#define MINIMUM_CIT_VERSION    931                     /* Minimum required version of Citadel server */
+#define        LIBCITADEL_MIN          931                     /* Minimum required version of libcitadel */
+#define DEFAULT_CTDLDIR                "/usr/local/citadel"    /* Default Citadel server directory */
+#define TARGET                 "webcit01"              /* Window target for inline URL's */
+#define HOUSEKEEPING           15                      /* Housekeeping frequency */
 #define MAX_WORKER_THREADS     250
-#define LISTEN_QUEUE_LENGTH    100             /* listen() backlog queue */
+#define LISTEN_QUEUE_LENGTH    100                     /* listen() backlog queue */
 
 #define USERCONFIGROOM         "My Citadel Config"
 #define DEFAULT_MAXMSGS                20
@@ -528,10 +527,6 @@ extern pthread_key_t MyConKey;
 #ifdef HAVE_OPENSSL
 #define THREADSSL ((SSL *)pthread_getspecific(ThreadSSL))
 extern pthread_key_t ThreadSSL;
-extern char ctdl_key_dir[PATH_MAX];
-extern char file_crpt_file_key[PATH_MAX];
-extern char file_crpt_file_csr[PATH_MAX];
-extern char file_crpt_file_cer[PATH_MAX];
 
 void init_ssl(void);
 void endtls(void);
@@ -544,7 +539,6 @@ int client_write_ssl(const StrBuf *Buf);
 extern int is_https;
 extern int follow_xff;
 extern char *server_cookie;
-extern char *ctdlhost, *ctdlport;
 extern char *axdefs[];
 extern int num_threads_existing;
 extern int num_threads_executing;
@@ -655,3 +649,4 @@ void display_summary_page(void);
 HashList *GetValidDomainNames(StrBuf *Target, WCTemplputParams *TP);
 void output_error_pic(const char *ErrMsg1, const char *ErrMsg2);
 void jsonMessageListHdr(void);
+extern char *ctdl_dir;                         /* Directory where Citadel Server is running */
index 411e06e3a4b7257c4b20492c2cbc6025c823a15d..8f7a9c9081f81ad705507d1c9b50bf4550b25248 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 1996-2021 by the citadel.org team
+// Copyright (c) 1996-2022 by the citadel.org team
 //
 // This program is open source software.  You can redistribute it and/or
 // modify it under the terms of the GNU General Public License version 3.
@@ -30,12 +30,11 @@ extern void webcit_calc_dirs_n_files(int relh, const char *basedir, int home, ch
 extern void worker_entry(void);
 extern void drop_root(uid_t UID);
 
-char socket_dir[PATH_MAX];     /* where to talk to our citadel server */
-char *server_cookie = NULL;    /* our Cookie connection to the client */
-int http_port = PORT_NUM;      /* Port to listen on */
-char *ctdlhost = DEFAULT_HOST; /* Host name or IP address of Citadel server */
-char *ctdlport = DEFAULT_PORT; /* Port number of Citadel server */
-int running_as_daemon = 0;     /* should we deamonize on startup? */
+char socket_dir[PATH_MAX];             /* where to talk to our citadel server */
+char *server_cookie = NULL;            /* our Cookie connection to the client */
+int http_port = PORT_NUM;              /* Port to listen on */
+int running_as_daemon = 0;             /* should we deamonize on startup? */
+char *ctdl_dir = DEFAULT_CTDLDIR;      /* Directory where Citadel Server is running */
 
 /* #define DBG_PRINNT_HOOKS_AT_START */
 #ifdef DBG_PRINNT_HOOKS_AT_START
@@ -109,7 +108,6 @@ int main(int argc, char **argv) {
                        else {
                                safestrncpy(relhome, relhome, sizeof relhome);
                        }
-                       /* free(hdir); TODO: SHOULD WE DO THIS? */
                        home=1;
                        break;
                case 'd':
@@ -189,7 +187,7 @@ int main(int argc, char **argv) {
 #ifdef HAVE_OPENSSL
                                "[-s] [-S cipher_suites]"
 #endif
-                               "[remotehost [remoteport]]\n");
+                               "[citadel_server_directory]\n");
                        return 1;
                }
 
@@ -200,10 +198,9 @@ int main(int argc, char **argv) {
                LOG_DAEMON
        );
 
-       if (optind < argc) {
-               ctdlhost = argv[optind];
-               if (++optind < argc)
-                       ctdlport = argv[optind];
+       while (optind < argc) {
+               ctdl_dir = strdup(argv[optind]);
+               ++optind;
        }
 
        /* daemonize, if we were asked to */
@@ -221,7 +218,7 @@ int main(int argc, char **argv) {
 
        /* Tell 'em who's in da house */
        syslog(LOG_NOTICE, "%s", PACKAGE_STRING);
-       syslog(LOG_NOTICE, "Copyright (C) 1996-2020 by the citadel.org team");
+       syslog(LOG_NOTICE, "Copyright (C) 1996-2022 by the citadel.org team");
        syslog(LOG_NOTICE, " ");
        syslog(LOG_NOTICE, "This program is open source software: you can redistribute it and/or");
        syslog(LOG_NOTICE, "modify it under the terms of the GNU General Public License, version 3.");
@@ -321,16 +318,12 @@ int main(int argc, char **argv) {
 
        pthread_mutex_init(&SessionListMutex, NULL);
 
-       /*
-        * Start up the housekeeping thread
-        */
+       // Start up the housekeeping thread
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        pthread_create(&SessThread, &attr, (void *(*)(void *)) housekeeping_loop, NULL);
 
-       /*
-        * If this is an HTTPS server, fire up SSL
-        */
+       // If this is an HTTPS server, fire up SSL
 #ifdef HAVE_OPENSSL
        if (is_https) {
                init_ssl();
@@ -338,7 +331,7 @@ int main(int argc, char **argv) {
 #endif
        drop_root(UID);
 
-       /* Become a worker thread.  More worker threads will be spawned as they are needed. */
+       // Become a worker thread.  More worker threads will be spawned as they are needed.
        worker_entry();
        ShutDownLibCitadel();
        return 0;