-Copyright: (C) 1987-2021 Citadel development team; GPL V3
+Copyright: (C) 1987-2022 Citadel development team; GPL V3
* In addition, as a special exception, we hereby declare that our
favorite type of software is called "open source" -- NOT "free
-// Copyright (c) 1987-2021 by the citadel.org team
+// Copyright (c) 1987-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.
// Check the modification time of the key and certificate -- reload if they changed
void update_key_and_cert_if_needed(void) {
- static time_t cert_mtime = 0;
+ static time_t previous_mtime = 0;
struct stat keystat;
struct stat certstat;
return;
}
- if ((keystat.st_mtime > cert_mtime) || (certstat.st_mtime > cert_mtime)) {
+ if ((keystat.st_mtime + certstat.st_mtime) != previous_mtime) {
bind_to_key_and_certificate();
- cert_mtime = certstat.st_mtime;
+ previous_mtime = keystat.st_mtime + certstat.st_mtime;
}
}
}
}
- /* All compares succeeded: we have a match! */
+ // All compares succeeded: we have a match!
return 0;
}
is_set = malloc(num_msgs * sizeof(char));
memset(is_set, 0, (num_msgs * sizeof(char)) );
- /* Decide which message set we're manipulating */
+ // Decide which message set we're manipulating
switch(which_set) {
case ctdlsetseen_seen:
vset = NewStrBufPlain(vbuf.v_seen, -1);
need_to_free_re = 1;
}
- /* Learn about the user and room in question */
+ // Learn about the user and room in question
if (server_shutting_down) {
if (need_to_free_re) regfree(&re);
return -1;
return -1;
}
- /* Load the message list */
+ // Load the message list
cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
if (cdbfr == NULL) {
if (need_to_free_re) regfree(&re);
- return 0; /* No messages at all? No further action. */
+ return 0; // No messages at all? No further action.
}
msglist = (long *) cdbfr->ptr;
num_msgs = cdbfr->len / sizeof(long);
- cdbfr->ptr = NULL; /* clear this so that cdb_free() doesn't free it */
- cdb_free(cdbfr); /* we own this memory now */
+ cdbfr->ptr = NULL; // clear this so that cdb_free() doesn't free it
+ cdb_free(cdbfr); // we own this memory now
/*
* Now begin the traversal.
is_seen = 0;
}
else {
- is_seen = is_msg_in_sequence_set(
- vbuf.v_seen, thismsg);
+ is_seen = is_msg_in_sequence_set(vbuf.v_seen, thismsg);
if (is_seen) lastold = thismsg;
}
- if ((thismsg > 0L)
- && (
-
- (mode == MSGS_ALL)
- || ((mode == MSGS_OLD) && (is_seen))
- || ((mode == MSGS_NEW) && (!is_seen))
- || ((mode == MSGS_LAST) && (a >= (num_msgs - ref)))
- || ((mode == MSGS_FIRST) && (a < ref))
+ if (
+ (thismsg > 0L)
+ && (
+ (mode == MSGS_ALL)
+ || ((mode == MSGS_OLD) && (is_seen))
+ || ((mode == MSGS_NEW) && (!is_seen))
+ || ((mode == MSGS_LAST) && (a >= (num_msgs - ref)))
+ || ((mode == MSGS_FIRST) && (a < ref))
|| ((mode == MSGS_GT) && (thismsg > ref))
|| ((mode == MSGS_LT) && (thismsg < ref))
|| ((mode == MSGS_EQ) && (thismsg == ref))
// Inline callback function for mime parser that wants to display text
-//
void fixed_output(char *name, char *filename, char *partnum, char *disp,
void *content, char *cbtype, char *cbcharset, size_t length,
char *encoding, char *cbid, void *cbuserdata)
// If we're in the middle of a multipart/alternative scope and
// we've already printed another section, skip this one.
- //
if ( (ma->is_ma) && (ma->did_print) ) {
syslog(LOG_DEBUG, "msgbase: skipping part %s (%s)", partnum, cbtype);
return;
// and then set ma->chosen_pref to that MIME type's position in our preference
// list. If we then hit another match, we only replace the first match if
// the preference value is lower.
-//
void choose_preferred(char *name, char *filename, char *partnum, char *disp,
void *content, char *cbtype, char *cbcharset, size_t length,
char *encoding, char *cbid, void *cbuserdata)
// Now that we've chosen our preferred part, output it.
-//
void output_preferred(char *name,
char *filename,
char *partnum,
}
-/*
- * Check whether the current user has permission to delete messages from
- * the current room (returns 1 for yes, 0 for no)
- */
+// Check whether the current user has permission to delete messages from
+// the current room (returns 1 for yes, 0 for no)
int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
int ra;
CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
}
-/*
- * Retrieve access control information for any user/room pair.
- * Yes, it has a couple of gotos. If you don't like that, go die in a car fire.
- */
+// Retrieve access control information for any user/room pair.
+// Yes, it has a couple of gotos. If you don't like that, go die in a car fire.
void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf, int *result, int *view) {
int retval = 0;
visit vbuf;
is_guest = 1;
}
- /* for internal programs, always do everything */
+ // for internal programs, always do everything
if (((CC->internal_pgm)) && (roombuf->QRflags & QR_INUSE)) {
retval = (UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED);
vbuf.v_view = 0;
goto SKIP_EVERYTHING;
}
- /* If guest mode is enabled, always grant access to the Lobby */
+ // If guest mode is enabled, always grant access to the Lobby
if ((is_guest) && (!strcasecmp(roombuf->QRname, BASEROOM))) {
retval = (UA_KNOWN | UA_GOTOALLOWED);
vbuf.v_view = 0;
goto SKIP_EVERYTHING;
}
- /* Locate any applicable user/room relationships */
+ // Locate any applicable user/room relationships
if (is_guest) {
memset(&vbuf, 0, sizeof vbuf);
}
CtdlGetRelationship(&vbuf, userbuf, roombuf);
}
- /* Force the properties of the Aide room */
+ // Force the properties of the Aide room
if (!strcasecmp(roombuf->QRname, CtdlGetConfigStr("c_aideroom"))) {
if (userbuf->axlevel >= AxAideU) {
retval = UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED;
goto NEWMSG;
}
- /* If this is a public room, it's accessible... */
+ // If this is a public room, it's accessible...
if ( ((roombuf->QRflags & QR_PRIVATE) == 0)
&& ((roombuf->QRflags & QR_MAILBOX) == 0)
) {
retval = retval | UA_KNOWN | UA_GOTOALLOWED;
}
- /* If this is a preferred users only room, check access level */
+ // If this is a preferred users only room, check access level
if (roombuf->QRflags & QR_PREFONLY) {
if (userbuf->axlevel < AxPrefU) {
retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED;
}
}
- /* For private rooms, check the generation number matchups */
+ // For private rooms, check the generation number matchups
if ( (roombuf->QRflags & QR_PRIVATE)
&& ((roombuf->QRflags & QR_MAILBOX) == 0)
) {
- /* An explicit match means the user belongs in this room */
+ // An explicit match means the user belongs in this room
if (vbuf.v_flags & V_ACCESS) {
retval = retval | UA_KNOWN | UA_GOTOALLOWED;
}
- /* Otherwise, check if this is a guess-name or passworded
- * room. If it is, a goto may at least be attempted
- */
+ // Otherwise, check if this is a guess-name or passworded
+ // room. If it is, a goto may at least be attempted
else if ( (roombuf->QRflags & QR_PRIVATE)
|| (roombuf->QRflags & QR_PASSWORDED)
) {
}
}
- /* For mailbox rooms, also check the namespace */
- /* Also, mailbox owners can delete their messages */
+ // For mailbox rooms, also check the namespace. Also, mailbox owners can delete their messages
if ( (roombuf->QRflags & QR_MAILBOX) && (atol(roombuf->QRname) != 0)) {
if (userbuf->usernum == atol(roombuf->QRname)) {
retval = retval | UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED;
}
- /* An explicit match means the user belongs in this room */
+ // An explicit match means the user belongs in this room
if (vbuf.v_flags & V_ACCESS) {
retval = retval | UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED;
}
}
- /* For non-mailbox rooms... */
+ // For non-mailbox rooms...
else {
// User is allowed to post in the room unless:
// - User is not validated
}
- /* Check to see if the user has forgotten this room */
+ // Check to see if the user has forgotten this room
if (vbuf.v_flags & V_FORGET) {
retval = retval & ~UA_KNOWN;
if ( ( ((roombuf->QRflags & QR_PRIVATE) == 0)
}
}
- /* If user is explicitly locked out of this room, deny everything */
+ // If user is explicitly locked out of this room, deny everything
if (vbuf.v_flags & V_LOCKOUT) {
retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED & ~UA_POSTALLOWED & ~UA_REPLYALLOWED;
}
- /* Aides get access to all private rooms */
+ // Aides get access to all private rooms
if ( (userbuf->axlevel >= AxAideU)
&& ((roombuf->QRflags & QR_MAILBOX) == 0)
) {
retval = retval | UA_ADMINALLOWED | UA_DELETEALLOWED | UA_POSTALLOWED | UA_REPLYALLOWED;
}
-NEWMSG: /* By the way, we also check for the presence of new messages */
+NEWMSG: // By the way, we also check for the presence of new messages
if (is_msg_in_sequence_set(vbuf.v_seen, roombuf->QRhighest) == 0) {
retval = retval | UA_HASNEWMSGS;
}
- /* System rooms never show up in the list. */
+ // System rooms never show up in the list.
if (roombuf->QRflags2 & QR2_SYSTEM) {
retval = retval & ~UA_KNOWN;
}
SKIP_EVERYTHING:
- /* Now give the caller the information it wants. */
+ // Now give the caller the information it wants.
if (result != NULL) *result = retval;
if (view != NULL) *view = vbuf.v_view;
}
-/*
- * Self-checking stuff for a room record read into memory
- */
+// Self-checking stuff for a room record read into memory
void room_sanity_check(struct ctdlroom *qrbuf) {
- /* Mailbox rooms are always on the lowest floor */
+ // Mailbox rooms are always on the lowest floor
if (qrbuf->QRflags & QR_MAILBOX) {
qrbuf->QRfloor = 0;
}
- /* Listing order of 0 is illegal except for base rooms */
+ // Listing order of 0 is illegal except for base rooms
if (qrbuf->QRorder == 0) {
if ( !(qrbuf->QRflags & QR_MAILBOX)
&& strncasecmp(qrbuf->QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)
}
-/*
- * CtdlGetRoom() - retrieve room data from disk
- */
+// CtdlGetRoom() - retrieve room data from disk
int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name) {
struct cdbdata *cdbqr;
char lowercase_name[ROOMNAMELEN];
return(1); // empty room name , not valid
}
- /* First, try the public namespace */
+ // First, try the public namespace
cdbqr = cdb_fetch(CDB_ROOMS, lowercase_name, strlen(lowercase_name));
- /* If that didn't work, try the user's personal namespace */
+ // If that didn't work, try the user's personal namespace
if (cdbqr == NULL) {
snprintf(personal_lowercase_name, sizeof personal_lowercase_name, "%010ld.%s", CC->user.usernum, lowercase_name);
cdbqr = cdb_fetch(CDB_ROOMS, personal_lowercase_name, strlen(personal_lowercase_name));
}
-/*
- * CtdlGetRoomLock() - same as getroom() but locks the record (if supported)
- */
+// CtdlGetRoomLock() - same as getroom() but locks the record (if supported)
int CtdlGetRoomLock(struct ctdlroom *qrbuf, const char *room_name) {
register int retval;
retval = CtdlGetRoom(qrbuf, room_name);
}
-/*
- * b_putroom() - back end to putroom() and b_deleteroom()
- * (if the supplied buffer is NULL, delete the room record)
- */
-void b_putroom(struct ctdlroom *qrbuf, char *room_name)
-{
+// b_putroom() - back end to putroom() and b_deleteroom()
+// (if the supplied buffer is NULL, delete the room record)
+void b_putroom(struct ctdlroom *qrbuf, char *room_name) {
char lowercase_name[ROOMNAMELEN];
char *aptr, *bptr;
long len;
}
-/*
- * CtdlPutRoom() - store room data to disk
- */
+// CtdlPutRoom() - store room data to disk
void CtdlPutRoom(struct ctdlroom *qrbuf) {
b_putroom(qrbuf, qrbuf->QRname);
}
-/*
- * b_deleteroom() - delete a room record from disk
- */
+// b_deleteroom() - delete a room record from disk
void b_deleteroom(char *room_name) {
b_putroom(NULL, room_name);
}
-/*
- * CtdlPutRoomLock() - same as CtdlPutRoom() but unlocks the record (if supported)
- */
+// CtdlPutRoomLock() - same as CtdlPutRoom() but unlocks the record (if supported)
void CtdlPutRoomLock(struct ctdlroom *qrbuf) {
CtdlPutRoom(qrbuf);
end_critical_section(S_ROOMS);
}
-/*
- * CtdlGetFloorByName() - retrieve the number of the named floor
- * return < 0 if not found else return floor number
- */
+// CtdlGetFloorByName() - retrieve the number of the named floor
+// return < 0 if not found else return floor number
int CtdlGetFloorByName(const char *floor_name) {
int a;
struct floor *flbuf = NULL;
for (a = 0; a < MAXFLOORS; ++a) {
flbuf = CtdlGetCachedFloor(a);
- /* check to see if it already exists */
+ // check to see if it already exists
if ((!strcasecmp(flbuf->f_name, floor_name)) && (flbuf->f_flags & F_INUSE)) {
return a;
}
}
-/*
- * CtdlGetFloorByNameLock() - retrieve floor number for given floor and lock the floor list.
- */
-int CtdlGetFloorByNameLock(const char *floor_name)
-{
+// CtdlGetFloorByNameLock() - retrieve floor number for given floor and lock the floor list.
+int CtdlGetFloorByNameLock(const char *floor_name) {
begin_critical_section(S_FLOORTAB);
return CtdlGetFloorByName(floor_name);
}
// citserver's main() function lives here.
//
-// Copyright (c) 1987-2021 by the citadel.org team
+// Copyright (c) 1987-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.
int sanity_diag_mode = 0;
-/*
- * Create or remove a lock file, so we only have one Citadel Server running at a time.
- * Set 'op' to nonzero to lock, zero to unlock.
- */
+// Create or remove a lock file, so we only have one Citadel Server running at a time.
+// Set 'op' to nonzero to lock, zero to unlock.
void ctdl_lockfile(int op) {
static char lockfilename[PATH_MAX];
static FILE *fp;
}
-/*
- * Here's where it all begins.
- */
+// Here's where it all begins.
int main(int argc, char **argv) {
char facility[32];
struct stat filestats;
#endif
- /* Tell 'em who's in da house */
+ // Tell 'em who's in da house
syslog(LOG_INFO, " ");
syslog(LOG_INFO, " ");
syslog(LOG_INFO, "*** Citadel server engine ***\n");
syslog(LOG_INFO, "Version %d (build %s) ***", REV_LEVEL, svn_revision());
- syslog(LOG_INFO, "Copyright (C) 1987-2021 by the Citadel development team.");
+ syslog(LOG_INFO, "Copyright (C) 1987-2022 by the Citadel development team.");
syslog(LOG_INFO, " ");
syslog(LOG_INFO, "This program is open source software: you can redistribute it and/or");
syslog(LOG_INFO, "modify it under the terms of the GNU General Public License, version 3.");
syslog(LOG_INFO, " ");
syslog(LOG_INFO, "%s", libcitadel_version_string());
- /* parse command-line arguments */
+ // parse command-line arguments
while ((a=getopt(argc, argv, "cl:dh:x:t:B:Dru:s:")) != EOF) switch(a) {
// test this binary for compatibility and exit
exit(CTDLEXIT_UNUSER);
}
- /* Last ditch effort to determine the user name ... if there's a user called "citadel" then use that */
+ // Last ditch effort to determine the user name ... if there's a user called "citadel" then use that
if (ctdluid == 0) {
p = getpwnam("citadel");
if (!p) {
}
}
- /* initialize the master context */
+ // initialize the master context
InitializeMasterCC();
InitializeMasterTSD();
syslog_facility
);
- /* daemonize, if we were asked to */
+ // daemonize, if we were asked to
if (running_as_daemon) {
start_daemon(0);
drop_root_perms = 1;
syslog(LOG_INFO, "main: upgrading modules"); // Run any upgrade entry points
upgrade_modules();
- /*
- * Load the user for the masterCC or create them if they don't exist
- */
+ // Load the user for the masterCC or create them if they don't exist
if (CtdlGetUser(&masterCC.user, "SYS_Citadel")) {
- /* User doesn't exist. We can't use create user here as the user number needs to be 0 */
+ // User doesn't exist. We can't use create user here as the user number needs to be 0
strcpy (masterCC.user.fullname, "SYS_Citadel") ;
CtdlPutUser(&masterCC.user);
- CtdlGetUser(&masterCC.user, "SYS_Citadel"); /* Just to be safe */
+ CtdlGetUser(&masterCC.user, "SYS_Citadel"); // Just to be safe
}
- /*
- * Bind the server to a Unix-domain socket (user client access)
- */
+ // Bind the server to a Unix-domain socket (user client access)
CtdlRegisterServiceHook(0,
file_citadel_socket,
citproto_begin_session,
do_async_loop,
CitadelServiceUDS);
- /*
- * Bind the server to a Unix-domain socket (admin client access)
- */
+ // Bind the server to a Unix-domain socket (admin client access)
CtdlRegisterServiceHook(0,
file_citadel_admin_socket,
citproto_begin_admin_session,
do_command_loop,
do_async_loop,
CitadelServiceUDS);
- chmod(file_citadel_admin_socket, S_IRWXU); /* for your eyes only */
+ chmod(file_citadel_admin_socket, S_IRWXU); // for your eyes only
- /*
- * Bind the server to our favorite TCP port (usually 504).
- */
+ // Bind the server to our favorite TCP port (usually 504).
CtdlRegisterServiceHook(CtdlGetConfigInt("c_port_number"),
NULL,
citproto_begin_session,
do_async_loop,
CitadelServiceTCP);
- /*
- * Load any server-side extensions available here.
- */
+ // Load any server-side extensions available here.
syslog(LOG_INFO, "main: initializing server extensions");
initialise_modules(0);
- /*
- * If we need host auth, start our chkpwd daemon.
- */
+ // If we need host auth, start our chkpwd daemon.
if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) {
start_chkpwd_daemon();
}
- /*
- * check, whether we're fired up another time after a crash.
- * if, post an aide message, so the admin has a chance to react.
- */
+ // check, whether we're fired up another time after a crash.
+ // if, post an aide message, so the admin has a chance to react.
checkcrash();
- /*
- * Now that we've bound the sockets, change to the Citadel user id and its corresponding group ids
- */
+ // Now that we've bound the sockets, change to the Citadel user id and its corresponding group ids
if (drop_root_perms) {
- cdb_chmod_data(); /* make sure we own our data files */
+ cdb_chmod_data(); // make sure we own our data files
getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
if (pwp == NULL)
syslog(LOG_ERR, "main: WARNING, getpwuid(%ld): %m Group IDs will be incorrect.", (long)CTDLUID);
#endif
}
- /* We want to check for idle sessions once per minute */
+ // We want to check for idle sessions once per minute
CtdlRegisterSessionHook(terminate_idle_sessions, EVT_TIMER, PRIO_CLEANUP + 1);
- /* Go into multithreaded mode. When this call exits, the server is stopping. */
+ // Go into multithreaded mode. When this call exits, the server is stopping.
go_threading();
- /* Get ready to shut down the server. */
+ // Get ready to shut down the server.
int exit_code = master_cleanup(exit_signal);
ctdl_lockfile(0);
if (restart_server) {
-/*
- * Server-side utility functions
- */
+// Server-side utility functions
#include "sysdep.h"
#include <stdio.h>
#include "citadel.h"
#include "support.h"
-/*
- * strproc() - make a string 'nice'
- */
-void strproc(char *string)
-{
+// strproc() - make a string 'nice'
+void strproc(char *string) {
int a, b;
if (string == NULL) return;
if (IsEmptyStr(string)) return;
- /* Convert non-printable characters to blanks */
+ // Convert non-printable characters to blanks
for (a=0; !IsEmptyStr(&string[a]); ++a) {
if (string[a]<32) string[a]=32;
if (string[a]>126) string[a]=32;
}
- /* a is now the length of our string. */
- /* Remove leading and trailing blanks */
+ // a is now the length of our string.
+ // Remove leading and trailing blanks
while( (string[a-1]<33) && (!IsEmptyStr(string)) )
string[--a]=0;
b = 0;
if (b > 0)
memmove(string,&string[b], a - b + 1);
- /* Remove double blanks */
+ // Remove double blanks
for (a=0; !IsEmptyStr(&string[a]); ++a) {
if ((string[a]==32)&&(string[a+1]==32)) {
strcpy(&string[a],&string[a+1]);
}
}
- /* remove characters which would interfere with the network */
+ // remove characters which would interfere with the network
for (a=0; !IsEmptyStr(&string[a]); ++a) {
while (string[a]=='!') strcpy(&string[a],&string[a+1]);
while (string[a]=='@') strcpy(&string[a],&string[a+1]);
}
-
-/*
- * get a line of text from a file
- * ignores lines starting with #
- */
-int getstring(FILE *fp, char *string)
-{
+// get a line of text from a file
+// ignores lines starting with #
+int getstring(FILE *fp, char *string) {
int a,c;
do {
strcpy(string,"");
-OBJS := http.o main.o request.o ssl.o static.o tcp_sockets.o webserver.o ctdlclient.o \
+OBJS := http.o main.o request.o tls.o static.o tcp_sockets.o webserver.o ctdlclient.o \
admin_functions.o room_functions.o util.o caldav_reports.o messages.o \
ctdlfunctions.o ctdl_commands.o forum_view.o html2html.o text2html.o user_functions.o
CFLAGS := -ggdb -Wno-format-truncation
+++ /dev/null
-//
-// Functions in this module handle SSL encryption when WebCit is running
-// as an HTTPS server.
-//
-// Copyright (c) 1996-2022 by the citadel.org team
-//
-// This program is open source software. It runs great on the
-// Linux operating system (and probably elsewhere). You can use,
-// copy, and run 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.
-
-#include "webcit.h"
-
-SSL_CTX *ssl_ctx; // global SSL context
-char key_file[PATH_MAX] = "";
-char cert_file[PATH_MAX] = "";
-char *ssl_cipher_list = DEFAULT_SSL_CIPHER_LIST;
-
-
-// Set the private key and certificate chain for the global SSL Context.
-// This is called during initialization, and can be called again later if the certificate changes.
-void bind_to_key_and_certificate(void) {
- if (IsEmptyStr(key_file)) {
- snprintf(key_file, sizeof key_file, "%s/keys/citadel.key", ctdl_dir);
- }
- if (IsEmptyStr(cert_file)) {
- snprintf(cert_file, sizeof key_file, "%s/keys/citadel.cer", ctdl_dir);
- }
-
- syslog(LOG_DEBUG, "crypto: [re]installing key \"%s\" and certificate \"%s\"", key_file, cert_file);
-
- SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file);
- SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, 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()));
- }
-}
-
-
-// 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;
-
- // Initialize SSL transport layer
- SSL_library_init();
- SSL_load_error_strings();
- ssl_method = SSLv23_server_method();
- if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
- syslog(LOG_WARNING, "SSL_CTX_new failed: %s", ERR_reason_error_string(ERR_get_error()));
- return;
- }
-
- syslog(LOG_INFO, "Requesting cipher list: %s", ssl_cipher_list);
- if (!(SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list))) {
- syslog(LOG_WARNING, "SSL_CTX_set_cipher_list failed: %s", ERR_reason_error_string(ERR_get_error()));
- return;
- }
-
- // Now try to bind to the key and certificate.
- bind_to_key_and_certificate();
-}
-
-
-// Check the modification time of the key and certificate -- reload if they changed
-void update_key_and_cert_if_needed(void) {
- static time_t cert_mtime = 0;
- struct stat keystat;
- struct stat certstat;
-
- if (stat(key_file, &keystat) != 0) {
- syslog(LOG_ERR, "%s: %s", key_file, strerror(errno));
- return;
- }
- if (stat(cert_file, &certstat) != 0) {
- syslog(LOG_ERR, "%s: %s", cert_file, strerror(errno));
- return;
- }
-
- if ((keystat.st_mtime > cert_mtime) || (certstat.st_mtime > cert_mtime)) {
- bind_to_key_and_certificate();
- cert_mtime = certstat.st_mtime;
- }
-}
-
-
-// starts SSL/TLS encryption for the current session.
-void starttls(struct client_handle *ch) {
- int retval, bits, alg_bits;
-
- if (!ssl_ctx) {
- return;
- }
-
- // Check the modification time of the key and certificate -- reload if they changed
- update_key_and_cert_if_needed();
-
- if (!(ch->ssl_handle = SSL_new(ssl_ctx))) {
- syslog(LOG_WARNING, "SSL_new failed: %s", ERR_reason_error_string(ERR_get_error()));
- return;
- }
- if (!(SSL_set_fd(ch->ssl_handle, ch->sock))) {
- syslog(LOG_WARNING, "SSL_set_fd failed: %s", ERR_reason_error_string(ERR_get_error()));
- SSL_free(ch->ssl_handle);
- return;
- }
- retval = SSL_accept(ch->ssl_handle);
- if (retval < 1) {
- syslog(LOG_WARNING, "SSL_accept failed: %s", ERR_reason_error_string(ERR_get_error()));
- }
- else {
- syslog(LOG_INFO, "SSL_accept success");
- }
- bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ch->ssl_handle), &alg_bits);
- syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)",
- SSL_CIPHER_get_name(SSL_get_current_cipher(ch->ssl_handle)),
- SSL_CIPHER_get_version(SSL_get_current_cipher(ch->ssl_handle)), bits, alg_bits);
- syslog(LOG_INFO, "SSL started");
-}
-
-
-// shuts down the TLS connection
-void endtls(struct client_handle *ch) {
- syslog(LOG_INFO, "Ending SSL/TLS");
- if (ch->ssl_handle != NULL) {
- SSL_shutdown(ch->ssl_handle);
- SSL_get_SSL_CTX(ch->ssl_handle);
- SSL_free(ch->ssl_handle);
- }
- ch->ssl_handle = NULL;
-}
-
-
-// Send binary data to the client encrypted.
-int client_write_ssl(struct client_handle *ch, char *buf, int nbytes) {
- int retval;
- int nremain;
- char junk[1];
-
- if (ch->ssl_handle == NULL)
- return (-1);
-
- nremain = nbytes;
- while (nremain > 0) {
- if (SSL_want_write(ch->ssl_handle)) {
- if ((SSL_read(ch->ssl_handle, junk, 0)) < 1) {
- syslog(LOG_WARNING, "SSL_read in client_write: %s", ERR_reason_error_string(ERR_get_error()));
- }
- }
- retval = SSL_write(ch->ssl_handle, &buf[nbytes - nremain], nremain);
- if (retval < 1) {
- long errval;
-
- errval = SSL_get_error(ch->ssl_handle, retval);
- if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
- sleep(1);
- continue;
- }
- syslog(LOG_WARNING, "SSL_write: %s", ERR_reason_error_string(ERR_get_error()));
- if (retval == -1) {
- syslog(LOG_WARNING, "errno is %d", errno);
- endtls(ch);
- }
- return -1;
- }
- nremain -= retval;
- }
- return 0;
-}
-
-
-// read data from the encrypted layer
-int client_read_ssl(struct client_handle *ch, char *buf, int nbytes) {
- int bytes_read = 0;
- int rlen = 0;
- char junk[1];
-
- if (ch->ssl_handle == NULL)
- return (-1);
-
- while (bytes_read < nbytes) {
- if (SSL_want_read(ch->ssl_handle)) {
- if ((SSL_write(ch->ssl_handle, junk, 0)) < 1) {
- syslog(LOG_WARNING, "SSL_write in client_read");
- }
- }
- rlen = SSL_read(ch->ssl_handle, &buf[bytes_read], nbytes - bytes_read);
- if (rlen < 1) {
- long errval;
- errval = SSL_get_error(ch->ssl_handle, rlen);
- if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
- sleep(1);
- continue;
- }
- syslog(LOG_WARNING, "SSL_read error %ld", errval);
- endtls(ch);
- return (-1);
- }
- bytes_read += rlen;
- }
- return (bytes_read);
-}
// Display a room list in the main div.
-//
function display_room_list() {
- document.getElementById("roomlist").innerHTML = "<img src=\"/ctdl/s/static/throbber.gif\" />"; // show throbber while loading
+ document.getElementById("roomlist").innerHTML = "<img src=\"/ctdl/s/images/throbber.gif\" />"; // show throbber while loading
fetch_room_list = async() => {
response = await fetch("/ctdl/r/");
if (response.ok) {
display_room_list_renderer(room_list);
}
+ else {
+ document.getElementById("roomlist").innerHTML = "<i>error</i>";
+ }
}
fetch_room_list();
}
// Renderer for display_room_list()
-//
function display_room_list_renderer(data) {
data = data.sort(function(a,b) {
if (a.floor != b.floor) {
--- /dev/null
+// Functions in this module handle SSL encryption when WebCit is running
+// as an HTTPS server.
+//
+// Copyright (c) 1996-2022 by the citadel.org team
+//
+// This program is open source software. It runs great on the
+// Linux operating system (and probably elsewhere). You can use,
+// copy, and run 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.
+
+#include "webcit.h"
+
+SSL_CTX *ssl_ctx; // global SSL context
+char key_file[PATH_MAX] = "";
+char cert_file[PATH_MAX] = "";
+char *ssl_cipher_list = DEFAULT_SSL_CIPHER_LIST;
+
+
+// Set the private key and certificate chain for the global SSL Context.
+// This is called during initialization, and can be called again later if the certificate changes.
+void bind_to_key_and_certificate(void) {
+ if (IsEmptyStr(key_file)) {
+ snprintf(key_file, sizeof key_file, "%s/keys/citadel.key", ctdl_dir);
+ }
+ if (IsEmptyStr(cert_file)) {
+ snprintf(cert_file, sizeof key_file, "%s/keys/citadel.cer", ctdl_dir);
+ }
+
+ syslog(LOG_DEBUG, "crypto: [re]installing key \"%s\" and certificate \"%s\"", key_file, cert_file);
+
+ SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file);
+ SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, 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()));
+ }
+}
+
+
+// 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;
+
+ // Initialize SSL transport layer
+ SSL_library_init();
+ SSL_load_error_strings();
+ ssl_method = SSLv23_server_method();
+ if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
+ syslog(LOG_WARNING, "SSL_CTX_new failed: %s", ERR_reason_error_string(ERR_get_error()));
+ return;
+ }
+
+ syslog(LOG_INFO, "Requesting cipher list: %s", ssl_cipher_list);
+ if (!(SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list))) {
+ syslog(LOG_WARNING, "SSL_CTX_set_cipher_list failed: %s", ERR_reason_error_string(ERR_get_error()));
+ return;
+ }
+
+ // Now try to bind to the key and certificate.
+ bind_to_key_and_certificate();
+}
+
+
+// Check the modification time of the key and certificate -- reload if they changed
+void update_key_and_cert_if_needed(void) {
+ static time_t previous_mtime = 0;
+ struct stat keystat;
+ struct stat certstat;
+
+ if (stat(key_file, &keystat) != 0) {
+ syslog(LOG_ERR, "%s: %s", key_file, strerror(errno));
+ return;
+ }
+ if (stat(cert_file, &certstat) != 0) {
+ syslog(LOG_ERR, "%s: %s", cert_file, strerror(errno));
+ return;
+ }
+
+ if ((keystat.st_mtime + certstat.st_mtime) != previous_mtime) {
+ bind_to_key_and_certificate();
+ previous_mtime = keystat.st_mtime + certstat.st_mtime;
+ }
+}
+
+
+// starts SSL/TLS encryption for the current session.
+void starttls(struct client_handle *ch) {
+ int retval, bits, alg_bits;
+
+ if (!ssl_ctx) {
+ return;
+ }
+
+ // Check the modification time of the key and certificate -- reload if they changed
+ update_key_and_cert_if_needed();
+
+ if (!(ch->ssl_handle = SSL_new(ssl_ctx))) {
+ syslog(LOG_WARNING, "SSL_new failed: %s", ERR_reason_error_string(ERR_get_error()));
+ return;
+ }
+ if (!(SSL_set_fd(ch->ssl_handle, ch->sock))) {
+ syslog(LOG_WARNING, "SSL_set_fd failed: %s", ERR_reason_error_string(ERR_get_error()));
+ SSL_free(ch->ssl_handle);
+ return;
+ }
+ retval = SSL_accept(ch->ssl_handle);
+ if (retval < 1) {
+ syslog(LOG_WARNING, "SSL_accept failed: %s", ERR_reason_error_string(ERR_get_error()));
+ }
+ else {
+ syslog(LOG_INFO, "SSL_accept success");
+ }
+ bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ch->ssl_handle), &alg_bits);
+ syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)",
+ SSL_CIPHER_get_name(SSL_get_current_cipher(ch->ssl_handle)),
+ SSL_CIPHER_get_version(SSL_get_current_cipher(ch->ssl_handle)), bits, alg_bits);
+ syslog(LOG_INFO, "SSL started");
+}
+
+
+// shuts down the TLS connection
+void endtls(struct client_handle *ch) {
+ syslog(LOG_INFO, "Ending SSL/TLS");
+ if (ch->ssl_handle != NULL) {
+ SSL_shutdown(ch->ssl_handle);
+ SSL_get_SSL_CTX(ch->ssl_handle);
+ SSL_free(ch->ssl_handle);
+ }
+ ch->ssl_handle = NULL;
+}
+
+
+// Send binary data to the client encrypted.
+int client_write_ssl(struct client_handle *ch, char *buf, int nbytes) {
+ int retval;
+ int nremain;
+ char junk[1];
+
+ if (ch->ssl_handle == NULL)
+ return (-1);
+
+ nremain = nbytes;
+ while (nremain > 0) {
+ if (SSL_want_write(ch->ssl_handle)) {
+ if ((SSL_read(ch->ssl_handle, junk, 0)) < 1) {
+ syslog(LOG_WARNING, "SSL_read in client_write: %s", ERR_reason_error_string(ERR_get_error()));
+ }
+ }
+ retval = SSL_write(ch->ssl_handle, &buf[nbytes - nremain], nremain);
+ if (retval < 1) {
+ long errval;
+
+ errval = SSL_get_error(ch->ssl_handle, retval);
+ if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
+ sleep(1);
+ continue;
+ }
+ syslog(LOG_WARNING, "SSL_write: %s", ERR_reason_error_string(ERR_get_error()));
+ if (retval == -1) {
+ syslog(LOG_WARNING, "errno is %d", errno);
+ endtls(ch);
+ }
+ return -1;
+ }
+ nremain -= retval;
+ }
+ return 0;
+}
+
+
+// read data from the encrypted layer
+int client_read_ssl(struct client_handle *ch, char *buf, int nbytes) {
+ int bytes_read = 0;
+ int rlen = 0;
+ char junk[1];
+
+ if (ch->ssl_handle == NULL)
+ return (-1);
+
+ while (bytes_read < nbytes) {
+ if (SSL_want_read(ch->ssl_handle)) {
+ if ((SSL_write(ch->ssl_handle, junk, 0)) < 1) {
+ syslog(LOG_WARNING, "SSL_write in client_read");
+ }
+ }
+ rlen = SSL_read(ch->ssl_handle, &buf[bytes_read], nbytes - bytes_read);
+ if (rlen < 1) {
+ long errval;
+ errval = SSL_get_error(ch->ssl_handle, rlen);
+ if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
+ sleep(1);
+ continue;
+ }
+ syslog(LOG_WARNING, "SSL_read error %ld", errval);
+ endtls(ch);
+ return (-1);
+ }
+ bytes_read += rlen;
+ }
+ return (bytes_read);
+}
}
-// Check the modification time of the key and certificate -- reload if they changed
+// Check the modification time of the key and certificate -- reload if either one changed
void update_key_and_cert_if_needed(void) {
- static time_t cert_mtime = 0;
+ static time_t previous_mtime = 0;
struct stat keystat;
struct stat certstat;
return;
}
- if ((keystat.st_mtime > cert_mtime) || (certstat.st_mtime > cert_mtime)) {
+ if ((keystat.st_mtime + certstat.st_mtime) != previous_mtime) {
bind_to_key_and_certificate();
- cert_mtime = certstat.st_mtime;
+ previous_mtime = keystat.st_mtime + certstat.st_mtime;
}
}