From: Art Cancro Date: Sun, 5 Jun 2022 16:49:16 +0000 (-0400) Subject: Moved 'setup' to the utils directory and converted the build X-Git-Tag: v952~13 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=950b5e7c91bc0146fc239dc90f3eb3d949f1f06a Moved 'setup' to the utils directory and converted the build --- diff --git a/citadel/Makefile b/citadel/Makefile index f1439fad9..bf4b39b6e 100644 --- a/citadel/Makefile +++ b/citadel/Makefile @@ -17,11 +17,24 @@ # config.mk is generated by ./configure include config.mk -citserver: server/*.c server/modules/*/*.c config.mk +all: citserver setup + +citserver: server/*.c server/modules/*/*.c config.mk server/*.h cc ${CFLAGS} \ server/*.c server/modules/*/*.c \ ${LDFLAGS} -lresolv -lcitadel -lpthread -lz -lical -lldap -lcrypt -lexpat -lcurl -ldb \ -o citserver +setup: utils/setup.c server/citadel_dirs.c utils/*.h server/*.h + cc ${CFLAGS} utils/setup.c -lcitadel -o setup + config.mk: configure ./configure + +clean: + rm -vf citserver + find . -name *.o | xargs rm -vf + rm -vf config.mk + +# In conf-IG-ure, "distclean" is the same as "clean" +distclean: clean diff --git a/citadel/acinclude.m4 b/citadel/acinclude.m4 deleted file mode 100644 index 0941acf0b..000000000 --- a/citadel/acinclude.m4 +++ /dev/null @@ -1,50 +0,0 @@ -# CIT_STRUCT_TM -# ------------------ -# Figure out how to get the current GMT offset. If `struct tm' has a -# `tm_gmtoff' member, define `HAVE_STRUCT_TM_TM_GMTOFF'. Otherwise, if the -# external variable `timezone' is found, define `HAVE_TIMEZONE'. -AC_DEFUN([CIT_STRUCT_TM], -[AC_REQUIRE([AC_STRUCT_TM])dnl -AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[#include -#include <$ac_cv_struct_tm> -]) -if test "$ac_cv_member_struct_tm_tm_gmtoff" != yes; then - AC_CACHE_CHECK(for timezone, ac_cv_var_timezone, -[AC_TRY_LINK( -[#include ], -[printf("%ld", (long)timezone);], ac_cv_var_timezone=yes, ac_cv_var_timezone=no)]) - if test $ac_cv_var_timezone = yes; then - AC_DEFINE(HAVE_TIMEZONE, 1, - [Define if you don't have `tm_gmtoff' but do have the external - variable `timezone'.]) - fi -fi -])# CIT_STRUCT_TM - -AC_DEFUN([AC_CHECK_DB],[ -for lib in $1 -do - AS_VAR_PUSHDEF([ac_tr_db], [ac_cv_db_lib_${lib}])dnl - bogo_saved_LIBS="$LIBS" - LIBS="$LIBS -l$lib" - AC_CACHE_CHECK([for db_create in -l${lib}], ac_tr_db, - [AC_TRY_LINK([#include ], [int foo=db_create((void *)0, (void *) 0, -0 )], - [AS_VAR_SET(ac_tr_db, yes)], - [AS_VAR_SET(ac_tr_db, no)]) - ]) - AS_IF([test AS_VAR_GET(ac_tr_db) = yes], - [$2 - LIBS="$bogo_saved_LIBS" - SERVER_LIBS="$SERVER_LIBS -l$lib" - db=yes], - [LIBS="$bogo_saved_LIBS" - db=no]) - AS_VAR_POPDEF([ac_tr_db])dnl -test "$db" = "yes" && break -done -if test "$db" = "no"; then -$3 -fi -])# AC_CHECK_DB - diff --git a/citadel/auth.c b/citadel/auth.c deleted file mode 100644 index ead5f54b5..000000000 --- a/citadel/auth.c +++ /dev/null @@ -1,136 +0,0 @@ -// system-level password checking for host auth mode -// by Nathan Bryant, March 1999 -// updated by Trey van Riper, June 2005 -// -// Copyright (c) 1999-2016 by the citadel.org team -// -// This program is open source software. Use, duplication, or disclosure -// is subject to the terms of the GNU General Public License, version 3. -// The program is distributed without any warranty, expressed or implied. - -#if defined(__linux) || defined(__sun) // needed for crypt(): -#define _XOPEN_SOURCE -#define _XOPEN_SOURCE_EXTENDED 1 -#endif - -#include -#include -#include -#include -#include - -#include "auth.h" -#include "sysdep.h" - -#ifdef HAVE_GETSPNAM -#include -#endif - -#ifdef HAVE_PAM_START -#include - -// struct appdata: passed to the conversation function -struct appdata { - const char *name; - const char *pw; -}; - -// conv(): the PAM conversation function. this assumes that a -// PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is -// asking for a password. esoteric authentication modules will fail with this -// code, but we can't really support them with the existing client protocol -// anyway. the failure mode should be to deny access, in any case. -static int conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { - struct pam_response *temp_resp; - struct appdata *data = appdata_ptr; - - if ((temp_resp = - malloc(sizeof(struct pam_response[num_msg]))) == NULL) - return PAM_CONV_ERR; - - while (num_msg--) { - switch ((*msg)[num_msg].msg_style) { - case PAM_PROMPT_ECHO_ON: - temp_resp[num_msg].resp = strdup(data->name); - break; - case PAM_PROMPT_ECHO_OFF: - temp_resp[num_msg].resp = strdup(data->pw); - break; - default: - temp_resp[num_msg].resp = NULL; - } - temp_resp[num_msg].resp_retcode = 0; - } - - *resp = temp_resp; - return PAM_SUCCESS; -} -#endif // HAVE_PAM_START - - -// check that `pass' is the correct password for `uid' -// returns zero if no, nonzero if yes -int validate_password(uid_t uid, const char *pass) { - if (pass == NULL) { - return (0); - } -#ifdef HAVE_PAM_START - struct pam_conv pc; - struct appdata data; - pam_handle_t *ph; - int i; -#else - char *crypted_pwd; -#ifdef HAVE_GETSPNAM - struct spwd *sp; -#endif -#endif - struct passwd *pw; - int retval = 0; - - pw = getpwuid(uid); - if (pw == NULL) { - return retval; - } -#ifdef HAVE_PAM_START - -#ifdef PAM_DATA_SILENT - int flags = PAM_DATA_SILENT; -#else - int flags = 0; -#endif - - pc.conv = conv; - pc.appdata_ptr = &data; - data.name = pw->pw_name; - data.pw = pass; - if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS) - return (0); - - if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) { - if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) { - retval = -1; - } - } - - pam_end(ph, i | flags); -#else - crypted_pwd = pw->pw_passwd; - -#ifdef HAVE_GETSPNAM - if (pw == NULL) - return (0); - if (pw->pw_name == NULL) - return (0); - if ((sp = getspnam(pw->pw_name)) != NULL) { - crypted_pwd = sp->sp_pwdp; - } -#endif - - if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) { - retval = -1; - } -#endif // HAVE_PAM_START - - return retval; -} diff --git a/citadel/auth.h b/citadel/auth.h deleted file mode 100644 index d3b0fb803..000000000 --- a/citadel/auth.h +++ /dev/null @@ -1,2 +0,0 @@ - -int validate_password(uid_t uid, const char *pass); diff --git a/citadel/axdefs.h b/citadel/axdefs.h deleted file mode 100644 index e92f74171..000000000 --- a/citadel/axdefs.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef AXDEFS - -char *axdefs[]={ - "Deleted", - "New User", - "Problem User", - "Local User", - "Network User", - "Preferred User", - "Admin", - "Admin" -}; - -#define AXDEFS 1 - -#else - -extern char *axdefs[]; - -#endif - - - - -#ifndef VIEWDEFS - -char *viewdefs[]={ - "Messages", - "Summary", - "Address book", - "Calendar", - "Tasks" -}; - -#define VIEWDEFS 1 - -#else - -extern char *viewdefs[]; - -#endif - diff --git a/citadel/bootstrap b/citadel/bootstrap index 354aed110..8f3373470 100755 --- a/citadel/bootstrap +++ b/citadel/bootstrap @@ -2,33 +2,7 @@ # # run me after checking Citadel out of the source code repository. -echo ... running aclocal ... -aclocal -I m4 - -echo ... running autoconf ... -autoconf - -# If your autoconf version changes, the autom4te.cache stuff will mess you up. -# Get rid of it. -echo ... removing autoheader cache files ... -rm -rf autom4te*.cache - -echo ... running autoheader ... -autoheader - echo ... running mk_svn_revision.sh ... ./scripts/mk_svn_revision.sh -echo ... running mk_module_init.sh ... -./scripts/mk_module_init.sh - grep '#define REV_LEVEL' citadel.h | sed 's/[^0-9]*//g' >package-version.txt - -echo -echo This script has been tested with autoconf 2.53 and -echo automake 1.5. Other versions may work, but we recommend -echo the latest echo compatible versions of these. -echo -echo Also note that autoconf and automake should be configured -echo with the same prefix. -echo diff --git a/citadel/chkpw.c b/citadel/chkpw.c deleted file mode 100644 index 83e432fad..000000000 --- a/citadel/chkpw.c +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, or disclosure -// is subject to the terms of the GNU General Public License, version 3. -// The program is distributed without any warranty, expressed or implied. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "citadel.h" -#include "sysdep.h" -#include "citadel_dirs.h" -/* These pipes are used to talk to the chkpwd daemon, which is forked during startup */ -int chkpwd_write_pipe[2]; -int chkpwd_read_pipe[2]; - -/* - * Validate a password on the host unix system by talking to the chkpwd daemon - */ -static int validpw(uid_t uid, const char *pass) -{ - char buf[256]; - int rv; - - rv = write(chkpwd_write_pipe[1], &uid, sizeof(uid_t)); - if (rv == -1) { - printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); - return 0; - } - - rv = write(chkpwd_write_pipe[1], pass, 256); - if (rv == -1) { - printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); - return 0; - } - rv = read(chkpwd_read_pipe[0], buf, 4); - if (rv == -1) { - printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); - return 0; - } - if (!strncmp(buf, "PASS", 4)) { - printf("pass\n"); - return(1); - } - - printf("fail\n"); - return 0; -} - -/* - * Start up the chkpwd daemon so validpw() has something to talk to - */ -void start_chkpwd_daemon(void) { - pid_t chkpwd_pid; - struct stat filestats; - int i; - - printf("Starting chkpwd daemon for host authentication mode\n"); - - if ((stat(file_chkpwd, &filestats)==-1) || - (filestats.st_size==0)){ - printf("didn't find chkpwd daemon in %s: %s\n", file_chkpwd, strerror(errno)); - abort(); - } - if (pipe(chkpwd_write_pipe) != 0) { - printf("Unable to create pipe for chkpwd daemon: %s\n", strerror(errno)); - abort(); - } - if (pipe(chkpwd_read_pipe) != 0) { - printf("Unable to create pipe for chkpwd daemon: %s\n", strerror(errno)); - abort(); - } - - chkpwd_pid = fork(); - if (chkpwd_pid < 0) { - printf("Unable to fork chkpwd daemon: %s\n", strerror(errno)); - abort(); - } - if (chkpwd_pid == 0) { - dup2(chkpwd_write_pipe[0], 0); - dup2(chkpwd_read_pipe[1], 1); - for (i=2; i<256; ++i) close(i); - execl(file_chkpwd, file_chkpwd, NULL); - printf("Unable to exec chkpwd daemon: %s\n", strerror(errno)); - abort(); - exit(errno); - } -} - - - -int main(int argc, char **argv) { - char buf[256]; - struct passwd *p; - int uid; - - printf("\n\n ** host auth mode test utility **\n\n"); - start_chkpwd_daemon(); - - if (getuid() != 0){ - printf("\n\nERROR: you need to be root to run this!\n\n"); - return(1); - } - while(1) { - printf("\n\nUsername: "); - fgets(buf, sizeof buf, stdin); - buf[strlen(buf)-1] = 0; - p = getpwnam(buf); - if (p == NULL) { - printf("Not found\n"); - } - else { - uid = p->pw_uid; - printf(" uid: %d\n", uid); - printf("Password: "); - fgets(buf, sizeof buf, stdin); - buf[strlen(buf)-1] = 0; - validpw(uid, buf); - } - } - - return(0); -} diff --git a/citadel/chkpwd.c b/citadel/chkpwd.c deleted file mode 100644 index 96fed6620..000000000 --- a/citadel/chkpwd.c +++ /dev/null @@ -1,48 +0,0 @@ -// -// a setuid helper program for machines which use shadow passwords -// by Nathan Bryant, March 1999 -// -// Copyright (c) 1987-2012 by the citadel.org team -// -// This program is open source software. Use, duplication, or disclosure -// is subject to the terms of the GNU General Public License, version 3. -// The program is distributed without any warranty, expressed or implied. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "auth.h" -#include "config.h" -#include "citadel_dirs.h" -#include "citadel.h" - -int main(void) -{ - uid_t uid; - char buf[SIZ]; - - while (1) { - buf[0] = '\0'; - read(0, &uid, sizeof(uid_t)); /* uid */ - read(0, buf, 256); /* password */ - - if (buf[0] == '\0') - return (0); - if (validate_password(uid, buf)) { - write(1, "PASS", 4); - } - else { - write(1, "FAIL", 4); - } - } - - return(0); -} diff --git a/citadel/citadel.pam b/citadel/citadel.pam deleted file mode 100644 index 743c35a4b..000000000 --- a/citadel/citadel.pam +++ /dev/null @@ -1,7 +0,0 @@ -#%PAM-1.0 -# -# /etc/pam.d/citadel: PAM configuration file for Linux-PAM. -# -auth include system-auth -account include system-auth -session include system-auth diff --git a/citadel/citmail.c b/citadel/citmail.c deleted file mode 100644 index 924b67571..000000000 --- a/citadel/citmail.c +++ /dev/null @@ -1,319 +0,0 @@ -// This program attempts to act like a local MDA if you're using sendmail or -// some other non-Citadel MTA. It basically just contacts the Citadel LMTP -// listener on a unix domain socket and transmits the message. Really though, -// if your MTA supports LMTP then you definitely should be using that instead. -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, or disclosure -// is subject to the terms of the GNU General Public License, version 3. -// The program is distributed without any warranty, expressed or implied. - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "citadel_dirs.h" - -int serv_sock; -int debug = 0; - -void strip_trailing_nonprint(char *buf) { - while ( (!IsEmptyStr(buf)) && (!isprint(buf[strlen(buf) - 1])) ) { - buf[strlen(buf) - 1] = 0; - } -} - - -void timeout(int signum) { - exit(signum); -} - - -int uds_connectsock(char *sockpath) { - int s; - struct sockaddr_un addr; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockpath); - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) { - fprintf(stderr, "citmail: Can't create socket: %s\n", - strerror(errno)); - exit(3); - } - - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "citmail: can't connect: %s\n", - strerror(errno)); - close(s); - exit(3); - } - - return s; -} - - -// input binary data from socket -void serv_read(char *buf, int bytes) { - int len, rlen; - - len = 0; - while (len < bytes) { - rlen = read(serv_sock, &buf[len], bytes - len); - if (rlen < 1) { - return; - } - len = len + rlen; - } -} - - -// send binary to server -void serv_write(char *buf, int nbytes) { - int bytes_written = 0; - int retval; - while (bytes_written < nbytes) { - retval = write(serv_sock, &buf[bytes_written], - nbytes - bytes_written); - if (retval < 1) { - return; - } - bytes_written = bytes_written + retval; - } -} - - -// input string from socket - implemented in terms of serv_read() -void serv_gets(char *buf) { - int i; - - // Read one character at a time. - for (i = 0;; i++) { - serv_read(&buf[i], 1); - if (buf[i] == '\n' || i == (SIZ-1)) - break; - } - - // If we got a long line, discard characters until the newline. - if (i == (SIZ-1)) - while (buf[i] != '\n') - serv_read(&buf[i], 1); - - // Strip all trailing nonprintables (crlf) - buf[i] = 0; - strip_trailing_nonprint(buf); - if (debug) fprintf(stderr, "> %s\n", buf); -} - - -// send line to server - implemented in terms of serv_write() -void serv_puts(char *buf) { - if (debug) fprintf(stderr, "< %s\n", buf); - serv_write(buf, strlen(buf)); - serv_write("\n", 1); -} - - -void cleanup(int exitcode) { - char buf[1024]; - - if (exitcode != 0) { - fprintf(stderr, "citmail: error #%d occurred while sending mail.\n", exitcode); - fprintf(stderr, "Please check your Citadel configuration.\n"); - } - serv_puts("QUIT"); - serv_gets(buf); - exit(exitcode); -} - - -int main(int argc, char **argv) { - char buf[1024]; - char fromline[1024]; - FILE *fp; - int i; - struct passwd *pw; - int from_header = 0; - int in_body = 0; - char ctdldir[PATH_MAX]=CTDLDIR; - char *sp, *ep; - char hostname[256]; - char **recipients = NULL; - int num_recipients = 0; - int to_or_cc = 0; - int read_recipients_from_headers = 0; - char *add_these_recipients = NULL; - - for (i=1; ipw_name, hostname); - while (fgets(buf, 1024, stdin) != NULL) { - if ( ( (buf[0] == 13) || (buf[0] == 10)) && (in_body == 0) ) { - in_body = 1; - if (from_header == 0) { - fprintf(fp, "%s%s", fromline, buf); - } - } - if (in_body == 0 && !strncasecmp(buf, "From:", 5)) { - strcpy(fromline, buf); - from_header = 1; - } - - if (read_recipients_from_headers) { - add_these_recipients = NULL; - if ((isspace(buf[0])) && (to_or_cc)) { - add_these_recipients = buf; - } - else { - if ((!strncasecmp(buf, "To:", 3)) || (!strncasecmp(buf, "Cc:", 3))) { - to_or_cc = 1; - } - else { - to_or_cc = 0; - } - if (to_or_cc) { - add_these_recipients = &buf[3]; - } - } - - if (add_these_recipients) { - int num_recp_on_this_line; - char this_recp[256]; - - num_recp_on_this_line = num_tokens(add_these_recipients, ','); - for (i=0; iconfig.mk cat config.mk diff --git a/citadel/configure.ac b/citadel/configure.ac index e2b50749e..a6ec3f514 100644 --- a/citadel/configure.ac +++ b/citadel/configure.ac @@ -1,3 +1,18 @@ + + + +FAIL FAIL FAIL + +THIS IS THE OLD CONFIGURE SCRIPT + +KEEPING IT HERE FOR REFERENCE AS WE BUILD THE NEW ONE + +DONT RUN THIS + + + + + dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.52) diff --git a/citadel/ctdlmigrate.c b/citadel/ctdlmigrate.c deleted file mode 100644 index 5d8601179..000000000 --- a/citadel/ctdlmigrate.c +++ /dev/null @@ -1,457 +0,0 @@ -// Across-the-wire migration utility for Citadel -// -// Copyright (c) 2009-2021 citadel.org -// -// 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. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "axdefs.h" -#include "sysdep.h" -#include "config.h" -#include "citadel_dirs.h" - - -// support for getz() -- (globals would not be appropriate in a multithreaded program) -static int gmaxlen = 0; -static char *gdeftext = NULL; - - -// support function for getz() -static int limit_rl(FILE *dummy) { - if (rl_end > gmaxlen) { - return '\b'; - } - return rl_getc(dummy); -} - - -// support function for getz() -static int getz_deftext(void) { - if (gdeftext) { - rl_insert_text(gdeftext); - gdeftext = NULL; - rl_startup_hook = NULL; - } - return 0; -} - - -// Replacement for gets() that uses libreadline. -void getz(char *buf, int maxlen, char *default_value, char *prompt) { - rl_startup_hook = getz_deftext; - rl_getc_function = limit_rl; - gmaxlen = maxlen; - gdeftext = default_value; - strcpy(buf, readline(prompt)); -} - - -// Exit from the program while displaying an error code -void ctdlmigrate_exit(int cmdexit) { - printf("\n\n\033[3%dmExit code %d\033[0m\n", (cmdexit ? 1 : 2), cmdexit); - exit(cmdexit); -} - - -// Connect to a Citadel on a remote host using a TCP/IP socket -static 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 sock = (-1); - - if ((host == NULL) || IsEmptyStr(host)) { - return(-1); - } - if ((service == NULL) || IsEmptyStr(service)) { - return(-1); - } - - 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) { - fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); - 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) { - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) { - fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); - return (-1); - } - - rc = connect(sock, ai->ai_addr, ai->ai_addrlen); - if (rc >= 0) { - return (sock); // Connected! - } - else { - fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); - close(sock); // Failed. Close the socket to avoid fd leak! - } - } - return (-1); -} - - -// Connect to a Citadel on a remote host using a unix domaion socket -int uds_connectsock(char *sockpath) { - int s; - struct sockaddr_un addr; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockpath); - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) { - fprintf(stderr, "ctdlmigrate: Can't create socket: %s\n", strerror(errno)); - return(-1); - } - - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "ctdlmigrate: can't connect: %s\n", strerror(errno)); - close(s); - return(-1); - } - - return s; -} - - -// input binary data from socket -void serv_read(int serv_sock, char *buf, int bytes) { - int len = 0; - int rlen = 0; - - while (len < bytes) { - rlen = read(serv_sock, &buf[len], bytes - len); - if (rlen < 1) { - return; - } - len = len + rlen; - } -} - - -// send binary to server -void serv_write(int serv_sock, char *buf, int nbytes) { - int bytes_written = 0; - int retval; - while (bytes_written < nbytes) { - retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); - if (retval < 1) { - return; - } - bytes_written = bytes_written + retval; - } -} - - -// input string from socket - implemented in terms of serv_read() -void serv_gets(int serv_sock, char *buf) { - int i; - - // Read one character at a time. - for (i = 0;; i++) { - serv_read(serv_sock, &buf[i], 1); - if (buf[i] == '\n' || i == (SIZ-1)) - break; - } - - // If we got a long line, discard characters until the newline. - if (i == (SIZ-1)) { - while (buf[i] != '\n') { - serv_read(serv_sock, &buf[i], 1); - } - } - - // Strip all trailing nonprintables (crlf) - buf[i] = 0; -} - - -// send line to server - implemented in terms of serv_write() -void serv_puts(int serv_sock, char *buf) { - serv_write(serv_sock, buf, strlen(buf)); - serv_write(serv_sock, "\n", 1); -} - - -// send formatted printable data to the server -void serv_printf(int serv_sock, const char *format, ...) { - va_list arg_ptr; - char buf[1024]; - - va_start(arg_ptr, format); - if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1) - buf[sizeof buf - 2] = '\n'; - serv_write(serv_sock, buf, strlen(buf)); - va_end(arg_ptr); -} - - -// You know what main() does. If you don't, you shouldn't be trying to understand this program. -int main(int argc, char *argv[]) { - char ctdldir[PATH_MAX]=CTDLDIR; - char yesno[2]; - int cmdexit = 0; // when something fails, set cmdexit to nonzero, and skip to the end - char buf[PATH_MAX]; - - char remote_user[128]; - char remote_host[128]; - char remote_pass[128]; - char *remote_port = "504"; - - int linecount = 0; - int a; - int remote_server_socket = (-1); - int local_admin_socket = (-1); - int progress = 0; - - // Parse command line - while ((a = getopt(argc, argv, "h:")) != EOF) { - switch (a) { - case 'h': - strcpy(ctdldir, optarg); - break; - default: - fprintf(stderr, "ctdlmigrate: usage: ctdlmigrate [-h server_dir]\n"); - return(1); - } - } - - if (chdir(ctdldir) != 0) { - fprintf(stderr, "ctdlmigrate: %s: %s\n", ctdldir, strerror(errno)); - exit(errno); - } - - signal(SIGINT, ctdlmigrate_exit); - signal(SIGQUIT, ctdlmigrate_exit); - signal(SIGTERM, ctdlmigrate_exit); - signal(SIGSEGV, ctdlmigrate_exit); - signal(SIGHUP, ctdlmigrate_exit); - signal(SIGPIPE, ctdlmigrate_exit); - - printf( "\033[2J\033[H\n" - " \033[32m╔═══════════════════════════════════════════════╗\n" - " ║ ║\n" - " ║ \033[33mCitadel over-the-wire migration utility \033[32m║\n" - " ║ ║\n" - " ╚═══════════════════════════════════════════════╝\033[0m\n" - "\n" - "This utility is designed to migrate your Citadel installation\n" - "to a new host system via a network connection, without disturbing\n" - "the source system. The target may be a different CPU architecture\n" - "and/or operating system. The source system should be running\n" - "Citadel version \033[33m%d\033[0m or newer, and the target system should be running\n" - "either the same version or a newer version.\n" - "\n" - "You must run this utility on the TARGET SYSTEM. Any existing data\n" - "on this system will be ERASED. Your target system will be on this\n" - "host in %s.\n" - "\n", - EXPORT_REV_MIN, ctdldir - ); - - getz(yesno, 1, NULL, "Do you wish to continue? "); - puts(yesno); - if (tolower(yesno[0]) != 'y') { - cmdexit = 101; - } - - if (!cmdexit) { - printf( "\033[2J\033[H\n" - "\033[32m╔═══════════════════════════════════════════════╗\n" - "║ ║\n" - "║ \033[33mValidate source and target systems\033[32m ║\n" - "║ ║\n" - "╚═══════════════════════════════════════════════╝\033[0m\n" - "\n\n"); - - printf("First we must validate that the local target system is running\n"); - printf("and ready to receive data.\n"); - printf("Checking connectivity to Citadel in %s...\n", ctdldir); - local_admin_socket = uds_connectsock("citadel-admin.socket"); - if (local_admin_socket < 0) { - cmdexit = 102; - } - } - - if (!cmdexit) { - serv_gets(local_admin_socket, buf); - puts(buf); - if (buf[0] != '2') { - cmdexit = 103; - } - } - - if (!cmdexit) { - serv_puts(local_admin_socket, "ECHO Connection to Citadel Server succeeded."); - serv_gets(local_admin_socket, buf); - puts(buf); - if (buf[0] != '2') { - cmdexit = 104; - } - } - - if (!cmdexit) { - printf("\n"); - printf("OK, this side is ready to go. Now we must connect to the source system.\n\n"); - - getz(remote_host, sizeof remote_host, NULL, "Enter the name or IP address of the source system: "); - getz(remote_user, sizeof remote_user, "admin", " Enter the user name of an administrator account: "); - getz(remote_pass, sizeof remote_pass, NULL, " Enter the password for this account: "); - - remote_server_socket = tcp_connectsock(remote_host, remote_port); - if (remote_server_socket < 0) { - cmdexit = 105; - } - } - - if (!cmdexit) { - serv_gets(remote_server_socket, buf); - puts(buf); - if (buf[0] != '2') { - cmdexit = 106; - } - } - - if (!cmdexit) { - serv_printf(remote_server_socket, "USER %s\n", remote_user); - serv_gets(remote_server_socket, buf); - puts(buf); - if (buf[0] != '3') { - cmdexit = 107; - } - } - - if (!cmdexit) { - serv_printf(remote_server_socket, "PASS %s\n", remote_pass); - serv_gets(remote_server_socket, buf); - puts(buf); - if (buf[0] != '2') { - cmdexit = 108; - } - } - - if (!cmdexit) { - printf( "\033[2J\033[H\n" - "\033[32m╔═══════════════════════════════════════════════════════════════════╗\n" - "║ ║\n" - "║ \033[33mMigrating from: %-50s\033[32m║\n" - "║ ║\n" - "╠═══════════════════════════════════════════════════════════════════╣\n" - "║ ║\n" - "║ Lines received: 0 Percent complete: 0 ║\n" - "║ ║\n" - "╚═══════════════════════════════════════════════════════════════════╝\033[0m\n" - "\n", remote_host - ); - } - - if (!cmdexit) { - serv_puts(remote_server_socket, "MIGR export"); - serv_gets(remote_server_socket, buf); - if (buf[0] != '1') { - printf("\n\033[31m%s\033[0m\n", buf); - cmdexit = 109; - } - } - - if (!cmdexit) { - serv_puts(local_admin_socket, "MIGR import"); - serv_gets(local_admin_socket, buf); - if (buf[0] != '4') { - printf("\n\033[31m%s\033[0m\n", buf); - cmdexit = 110; - } - } - - if (!cmdexit) { - char *ptr; - time_t last_update = time(NULL); - - while (serv_gets(remote_server_socket, buf), strcmp(buf, "000")) { - ptr = strchr(buf, '\n'); - if (ptr) *ptr = 0; // remove the newline character - ++linecount; - if (!strncasecmp(buf, "", 10)) { - progress = atoi(&buf[10]); - printf("\033[8;65H\033[33m%d\033[0m\033[12;0H\n", progress); - } - if (time(NULL) != last_update) { - last_update = time(NULL); - printf("\033[8;19H\033[33m%d\033[0m\033[12;0H\n", linecount); - } - serv_puts(local_admin_socket, buf); - } - - serv_puts(local_admin_socket, "000"); - } - - if ( (cmdexit == 0) && (progress < 100) ) { - printf("\033[31mERROR: source stream ended before 100 percent of data was received.\033[0m\n"); - cmdexit = 111; - } - - if (!cmdexit) { - printf("\033[36mMigration is complete. Restarting the target server.\033[0m\n"); - serv_puts(local_admin_socket, "DOWN 1"); - serv_gets(local_admin_socket, buf); - puts(buf); - printf("\033[36mIt is recommended that you shut down the source server now.\033[0m\n"); - printf("\033[36mRemember to copy over your SSL keys and file libraries if appropriate.\033[0m\n"); - } - - close(remote_server_socket); - close(local_admin_socket); - ctdlmigrate_exit(cmdexit); -} diff --git a/citadel/database_cleanup.sh b/citadel/database_cleanup.sh deleted file mode 100755 index 765494679..000000000 --- a/citadel/database_cleanup.sh +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/bash - -die () { - echo Exiting. - exit 1 -} - -DATA_DIR="/usr/local/citadel" - -usage() { - echo "Usage: database_cleanup.sh [ -h citadel_dir ]" - exit 2 -} - -PARSED_ARGUMENTS=$(getopt -a -n database_cleanup.sh -o h: -- "$@") -VALID_ARGUMENTS=$? -if [ "$VALID_ARGUMENTS" != "0" ]; then - usage -fi - -eval set -- "$PARSED_ARGUMENTS" -while : -do - case "$1" in - -h | --alpha) - DATA_DIR=${2} - shift 2 - ;; - # -- means the end of the arguments; drop this, and break out of the while loop - --) shift; break ;; - # If invalid options were passed, then getopt should have reported an error, - # which we checked as VALID_ARGUMENTS when getopt was called... - *) echo "Unexpected option: $1 - this should not happen." - usage - ;; - esac -done - -DATA_DIR=$DATA_DIR/data - -# If we're on a Docker or Easy Install system, use our own db_ tools. -if [ -x /usr/local/ctdlsupport/bin/db_dump ] ; then - export PATH=/usr/local/ctdlsupport/bin:$PATH - RECOVER=/usr/local/ctdlsupport/bin/db_recover - DUMP=/usr/local/ctdlsupport/bin/db_dump - LOAD=/usr/local/ctdlsupport/bin/db_load - -# otherwise look in /usr/local -elif [ -x /usr/local/bin/db_dump ] ; then - export PATH=/usr/local/bin:$PATH - RECOVER=/usr/local/bin/db_recover - DUMP=/usr/local/bin/db_dump - LOAD=/usr/local/bin/db_load - -# usual install -else - if test -f /usr/bin/db_dump; then - RECOVER=/usr/bin/db_recover - DUMP=/usr/bin/db_dump - LOAD=/usr/bin/db_load - else - if test -n "`ls /usr/bin/db?*recover`"; then - # seems we have something debian alike thats adding version in the filename - if test "`ls /usr/bin/db*recover |wc -l`" -gt "1"; then - echo "Warning: you have more than one version of the Berkeley DB utilities installed." 1>&2 - echo "Using the latest one." 1>&2 - RECOVER=`ls /usr/bin/db*recover |sort |tail -n 1` - DUMP=`ls /usr/bin/db*dump |sort |tail -n 1` - LOAD=`ls /usr/bin/db*load |sort |tail -n 1` - else - RECOVER=`ls /usr/bin/db*recover` - DUMP=`ls /usr/bin/db*dump` - LOAD=`ls /usr/bin/db*load` - fi - else - echo "database_cleanup.sh cannot find the Berkeley DB utilities. Exiting." 1>&2 - die - fi - - fi -fi - -# Ok, let's begin. - -clear -cat </tmp/CitaDump.$x || { - echo error $? - die - } - rm -vf $DATA_DIR/$filename -done - -echo Removing old databases -rm -vf $DATA_DIR/* - -for x in 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d -do - filename=cdb.$x - echo Loading $filename - $LOAD -h $DATA_DIR $filename /dev/null 2>/dev/null || exit 1 - -# this check will find the timezone if /etc/localtime is a link to the right timezone file -# or that file has been copied to /etc/localtime and not changed afterwards -LOCALTIMESUM=`md5sum /etc/localtime | awk ' { print $1 } ' 2>/dev/null` -find /usr/share/zoneinfo -type f -print | while read filename -do - THISTIMESUM=`md5sum $filename | awk ' { print $1 } '` - if [ $LOCALTIMESUM = $THISTIMESUM ] ; then - echo $filename | cut -c21- - exit 0 - fi -done 2>/dev/null - -# seems we haven't found the timezone yet, let's see whether /etc/timezone has some info - -if [ -e /etc/timezone ]; then - TIMEZONE="$(head -n 1 /etc/timezone)" - TIMEZONE="${TIMEZONE%% *}" - TIMEZONE="${TIMEZONE##/}" - TIMEZONE="${TIMEZONE%%/}" - TIMEZONE="$(convert_timezone $TIMEZONE)" - if [ -f "/usr/share/zoneinfo/$TIMEZONE" ] ; then - echo $TIMEZONE - exit 0 - fi -fi - -exit 2 diff --git a/citadel/install-sh b/citadel/install-sh deleted file mode 100644 index ebc66913e..000000000 --- a/citadel/install-sh +++ /dev/null @@ -1,250 +0,0 @@ -#! /bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5 (mit/util/scripts/install.sh). -# -# Copyright 1991 by the Massachusetts Institute of Technology -# -# Permission to use, copy, modify, distribute, and sell this software and its -# documentation for any purpose is hereby granted without fee, provided that -# the above copyright notice appear in all copies and that both that -# copyright notice and this permission notice appear in supporting -# documentation, and that the name of M.I.T. not be used in advertising or -# publicity pertaining to distribution of the software without specific, -# written prior permission. M.I.T. makes no representations about the -# suitability of this software for any purpose. It is provided "as is" -# without express or implied warranty. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. It can only install one file at a time, a restriction -# shared with many OS's install programs. - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -transformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/citadel/internetmail.h b/citadel/internetmail.h deleted file mode 100644 index 00c565297..000000000 --- a/citadel/internetmail.h +++ /dev/null @@ -1,2 +0,0 @@ -void LoadInternetConfig(void); -int IsHostLocal(char *WhichHost); diff --git a/citadel/m4/ucread.m4 b/citadel/m4/ucread.m4 deleted file mode 100644 index 09ac70fcd..000000000 --- a/citadel/m4/ucread.m4 +++ /dev/null @@ -1,33 +0,0 @@ -# Check if "struct ucred" is available. If not, try harder with -# _GNU_SOURCE. -# -# heavily inspired by: http://git.musicpd.org/cgit/master/mpd.git/tree/m4/ucred.m4 -# Author: Max Kellermann - -AC_DEFUN([STRUCT_UCRED],[ - AC_MSG_CHECKING([for struct ucred]) - AC_CACHE_VAL(mpd_cv_have_struct_ucred, [ - AC_TRY_COMPILE([#include ], - [struct ucred cred;], - mpd_cv_have_struct_ucred=yes, - mpd_cv_have_struct_ucred=no) - if test x$mpd_cv_have_struct_ucred = xno; then - # glibc 2.8 forces _GNU_SOURCE on us - AC_TRY_COMPILE( - [#define _GNU_SOURCE - #include ], - [struct ucred cred;], - mpd_cv_have_struct_ucred=yes, - mpd_cv_have_struct_ucred=no) - if test x$mpd_cv_have_struct_ucred = xyes; then - # :( - MPD_CFLAGS="$MPD_CFLAGS -D_GNU_SOURCE" - fi - fi - ]) - - AC_MSG_RESULT($mpd_cv_have_struct_ucred) - if test x$mpd_cv_have_struct_ucred = xyes; then - AC_DEFINE(HAVE_STRUCT_UCRED, 1, [Define if struct ucred is present from sys/socket.h]) - fi -]) \ No newline at end of file diff --git a/citadel/scripts/dolcov.sh b/citadel/scripts/dolcov.sh deleted file mode 100755 index bb5f439db..000000000 --- a/citadel/scripts/dolcov.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -CITDIR=`pwd` -OUTDIR=${CITDIR}/../../coverage/citadel -ln -s parsedate.c y.tab.c - -# if we call citserver with ./citserver, we don't need these: -#cd ${CITDIR}/utillib/; ln -s . utillib; cd .. -#cd ${CITDIR}/modules -#for i in *; do cd $CITDIR/modules/$i; ln -s . modules; ln -s . $i; ln -s ../../user_ops.h .; done - -cd ${CITDIR} - -mkdir -p ${OUTDIR} -lcov --base-directory ${CITDIR} --directory . --capture --output-file ${OUTDIR}/citadel.info $@ -genhtml --output-directory ${OUTDIR} ${OUTDIR}/citadel.info - - - -#exit -#rm y.tab.c - -find -type l -exec rm {} \; -rm -f .#user_ops.h.gcov \ No newline at end of file diff --git a/citadel/scripts/mk_module_init.sh b/citadel/scripts/mk_module_init.sh deleted file mode 100755 index cabae3ccb..000000000 --- a/citadel/scripts/mk_module_init.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/bin/sh -# -# Script to generate $C_FILE -# - -ECHO=/usr/bin/printf -SED=/usr/bin/sed - -#MINUS_e=X`$ECHO -n -e` -#if [ $MINUS_e != "X" ] ; then -# MINUS_e="" -#else -# MINUS_e="-e" -#fi - -#MINUS_E=X`$ECHO -n -E` -#if [ $MINUS_E != "X" ] ; then -# MINUS_E="" -#else -# MINUS_E="-E" -#fi - - -CUR_DIR=`pwd` -C_FILE="$CUR_DIR/modules_init.c" -H_FILE="$CUR_DIR/modules_init.h" -MOD_FILE="$CUR_DIR/Make_modules" -SRC_FILE="$CUR_DIR/Make_sources" -U_FILE="$CUR_DIR/modules_upgrade.c" - -/usr/bin/printf "Scanning extension modules for entry points.\n" - -STATIC_FIRST_MODULES="control modules euidindex msgbase database" -DYNAMIC_MODULES=`grep CTDL_MODULE_INIT modules/*/*.c |$SED 's;.*(\(.*\));\1;'` -if test -d user_modules; then - USER_MODULES=`grep CTDL_MODULE_INIT user_modules/*/*.c |$SED 's;.*(\(.*\));\1;'` -else - USER_MODULES= -fi -STATIC_LAST_MODULES="netconfig" - -############################################################################### -# start the c file # -############################################################################### - -cat <$C_FILE -/* - * $C_FILE - * Auto generated by mk_modules_init.sh DO NOT EDIT THIS FILE - */ - - - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "modules_init.h" -#include "sysdep_decls.h" -#include "serv_extensions.h" - - -void LogPrintMessages(long err); -extern long DetailErrorFlags; - -void initialise_modules (int threading) -{ - long filter; - const char *pMod; - - syslog(LOG_DEBUG, "modules: initializing, CtdlThreads %s", (threading ? "enabled" : "not yet enabled")); - -EOF - - -for i in ${STATIC_FIRST_MODULES} ${DYNAMIC_MODULES} ${USER_MODULES} ${STATIC_LAST_MODULES}; do -cat <> $C_FILE - pMod = CTDL_INIT_CALL($i); - syslog(LOG_DEBUG, "modules: loaded %s", pMod); -EOF - -done -cat <> $C_FILE - - for (filter = 1; filter != 0; filter = filter << 1) - if ((filter & DetailErrorFlags) != 0) - LogPrintMessages(filter); -} - -EOF - - - - - -############################################################################### -# start the header file # -############################################################################### -cat < $H_FILE -/* - * $H_FILE - * Auto generated by mk_modules_init.sh DO NOT EDIT THIS FILE - */ - - -#ifndef MODULES_INIT_H -#define MODULES_INIT_H -#include "ctdl_module.h" -extern size_t nSizErrmsg; -void initialise_modules (int threading); -void upgrade_modules(void); - -EOF - -for i in ${STATIC_FIRST_MODULES} ${DYNAMIC_MODULES} ${USER_MODULES} ${STATIC_LAST_MODULES}; do -# Add this entry point to the .h file -cat <> $H_FILE - CTDL_MODULE_INIT($i); -EOF -done - -grep CTDL_MODULE_UPGRADE *.c modules/*/*.c |$SED 's;.*(\(.*\));\CTDL_MODULE_UPGRADE(\1)\;\n;' >> $H_FILE - -cat <> $H_FILE - - -#endif /* MODULES_INIT_H */ - -EOF - - -############################################################################### -# u start the Makefile included file for $SERV_MODULES # -############################################################################### -cat <$MOD_FILE -# -# Make_modules -# This file is to be included by Makefile to dynamically add modules to the build process -# THIS FILE WAS AUTO GENERATED BY mk_modules_init.sh DO NOT EDIT THIS FILE -# - -SERV_MODULES = \\ -EOF - -echo modules/*/*.c | $SED -e "s;\.c ;.o \\\\\n;g" -e "s;\.c;.o;" >> $MOD_FILE -echo >> $MOD_FILE - - -############################################################################### -# start of the files which inturn removes any existing file # -############################################################################### - - -# start the Makefile included file for $SOURCES -cat <$SRC_FILE -# -# Make_sources -# This file is to be included by Makefile to dynamically add modules to the build process -# THIS FILE WAS AUTO GENERATED BY mk_modules_init.sh DO NOT EDIT THIS FILE -# - -SOURCES = \\ -EOF - -echo modules/*/*.c | $SED "s;\.c ;.c \\\\\n;g" >> $SRC_FILE -echo >> $SRC_FILE - - - -############################################################################### -# start the upgrade file # -############################################################################### -cat <$U_FILE -/* - * $U_FILE - * Auto generated by mk_modules_init.sh DO NOT EDIT THIS FILE - */ - - - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "modules_init.h" -#include "sysdep_decls.h" -#include "serv_extensions.h" - - - -void upgrade_modules (void) -{ - const char *pMod; - - syslog(LOG_INFO, "modules: upgrading."); - -EOF - -# Add this entry point to the .c file - -grep CTDL_MODULE_UPGRADE *.c modules/*/*.c |$SED 's;.*(\(.*\));\tpMod = CTDL_UPGRADE_CALL(\1)\;\n\tsyslog(LOG_INFO, "modules: %s\\n", pMod)\;\n;' >> $U_FILE - -#close the upgrade file -/usr/bin/printf "}\n" >> $U_FILE diff --git a/citadel/scripts/valgrind_suspressions.txt b/citadel/scripts/valgrind_suspressions.txt deleted file mode 100644 index ca6afee9f..000000000 --- a/citadel/scripts/valgrind_suspressions.txt +++ /dev/null @@ -1,273 +0,0 @@ -{ - blargtest ion_name_here - Memcheck:Cond - obj:/lib/libc-2.11.2.so - fun:ERR_load_ERR_strings - fun:ERR_load_crypto_strings - fun:SSL_load_error_strings - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - - Memcheck:Value8 - obj:/lib/libc-2.11.2.so - fun:ERR_load_ERR_strings - fun:ERR_load_crypto_strings - fun:SSL_load_error_strings - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - - Memcheck:Cond - fun:__GI_strlen - obj:/usr/lib/libcrypto.so.0.9.8 - fun:BIO_gets - fun:PEM_read_bio - fun:PEM_bytes_read_bio - fun:PEM_ASN1_read_bio - fun:SSL_CTX_use_certificate_chain_file - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - - Memcheck:Cond - fun:PEM_read_bio - fun:PEM_bytes_read_bio - fun:PEM_ASN1_read_bio - fun:SSL_CTX_use_certificate_chain_file - fun:init_ssl - fun:init_sysdep - fun:main -} - - - - - - - - - -{ - some openssl initializationshit - Memcheck:Cond - ... - fun:SSL_load_error_strings - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - some openssl shit - Memcheck:Value8 - ... - fun:SSL_load_error_strings - fun:init_ssl - fun:init_sysdep - fun:main -} -# obj:/lib/libc-* - -{ - more openssl library shit - Memcheck:Leak - ... - fun:SSL_library_init - fun:init_ssl - fun:init_sysdep - fun:main -} - -{ - more openssl library shit - Memcheck:Cond - ... - fun:SSL_CTX_use_certificate_chain_file - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - more openssl library shit - Memcheck:Cond - ... - fun:SSL_CTX_use_PrivateKey_file - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - more openssl library shit - Memcheck:Value8 - ... - fun:SSL_CTX_use_PrivateKey_file - fun:init_ssl - fun:init_sysdep - fun:main -} -{ - - Memcheck:Value8 - ... - fun:SSL_CTX_use_certificate_chain_file - fun:init_ssl - fun:init_sysdep - fun:main -} - - - -{ - - Memcheck:Cond - ... - fun:_dl_start - obj:/lib/ld-2.11.2.so - obj:* - obj:* - obj:* -} - -{ - - Memcheck:Cond - ... - fun:dl_main - fun:_dl_sysdep_start - fun:_dl_start - obj:/lib/ld-2.11.2.so - obj:* - obj:* -} - -{ - - Memcheck:Addr8 - ... - fun:__env_open - fun:open_databases - fun:master_startup - fun:main -} -{ - - Memcheck:Cond - ... - fun:__env_open - fun:open_databases - fun:master_startup - fun:main -} -{ - - Memcheck:Value8 - ... - fun:__env_open - fun:open_databases - fun:master_startup - fun:main -} - -{ - - Memcheck:Value8 - ... - fun:__env_open - fun:open_databases - fun:master_startup -} -{ - - Memcheck:Cond - ... - fun:__db_open_pp - fun:open_databases - fun:master_startup - fun:main -} -{ - - Memcheck:Cond - ... - fun:__env_open - fun:open_databases - fun:master_startup -} -{ - - Memcheck:Value8 - ... - fun:__db_open_pp - fun:open_databases - fun:master_startup - fun:main -} -{ - - Memcheck:Value8 - ... - fun:__db_open_pp - fun:open_databases - fun:master_startup - fun:main -} - -{ - - Memcheck:Cond - ... - fun:__db_open_pp - fun:open_databases -} -{ - - Memcheck:Value8 - ... - fun:__db_open_pp - fun:open_databases - fun:master_startup -} -{ - - Memcheck:Value8 - ... - fun:__db_open_pp - fun:open_databases -} - - - -{ - - Memcheck:Value8 - fun:CtdlRegisterServiceHook - ... -} - -{ - - Memcheck:Cond - fun:__GI_strlen - fun:CtdlRegisterServiceHook - ... -} - - - - - -# close -{ - - Memcheck:Cond - ... - fun:close_databases - fun:master_cleanup - fun:main -} diff --git a/citadel/sendcommand.c b/citadel/sendcommand.c deleted file mode 100644 index bd87ff3b4..000000000 --- a/citadel/sendcommand.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Command-line utility to transmit a server command. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "citadel_dirs.h" -#include - -int serv_sock = (-1); - -int uds_connectsock(char *sockpath) { - int s; - struct sockaddr_un addr; - - 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) { - fprintf(stderr, "sendcommand: Can't create socket: %s\n", strerror(errno)); - exit(3); - } - - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "sendcommand: can't connect: %s\n", strerror(errno)); - close(s); - exit(3); - } - - return s; -} - - -/* - * input binary data from socket - */ -void serv_read(char *buf, int bytes) { - int len, rlen; - - len = 0; - while (len < bytes) { - rlen = read(serv_sock, &buf[len], bytes - len); - if (rlen < 1) { - return; - } - len = len + rlen; - } -} - - -/* - * send binary to server - */ -void serv_write(char *buf, int nbytes) { - int bytes_written = 0; - int retval; - while (bytes_written < nbytes) { - retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); - if (retval < 1) { - return; - } - bytes_written = bytes_written + retval; - } -} - - -/* - * input string from socket - implemented in terms of serv_read() - */ -void serv_gets(char *buf) { - int i; - - /* Read one character at a time. - */ - for (i = 0;; i++) { - serv_read(&buf[i], 1); - if (buf[i] == '\n' || i == (SIZ-1)) - break; - } - - /* If we got a long line, discard characters until the newline. - */ - if (i == (SIZ-1)) { - while (buf[i] != '\n') { - serv_read(&buf[i], 1); - } - } - - /* Strip all trailing nonprintables (crlf) - */ - buf[i] = 0; -} - - -/* - * send line to server - implemented in terms of serv_write() - */ -void serv_puts(char *buf) { - serv_write(buf, strlen(buf)); - serv_write("\n", 1); -} - - -/* - * Main loop. Do things and have fun. - */ -int main(int argc, char **argv) { - int a; - int watchdog = 60; - char buf[SIZ]; - int xfermode = 0; - char ctdldir[PATH_MAX]=CTDLDIR; - - /* Parse command line */ - while ((a = getopt(argc, argv, "h:w:")) != EOF) { - switch (a) { - case 'h': - strncpy(ctdldir, optarg, sizeof ctdldir); - break; - case 'w': - watchdog = atoi(optarg); - break; - default: - fprintf(stderr, "sendcommand: usage: sendcommand [-h server_dir] [-w watchdog_timeout]\n"); - return(1); - } - } - - fprintf(stderr, "sendcommand: started (pid=%d) connecting to Citadel server with data directory %s\n", - (int) getpid(), - ctdldir - ); - fflush(stderr); - - if (chdir(ctdldir) != 0) { - fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); - exit(errno); - } - - alarm(watchdog); - serv_sock = uds_connectsock(file_citadel_admin_socket); - serv_gets(buf); - fprintf(stderr, "%s\n", buf); - - strcpy(buf, ""); - for (a=optind; a 0) { - if (buf[strlen(buf)-1] == '\n') { - buf[strlen(buf)-1] = 0; - } - serv_puts(buf); - } - serv_puts("000"); - } - - if ((xfermode == '1') || (xfermode == '8')) { /* receive text */ - while(serv_gets(buf), strcmp(buf, "000")) { - printf("%s\n", buf); - } - } - - if (xfermode == '6') { /* receive binary */ - size_t len = atoi(&buf[4]); - size_t bytes_remaining = len; - - while (bytes_remaining > 0) { - size_t this_block = bytes_remaining; - if (this_block > SIZ) this_block = SIZ; - serv_read(buf, this_block); - fwrite(buf, this_block, 1, stdout); - bytes_remaining -= this_block; - } - } - - close(serv_sock); - alarm(0); /* cancel the watchdog timer */ - - fprintf(stderr, "sendcommand: processing ended.\n"); - if (xfermode == '5') { - return(1); - } - return(0); -} diff --git a/citadel/setup.c b/citadel/setup.c deleted file mode 100644 index 9083fb8d4..000000000 --- a/citadel/setup.c +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Citadel setup utility - * - * 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. - */ - -#define SHOW_ME_VAPPEND_PRINTF -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "axdefs.h" -#include "sysdep.h" -#include "citadel_dirs.h" - -#ifdef ENABLE_NLS -#ifdef HAVE_XLOCALE_H -#include -#endif -#include -#include -#define _(string) gettext(string) -#else -#define _(string) (string) -#endif - -#define SERVICE_NAME "citadel" -#define PROTO_NAME "tcp" -#define NSSCONF "/etc/nsswitch.conf" - -typedef enum _SetupStep { - eCitadelHomeDir = 0, - eSysAdminName = 1, - eSysAdminPW = 2, - eUID = 3, - eIP_ADDR = 4, - eCTDL_Port = 5, - eAuthType = 6, - eLDAP_Host = 7, - eLDAP_Port = 8, - eLDAP_Base_DN = 9, - eLDAP_Bind_DN = 10, - eLDAP_Bind_PW = 11, - eMaxQuestions = 12 -} eSetupStep; - -///"CREATE_XINETD_ENTRY"; -/* Environment variables, don't translate! */ -const char *EnvNames [eMaxQuestions] = { - "HOME_DIRECTORY", - "SYSADMIN_NAME", - "SYSADMIN_PW", - "CITADEL_UID", - "IP_ADDR", - "CITADEL_PORT", - "ENABLE_UNIX_AUTH", - "LDAP_HOST", - "LDAP_PORT", - "LDAP_BASE_DN", - "LDAP_BIND_DN", - "LDAP_BIND_PW" -}; - -int setup_type = (-1); -int enable_home = 1; -char admin_name[SIZ]; -char admin_pass[SIZ]; -char admin_cmd[SIZ]; -int serv_sock = (-1) ; - -const char *setup_titles[eMaxQuestions]; -const char *setup_text[eMaxQuestions]; - -char *program_title; - -void SetTitles(void) -{ - int have_run_dir; -#ifndef HAVE_RUN_DIR - have_run_dir = 1; -#else - have_run_dir = 0; -#endif - -#ifdef ENABLE_NLS - setlocale(LC_MESSAGES, getenv("LANG")); - bindtextdomain("citadel-setup", LOCALEDIR"/locale"); - textdomain("citadel-setup"); - bind_textdomain_codeset("citadel-setup","UTF8"); -#endif - - setup_titles[eCitadelHomeDir] = _("Citadel Home Directory"); - if (have_run_dir) - setup_text[eCitadelHomeDir] = _( -"Enter the full pathname of the directory in which the Citadel\n" -"installation you are creating or updating resides. If you\n" -"specify a directory other than the default, you will need to\n" -"specify the -h flag to the server when you start it up.\n"); - else - setup_text[eCitadelHomeDir] = _( -"Enter the subdirectory name for an alternate installation of " -"Citadel. To do a default installation just leave it blank." -"If you specify a directory other than the default, you will need to\n" -"specify the -h flag to the server when you start it up.\n" -"note that it may not have a leading /"); - - setup_titles[eSysAdminName] = _("Citadel administrator username:"); - setup_text[eSysAdminName] = _( -"Please enter the name of the Citadel user account that should be granted " -"administrative privileges once created. If using internal authentication " -"this user account will be created if it does not exist. For external " -"authentication this user account has to exist."); - - setup_titles[eSysAdminPW] = _("Administrator password:"); - setup_text[eSysAdminPW] = _( -"Enter a password for the system administrator. When setup\n" -"completes it will attempt to create the administrator user\n" -"and set the password specified here.\n"); - - setup_titles[eUID] = _("Citadel User ID:"); - setup_text[eUID] = _( -"Citadel needs to run under its own user ID. This would\n" -"typically be called \"citadel\", but if you are running Citadel\n" -"as a public site, you might also call it \"bbs\" or \"guest\".\n" -"The server will run under this user ID. Please specify that\n" -"user ID here. You may specify either a user name or a numeric\n" -"UID.\n"); - - setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:"); - setup_text[eIP_ADDR] = _( -"Please specify the IP address which the server should be listening to. " -"You can name a specific IPv4 or IPv6 address, or you can specify\n" -"\"*\" for \"any address\", \"::\" for \"any IPv6 address\", or \"0.0.0.0\"\n" -"for \"any IPv4 address\". If you leave this blank, Citadel will\n" -"listen on all addresses. " -"This can usually be left to the default unless multiple instances of Citadel " -"are running on the same computer."); - - setup_titles[eCTDL_Port] = _("Server port number:"); - setup_text[eCTDL_Port] = _( -"Specify the TCP port number on which your server will run.\n" -"Normally, this will be port 504, which is the official port\n" -"assigned by the IANA for Citadel servers. You will only need\n" -"to specify a different port number if you run multiple instances\n" -"of Citadel on the same computer and there is something else\n" -"already using port 504.\n"); - - setup_titles[eAuthType] = _("Authentication method to use:"); - setup_text[eAuthType] = _( -"Please choose the user authentication mode. By default Citadel will use its " -"own internal user accounts database. If you choose Host, Citadel users will " -"have accounts on the host system, authenticated via /etc/passwd or a PAM " -"source. LDAP chooses an RFC 2307 compliant directory server, the last option " -"chooses the nonstandard MS Active Directory LDAP scheme." -"\n" -"Do not change this option unless you are sure it is required, since changing " -"back requires a full reinstall of Citadel." -"\n" -" 0. Self contained authentication\n" -" 1. Host system integrated authentication\n" -" 2. External LDAP - RFC 2307 POSIX schema\n" -" 3. External LDAP - MS Active Directory schema\n" -"\n" -"For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n" -"\n" -"ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n"); - - setup_titles[eLDAP_Host] = _("LDAP host:"); - setup_text[eLDAP_Host] = _( -"Please enter the host name or IP address of your LDAP server.\n"); - - setup_titles[eLDAP_Port] = _("LDAP port number:"); - setup_text[eLDAP_Port] = _( -"Please enter the port number of the LDAP service (usually 389).\n"); - - setup_titles[eLDAP_Base_DN] = _("LDAP base DN:"); - setup_text[eLDAP_Base_DN] = _( -"Please enter the Base DN to search for authentication\n" -"(for example: dc=example,dc=com)\n"); - - setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:"); - setup_text[eLDAP_Bind_DN] = _( -"Please enter the DN of an account to use for binding to the LDAP server for " -"performing queries. The account does not require any other privileges. If " -"your LDAP server allows anonymous queries, you can leave this blank.\n"); - - setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:"); - setup_text[eLDAP_Bind_PW] = _( -"If you entered a Bind DN in the previous question, you must now enter\n" -"the password associated with that account. Otherwise, you can leave this\n" -"blank.\n"); - -#if 0 -// Debug loading of locales... Strace does a better job though. - printf("Message catalog directory: %s\n", bindtextdomain("citadel-setup", LOCALEDIR"/locale")); - printf("Text domain: %s\n", textdomain("citadel-setup")); - printf("Text domain Charset: %s\n", bind_textdomain_codeset("citadel-setup","UTF8")); - { - int i; - for (i = 0; i < eMaxQuestions; i++) - printf("%s - %s\n", setup_titles[i], _(setup_titles[i])); - exit(0); - } -#endif -} - - -void title(const char *text) { - printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text); -} - - -int yesno(const char *question, int default_value) { - int answer = 0; - char buf[SIZ]; - - do { - printf("%s\n%s [%s] --> ", question, _("Yes/No"), ( default_value ? _("Yes") : _("No") )); - if (fgets(buf, sizeof buf, stdin)) { - answer = tolower(buf[0]); - if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) { - answer = default_value; - } - else if (answer == 'y') { - answer = 1; - } - else if (answer == 'n') { - answer = 0; - } - } - } while ((answer < 0) || (answer > 1)); - return (answer); -} - - -void important_message(const char *title, const char *msgtext) { - char buf[SIZ]; - - printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - printf(" %s \n\n%s\n\n", title, msgtext); - printf("%s", _("Press return to continue...")); - if (fgets(buf, sizeof buf, stdin)) { - ; - } -} - - -void important_msgnum(int msgnum) { - important_message(_("Important Message"), setup_text[msgnum]); -} - - -void display_error(char *error_message_format, ...) { - StrBuf *Msg; - va_list arg_ptr; - - Msg = NewStrBuf(); - va_start(arg_ptr, error_message_format); - StrBufVAppendPrintf(Msg, error_message_format, arg_ptr); - va_end(arg_ptr); - - important_message(_("Error"), ChrPtr(Msg)); - FreeStrBuf(&Msg); -} - - -void progress(char *text, long int curr, long int cmax) { - static long dots_printed = 0L; - long a = 0; - - if (curr == 0) { - printf("%s\n", text); - printf("...................................................."); - printf("..........................\r"); - dots_printed = 0; - } else if (curr == cmax) { - printf("\r%79s\n", ""); - } else { - a = (curr * 100) / cmax; - a = a * 78; - a = a / 100; - while (dots_printed < a) { - printf("*"); - ++dots_printed; - } - } - fflush(stdout); -} - - -int uds_connectsock(char *sockpath) { - int s; - struct sockaddr_un addr; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockpath); - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) { - return(-1); - } - - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(s); - return(-1); - } - - return s; -} - - -/* - * input binary data from socket - */ -void serv_read(char *buf, int bytes) { - int len, rlen; - - len = 0; - while (len < bytes) { - rlen = read(serv_sock, &buf[len], bytes - len); - if (rlen < 1) { - return; - } - len = len + rlen; - } -} - - -/* - * send binary to server - */ -void serv_write(char *buf, int nbytes) { - int bytes_written = 0; - int retval; - while (bytes_written < nbytes) { - retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); - if (retval < 1) { - return; - } - bytes_written = bytes_written + retval; - } -} - - -/* - * input string from socket - implemented in terms of serv_read() - */ -void serv_gets(char *buf) { - int i; - - /* Read one character at a time. - */ - for (i = 0;; i++) { - serv_read(&buf[i], 1); - if (buf[i] == '\n' || i == (SIZ-1)) - break; - } - - /* If we got a long line, discard characters until the newline. - */ - if (i == (SIZ-1)) { - while (buf[i] != '\n') { - serv_read(&buf[i], 1); - } - } - - /* Strip all trailing nonprintables (crlf) - */ - buf[i] = 0; -} - - -/* - * send line to server - implemented in terms of serv_write() - */ -void serv_puts(char *buf) { - serv_write(buf, strlen(buf)); - serv_write("\n", 1); -} - - -/* - * Convenience functions to get/set system configuration entries - */ -void getconf_str(char *buf, char *key) { - char cmd[SIZ]; - char ret[SIZ]; - - sprintf(cmd, "CONF GETVAL|%s", key); - serv_puts(cmd); - serv_gets(ret); - if (ret[0] == '2') { - extract_token(buf, &ret[4], 0, '|', SIZ); - } - else { - strcpy(buf, ""); - } -} - - -int getconf_int(char *key) { - char buf[SIZ]; - getconf_str(buf, key); - return atoi(buf); -} - - -void setconf_str(char *key, char *val) { - char buf[SIZ]; - - sprintf(buf, "CONF PUTVAL|%s|%s", key, val); - serv_puts(buf); - serv_gets(buf); -} - - -void setconf_int(char *key, int val) { - char buf[SIZ]; - - sprintf(buf, "CONF PUTVAL|%s|%d", key, val); - serv_puts(buf); - serv_gets(buf); -} - - -/* - * On systems which use xinetd, see if we can offer to install Citadel as - * the default telnet target. - */ -void check_xinetd_entry(void) -{ - char *filename = "/etc/xinetd.d/telnet"; - FILE *fp; - char buf[SIZ]; - int already_citadel = 0; - int rv; - - fp = fopen(filename, "r+"); - if (fp == NULL) return; /* Not there. Oh well... */ - - while (fgets(buf, sizeof buf, fp) != NULL) { - if (strstr(buf, "/citadel") != NULL) { - already_citadel = 1; - } - } - fclose(fp); - if (already_citadel) return; /* Already set up this way. */ - - /* Otherwise, prompt the user to create an entry. */ - if (getenv("CREATE_XINETD_ENTRY") != NULL) { - if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) { - return; - } - } - else { - snprintf(buf, sizeof buf, - _("Setup can configure the \"xinetd\" service to automatically\n" - "connect incoming telnet sessions to Citadel, bypassing the\n" - "host system login: prompt. Would you like to do this?\n" - ) - ); - if (yesno(buf, 1) == 0) { - return; - } - } - - fp = fopen(filename, "w"); - fprintf(fp, - "# description: telnet service for Citadel users\n" - "service telnet\n" - "{\n" - " disable = no\n" - " flags = REUSE\n" - " socket_type = stream\n" - " wait = no\n" - " user = root\n" - " server = /usr/sbin/in.telnetd\n" - " server_args = -h -L %s/citadel\n" - " log_on_failure += USERID\n" - "}\n", - ctdl_bin_dir - ); - fclose(fp); - - /* Now try to restart the service. This will not have the intended effect on Solaris, but who uses Solaris anymore? */ - rv = system("systemctl restart xinetd >/dev/null 2>&1"); - if (rv != 0) { - rv = system("service xinetd restart >/dev/null 2>&1"); - } - if (rv != 0) { - display_error(_("failed to restart xinetd.\n")); - } -} - - -void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue) -{ - char buf[SIZ] = ""; - char setupmsg[SIZ]; - - strcpy(setupmsg, ""); - - title(prompt_title); - printf("\n%s\n", prompt_text); - printf("%s\n%s\n", _("This is currently set to:"), Target); - printf("%s\n", _("Enter new value or press return to leave unchanged:")); - if (fgets(buf, sizeof buf, stdin)) { - buf[strlen(buf) - 1] = 0; - } - if (!IsEmptyStr(buf)) { - strcpy(Target, buf); - } -} - - -void set_bool_val(int msgpos, int *ip, char *DefValue) { - title(setup_titles[msgpos]); - *ip = yesno(setup_text[msgpos], *ip); -} - - -void set_str_val(int msgpos, char *Target, char *DefValue) -{ - strprompt(setup_titles[msgpos], - setup_text[msgpos], - Target, - DefValue - ); -} - - -/* like set_str_val() but for numeric values */ -void set_int_val(int msgpos, int *target, char *default_value) -{ - char buf[32]; - sprintf(buf, "%d", *target); - do { - set_str_val(msgpos, buf, default_value); - } while ( (strcmp(buf, "0")) && (atoi(buf) == 0) ); - *target = atoi(buf); -} - - -void edit_value(int curr) -{ - struct passwd *pw = NULL; - char ctdluidname[256]; - char buf[SIZ]; - char *default_value = NULL; - int ctdluid = 0; - int portnum = 0; - int auth = 0; - int lportnum = 0; - - if (default_value == NULL) { - default_value = ""; - } - - switch (curr) { - - case eSysAdminName: - getconf_str(admin_name, "c_sysadm"); - set_str_val(curr, admin_name, default_value); - setconf_str("c_sysadm", admin_name); - break; - - case eSysAdminPW: - set_str_val(curr, admin_pass, default_value); - break; - - case eUID: - ctdluid = getconf_int("c_ctdluid"); - pw = getpwuid(ctdluid); - if (pw == NULL) { - set_int_val(curr, &ctdluid, default_value); - } - else { - strcpy(ctdluidname, pw->pw_name); - set_str_val(curr, ctdluidname, default_value); - pw = getpwnam(ctdluidname); - if (pw != NULL) { - ctdluid = pw->pw_uid; - } - else if (atoi(ctdluidname) > 0) { - ctdluid = atoi(ctdluidname); - } - } - setconf_int("c_ctdluid", ctdluid); - break; - - case eIP_ADDR: - getconf_str(buf, "c_ip_addr"); - set_str_val(curr, buf, default_value); - setconf_str("c_ip_addr", buf); - break; - - case eCTDL_Port: - portnum = getconf_int("c_port_number"); - set_int_val(curr, &portnum, default_value); - setconf_int("c_port_number", portnum); - break; - - case eAuthType: - auth = getconf_int("c_auth_mode"); - set_int_val(curr, &auth, default_value); - setconf_int("c_auth_mode", auth); - break; - - case eLDAP_Host: - getconf_str(buf, "c_ldap_host"); - if (IsEmptyStr(buf)) { - strcpy(buf, "localhost"); - } - set_str_val(curr, buf, default_value); - setconf_str("c_ldap_host", buf); - break; - - case eLDAP_Port: - lportnum = getconf_int("c_ldap_port"); - if (lportnum == 0) { - lportnum = 389; - } - set_int_val(curr, &lportnum, default_value); - setconf_int("c_ldap_port", lportnum); - break; - - case eLDAP_Base_DN: - getconf_str(buf, "c_ldap_base_dn"); - set_str_val(curr, buf, default_value); - setconf_str("c_ldap_base_dn", buf); - break; - - case eLDAP_Bind_DN: - getconf_str(buf, "c_ldap_bind_dn"); - set_str_val(curr, buf, default_value); - setconf_str("c_ldap_bind_dn", buf); - break; - - case eLDAP_Bind_PW: - getconf_str(buf, "c_ldap_bind_pw"); - set_str_val(curr, buf, default_value); - setconf_str("c_ldap_bind_pw", buf); - break; - } -} - - -/* - * Messages that are no longer in use. - * We keep them here so we don't lose the translations if we need them later. - */ -#if 0 -important_message(_("Setup finished"), -_("Setup of the Citadel server is complete.\n" -"If you will be using WebCit, please run its\n" -"setup program now; otherwise, run './citadel'\n" -"to log in.\n")); -important_message(_("Setup failed"), -_("Setup is finished, but the Citadel server failed to start.\n" -"Go back and check your configuration.\n"); -important_message(_("Setup finished"), -_("Setup is finished. You may now start the server.")); -#endif - - -int main(int argc, char *argv[]) -{ - int a, i; - int curr; - char buf[1024]; - char aaa[128]; - char ctdldir[PATH_MAX]=CTDLDIR; - struct passwd *pw; - gid_t gid; - char *activity = NULL; - - /* Keep a mild groove on */ - program_title = _("Citadel setup program"); - - /* set an invalid setup type */ - setup_type = (-1); - - /* parse command line args */ - for (a = 0; a < argc; ++a) { - if (!strncmp(argv[a], "-u", 2)) { - strcpy(aaa, argv[a]); - strcpy(aaa, &aaa[2]); - setup_type = atoi(aaa); - } - else if (!strncmp(argv[a], "-h", 2)) { - safestrncpy(ctdldir, &argv[a][2], sizeof ctdldir); - } - } - - if (chdir(ctdldir) != 0) { - fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); - exit(errno); - } - - SetTitles(); - - /* - * Connect to the running Citadel server. - */ - char *connectingmsg = _("Connecting to Citadel server"); - for (i=0; ((i<30) && (serv_sock < 0)) ; ++i) { /* wait for server to start up */ - progress(connectingmsg, i, 30); - serv_sock = uds_connectsock(file_citadel_admin_socket); - sleep(1); - } - progress(connectingmsg, 30, 30); - - if (serv_sock < 0) { - display_error( - "%s: %s %s\n", - _("Setup could not connect to a running Citadel server."), - strerror(errno), file_citadel_admin_socket - ); - exit(1); - } - - /* - * read the server greeting - */ - serv_gets(buf); - if (buf[0] != '2') { - display_error("%s\n", buf); - exit(2); - } - - /* - * Are we connected to the correct Citadel server? - */ - serv_puts("INFO"); - serv_gets(buf); - if (buf[0] != '1') { - display_error("%s\n", buf); - exit(3); - } - a = 0; - while (serv_gets(buf), strcmp(buf, "000")) { - if (a == 5) { - if (atoi(buf) != REV_LEVEL) { - display_error("%s\n", - _("Your setup program and Citadel server are from different versions.") - ); - exit(4); - } - } - ++a; - } - - printf("\n\n\n *** %s ***\n\n", program_title); - - /* Go through a series of dialogs prompting for config info */ - for (curr = 1; curr < eMaxQuestions; ++curr) { - edit_value(curr); - - if ( (curr == eAuthType) - && (getconf_int("c_auth_mode") != AUTHMODE_LDAP) - && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD) - ) { - curr += 5; /* skip LDAP questions if we're not authenticating against LDAP */ - } - - if (curr == eSysAdminName) { - if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { - /* for native auth mode, fetch the admin's existing pw */ - snprintf(buf, sizeof buf, "AGUP %s", admin_name); - serv_puts(buf); - serv_gets(buf); - if (buf[0] == '2') { - extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass); - } - } - else { - ++curr; /* skip the password question for non-native auth modes */ - } - } - } - - if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) { - gid = getgid(); - } else { - gid = pw->pw_gid; - } - - if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) { - display_error("%s\n", _("failed to create directories")); - } - - activity = _("Reconfiguring Citadel server"); - progress(activity, 0, 5); - sleep(1); /* Let the message appear briefly */ - - /* - * Create the administrator account. It's ok if the command fails if this user already exists. - */ - if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { - progress(activity, 1, 5); - snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass); - serv_puts(buf); - progress(activity, 2, 5); - serv_gets(buf); - } - progress(activity, 3, 5); - - /* - * Assign the desired password and access level to the administrator account. - */ - if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { - snprintf(buf, sizeof buf, "AGUP %s", admin_name); - serv_puts(buf); - progress(activity, 4, 5); - serv_gets(buf); - if (buf[0] == '2') { - int admin_flags = extract_int(&buf[4], 2); - int admin_times_called = extract_int(&buf[4], 3); - int admin_msgs_posted = extract_int(&buf[4], 4); - snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6", - admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted - ); - serv_puts(buf); - serv_gets(buf); - } - } - progress(activity, 5, 5); - - check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */ - - /* - * Restart citserver - */ - activity = _("Restarting Citadel server to apply changes"); - progress(activity, 0, 51); - - serv_puts("TIME"); - serv_gets(buf); - long original_start_time = extract_long(&buf[4], 3); - - progress(activity, 1, 51); - serv_puts("DOWN 1"); - progress(activity, 2, 51); - serv_gets(buf); - if (buf[0] != '2') { - display_error("%s\n", buf); - exit(6); - } - - close(serv_sock); - serv_sock = (-1); - - for (i=3; i<=6; ++i) { /* wait for server to shut down */ - progress(activity, i, 51); - sleep(1); - } - - for (i=7; ((i<=48) && (serv_sock < 0)) ; ++i) { /* wait for server to start up */ - progress(activity, i, 51); - serv_sock = uds_connectsock(file_citadel_admin_socket); - sleep(1); - } - - progress(activity, 49, 51); - serv_gets(buf); - - progress(activity, 50, 51); - serv_puts("TIME"); - serv_gets(buf); - long new_start_time = extract_long(&buf[4], 3); - - close(serv_sock); - progress(activity, 51, 51); - - if ((original_start_time == new_start_time) || (new_start_time <= 0)) { - display_error("%s\n", _("Setup failed to restart Citadel server. Please restart it manually.")); - exit(7); - } - - exit(0); - return 0; -} diff --git a/citadel/utils/auth.c b/citadel/utils/auth.c new file mode 100644 index 000000000..ead5f54b5 --- /dev/null +++ b/citadel/utils/auth.c @@ -0,0 +1,136 @@ +// system-level password checking for host auth mode +// by Nathan Bryant, March 1999 +// updated by Trey van Riper, June 2005 +// +// Copyright (c) 1999-2016 by the citadel.org team +// +// This program is open source software. Use, duplication, or disclosure +// is subject to the terms of the GNU General Public License, version 3. +// The program is distributed without any warranty, expressed or implied. + +#if defined(__linux) || defined(__sun) // needed for crypt(): +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +#include +#include +#include +#include +#include + +#include "auth.h" +#include "sysdep.h" + +#ifdef HAVE_GETSPNAM +#include +#endif + +#ifdef HAVE_PAM_START +#include + +// struct appdata: passed to the conversation function +struct appdata { + const char *name; + const char *pw; +}; + +// conv(): the PAM conversation function. this assumes that a +// PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is +// asking for a password. esoteric authentication modules will fail with this +// code, but we can't really support them with the existing client protocol +// anyway. the failure mode should be to deny access, in any case. +static int conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { + struct pam_response *temp_resp; + struct appdata *data = appdata_ptr; + + if ((temp_resp = + malloc(sizeof(struct pam_response[num_msg]))) == NULL) + return PAM_CONV_ERR; + + while (num_msg--) { + switch ((*msg)[num_msg].msg_style) { + case PAM_PROMPT_ECHO_ON: + temp_resp[num_msg].resp = strdup(data->name); + break; + case PAM_PROMPT_ECHO_OFF: + temp_resp[num_msg].resp = strdup(data->pw); + break; + default: + temp_resp[num_msg].resp = NULL; + } + temp_resp[num_msg].resp_retcode = 0; + } + + *resp = temp_resp; + return PAM_SUCCESS; +} +#endif // HAVE_PAM_START + + +// check that `pass' is the correct password for `uid' +// returns zero if no, nonzero if yes +int validate_password(uid_t uid, const char *pass) { + if (pass == NULL) { + return (0); + } +#ifdef HAVE_PAM_START + struct pam_conv pc; + struct appdata data; + pam_handle_t *ph; + int i; +#else + char *crypted_pwd; +#ifdef HAVE_GETSPNAM + struct spwd *sp; +#endif +#endif + struct passwd *pw; + int retval = 0; + + pw = getpwuid(uid); + if (pw == NULL) { + return retval; + } +#ifdef HAVE_PAM_START + +#ifdef PAM_DATA_SILENT + int flags = PAM_DATA_SILENT; +#else + int flags = 0; +#endif + + pc.conv = conv; + pc.appdata_ptr = &data; + data.name = pw->pw_name; + data.pw = pass; + if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS) + return (0); + + if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) { + if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) { + retval = -1; + } + } + + pam_end(ph, i | flags); +#else + crypted_pwd = pw->pw_passwd; + +#ifdef HAVE_GETSPNAM + if (pw == NULL) + return (0); + if (pw->pw_name == NULL) + return (0); + if ((sp = getspnam(pw->pw_name)) != NULL) { + crypted_pwd = sp->sp_pwdp; + } +#endif + + if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) { + retval = -1; + } +#endif // HAVE_PAM_START + + return retval; +} diff --git a/citadel/utils/auth.h b/citadel/utils/auth.h new file mode 100644 index 000000000..d3b0fb803 --- /dev/null +++ b/citadel/utils/auth.h @@ -0,0 +1,2 @@ + +int validate_password(uid_t uid, const char *pass); diff --git a/citadel/utils/axdefs.h b/citadel/utils/axdefs.h new file mode 100644 index 000000000..e92f74171 --- /dev/null +++ b/citadel/utils/axdefs.h @@ -0,0 +1,42 @@ +#ifndef AXDEFS + +char *axdefs[]={ + "Deleted", + "New User", + "Problem User", + "Local User", + "Network User", + "Preferred User", + "Admin", + "Admin" +}; + +#define AXDEFS 1 + +#else + +extern char *axdefs[]; + +#endif + + + + +#ifndef VIEWDEFS + +char *viewdefs[]={ + "Messages", + "Summary", + "Address book", + "Calendar", + "Tasks" +}; + +#define VIEWDEFS 1 + +#else + +extern char *viewdefs[]; + +#endif + diff --git a/citadel/utils/chkpw.c b/citadel/utils/chkpw.c new file mode 100644 index 000000000..83e432fad --- /dev/null +++ b/citadel/utils/chkpw.c @@ -0,0 +1,138 @@ +// +// Copyright (c) 1987-2022 by the citadel.org team +// +// This program is open source software. Use, duplication, or disclosure +// is subject to the terms of the GNU General Public License, version 3. +// The program is distributed without any warranty, expressed or implied. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "citadel.h" +#include "sysdep.h" +#include "citadel_dirs.h" +/* These pipes are used to talk to the chkpwd daemon, which is forked during startup */ +int chkpwd_write_pipe[2]; +int chkpwd_read_pipe[2]; + +/* + * Validate a password on the host unix system by talking to the chkpwd daemon + */ +static int validpw(uid_t uid, const char *pass) +{ + char buf[256]; + int rv; + + rv = write(chkpwd_write_pipe[1], &uid, sizeof(uid_t)); + if (rv == -1) { + printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); + return 0; + } + + rv = write(chkpwd_write_pipe[1], pass, 256); + if (rv == -1) { + printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); + return 0; + } + rv = read(chkpwd_read_pipe[0], buf, 4); + if (rv == -1) { + printf( "Communicatino with chkpwd broken: %s\n", strerror(errno)); + return 0; + } + if (!strncmp(buf, "PASS", 4)) { + printf("pass\n"); + return(1); + } + + printf("fail\n"); + return 0; +} + +/* + * Start up the chkpwd daemon so validpw() has something to talk to + */ +void start_chkpwd_daemon(void) { + pid_t chkpwd_pid; + struct stat filestats; + int i; + + printf("Starting chkpwd daemon for host authentication mode\n"); + + if ((stat(file_chkpwd, &filestats)==-1) || + (filestats.st_size==0)){ + printf("didn't find chkpwd daemon in %s: %s\n", file_chkpwd, strerror(errno)); + abort(); + } + if (pipe(chkpwd_write_pipe) != 0) { + printf("Unable to create pipe for chkpwd daemon: %s\n", strerror(errno)); + abort(); + } + if (pipe(chkpwd_read_pipe) != 0) { + printf("Unable to create pipe for chkpwd daemon: %s\n", strerror(errno)); + abort(); + } + + chkpwd_pid = fork(); + if (chkpwd_pid < 0) { + printf("Unable to fork chkpwd daemon: %s\n", strerror(errno)); + abort(); + } + if (chkpwd_pid == 0) { + dup2(chkpwd_write_pipe[0], 0); + dup2(chkpwd_read_pipe[1], 1); + for (i=2; i<256; ++i) close(i); + execl(file_chkpwd, file_chkpwd, NULL); + printf("Unable to exec chkpwd daemon: %s\n", strerror(errno)); + abort(); + exit(errno); + } +} + + + +int main(int argc, char **argv) { + char buf[256]; + struct passwd *p; + int uid; + + printf("\n\n ** host auth mode test utility **\n\n"); + start_chkpwd_daemon(); + + if (getuid() != 0){ + printf("\n\nERROR: you need to be root to run this!\n\n"); + return(1); + } + while(1) { + printf("\n\nUsername: "); + fgets(buf, sizeof buf, stdin); + buf[strlen(buf)-1] = 0; + p = getpwnam(buf); + if (p == NULL) { + printf("Not found\n"); + } + else { + uid = p->pw_uid; + printf(" uid: %d\n", uid); + printf("Password: "); + fgets(buf, sizeof buf, stdin); + buf[strlen(buf)-1] = 0; + validpw(uid, buf); + } + } + + return(0); +} diff --git a/citadel/utils/chkpwd.c b/citadel/utils/chkpwd.c new file mode 100644 index 000000000..96fed6620 --- /dev/null +++ b/citadel/utils/chkpwd.c @@ -0,0 +1,48 @@ +// +// a setuid helper program for machines which use shadow passwords +// by Nathan Bryant, March 1999 +// +// Copyright (c) 1987-2012 by the citadel.org team +// +// This program is open source software. Use, duplication, or disclosure +// is subject to the terms of the GNU General Public License, version 3. +// The program is distributed without any warranty, expressed or implied. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "auth.h" +#include "config.h" +#include "citadel_dirs.h" +#include "citadel.h" + +int main(void) +{ + uid_t uid; + char buf[SIZ]; + + while (1) { + buf[0] = '\0'; + read(0, &uid, sizeof(uid_t)); /* uid */ + read(0, buf, 256); /* password */ + + if (buf[0] == '\0') + return (0); + if (validate_password(uid, buf)) { + write(1, "PASS", 4); + } + else { + write(1, "FAIL", 4); + } + } + + return(0); +} diff --git a/citadel/utils/citadel.pam b/citadel/utils/citadel.pam new file mode 100644 index 000000000..743c35a4b --- /dev/null +++ b/citadel/utils/citadel.pam @@ -0,0 +1,7 @@ +#%PAM-1.0 +# +# /etc/pam.d/citadel: PAM configuration file for Linux-PAM. +# +auth include system-auth +account include system-auth +session include system-auth diff --git a/citadel/utils/citmail.c b/citadel/utils/citmail.c new file mode 100644 index 000000000..924b67571 --- /dev/null +++ b/citadel/utils/citmail.c @@ -0,0 +1,319 @@ +// This program attempts to act like a local MDA if you're using sendmail or +// some other non-Citadel MTA. It basically just contacts the Citadel LMTP +// listener on a unix domain socket and transmits the message. Really though, +// if your MTA supports LMTP then you definitely should be using that instead. +// +// Copyright (c) 1987-2022 by the citadel.org team +// +// This program is open source software. Use, duplication, or disclosure +// is subject to the terms of the GNU General Public License, version 3. +// The program is distributed without any warranty, expressed or implied. + +#include "sysdep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "citadel.h" +#include "citadel_dirs.h" + +int serv_sock; +int debug = 0; + +void strip_trailing_nonprint(char *buf) { + while ( (!IsEmptyStr(buf)) && (!isprint(buf[strlen(buf) - 1])) ) { + buf[strlen(buf) - 1] = 0; + } +} + + +void timeout(int signum) { + exit(signum); +} + + +int uds_connectsock(char *sockpath) { + int s; + struct sockaddr_un addr; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + fprintf(stderr, "citmail: Can't create socket: %s\n", + strerror(errno)); + exit(3); + } + + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + fprintf(stderr, "citmail: can't connect: %s\n", + strerror(errno)); + close(s); + exit(3); + } + + return s; +} + + +// input binary data from socket +void serv_read(char *buf, int bytes) { + int len, rlen; + + len = 0; + while (len < bytes) { + rlen = read(serv_sock, &buf[len], bytes - len); + if (rlen < 1) { + return; + } + len = len + rlen; + } +} + + +// send binary to server +void serv_write(char *buf, int nbytes) { + int bytes_written = 0; + int retval; + while (bytes_written < nbytes) { + retval = write(serv_sock, &buf[bytes_written], + nbytes - bytes_written); + if (retval < 1) { + return; + } + bytes_written = bytes_written + retval; + } +} + + +// input string from socket - implemented in terms of serv_read() +void serv_gets(char *buf) { + int i; + + // Read one character at a time. + for (i = 0;; i++) { + serv_read(&buf[i], 1); + if (buf[i] == '\n' || i == (SIZ-1)) + break; + } + + // If we got a long line, discard characters until the newline. + if (i == (SIZ-1)) + while (buf[i] != '\n') + serv_read(&buf[i], 1); + + // Strip all trailing nonprintables (crlf) + buf[i] = 0; + strip_trailing_nonprint(buf); + if (debug) fprintf(stderr, "> %s\n", buf); +} + + +// send line to server - implemented in terms of serv_write() +void serv_puts(char *buf) { + if (debug) fprintf(stderr, "< %s\n", buf); + serv_write(buf, strlen(buf)); + serv_write("\n", 1); +} + + +void cleanup(int exitcode) { + char buf[1024]; + + if (exitcode != 0) { + fprintf(stderr, "citmail: error #%d occurred while sending mail.\n", exitcode); + fprintf(stderr, "Please check your Citadel configuration.\n"); + } + serv_puts("QUIT"); + serv_gets(buf); + exit(exitcode); +} + + +int main(int argc, char **argv) { + char buf[1024]; + char fromline[1024]; + FILE *fp; + int i; + struct passwd *pw; + int from_header = 0; + int in_body = 0; + char ctdldir[PATH_MAX]=CTDLDIR; + char *sp, *ep; + char hostname[256]; + char **recipients = NULL; + int num_recipients = 0; + int to_or_cc = 0; + int read_recipients_from_headers = 0; + char *add_these_recipients = NULL; + + for (i=1; ipw_name, hostname); + while (fgets(buf, 1024, stdin) != NULL) { + if ( ( (buf[0] == 13) || (buf[0] == 10)) && (in_body == 0) ) { + in_body = 1; + if (from_header == 0) { + fprintf(fp, "%s%s", fromline, buf); + } + } + if (in_body == 0 && !strncasecmp(buf, "From:", 5)) { + strcpy(fromline, buf); + from_header = 1; + } + + if (read_recipients_from_headers) { + add_these_recipients = NULL; + if ((isspace(buf[0])) && (to_or_cc)) { + add_these_recipients = buf; + } + else { + if ((!strncasecmp(buf, "To:", 3)) || (!strncasecmp(buf, "Cc:", 3))) { + to_or_cc = 1; + } + else { + to_or_cc = 0; + } + if (to_or_cc) { + add_these_recipients = &buf[3]; + } + } + + if (add_these_recipients) { + int num_recp_on_this_line; + char this_recp[256]; + + num_recp_on_this_line = num_tokens(add_these_recipients, ','); + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "citadel.h" +#include "axdefs.h" +#include "sysdep.h" +#include "config.h" +#include "citadel_dirs.h" + + +// support for getz() -- (globals would not be appropriate in a multithreaded program) +static int gmaxlen = 0; +static char *gdeftext = NULL; + + +// support function for getz() +static int limit_rl(FILE *dummy) { + if (rl_end > gmaxlen) { + return '\b'; + } + return rl_getc(dummy); +} + + +// support function for getz() +static int getz_deftext(void) { + if (gdeftext) { + rl_insert_text(gdeftext); + gdeftext = NULL; + rl_startup_hook = NULL; + } + return 0; +} + + +// Replacement for gets() that uses libreadline. +void getz(char *buf, int maxlen, char *default_value, char *prompt) { + rl_startup_hook = getz_deftext; + rl_getc_function = limit_rl; + gmaxlen = maxlen; + gdeftext = default_value; + strcpy(buf, readline(prompt)); +} + + +// Exit from the program while displaying an error code +void ctdlmigrate_exit(int cmdexit) { + printf("\n\n\033[3%dmExit code %d\033[0m\n", (cmdexit ? 1 : 2), cmdexit); + exit(cmdexit); +} + + +// Connect to a Citadel on a remote host using a TCP/IP socket +static 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 sock = (-1); + + if ((host == NULL) || IsEmptyStr(host)) { + return(-1); + } + if ((service == NULL) || IsEmptyStr(service)) { + return(-1); + } + + 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) { + fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); + 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) { + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); + return (-1); + } + + rc = connect(sock, ai->ai_addr, ai->ai_addrlen); + if (rc >= 0) { + return (sock); // Connected! + } + else { + fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno)); + close(sock); // Failed. Close the socket to avoid fd leak! + } + } + return (-1); +} + + +// Connect to a Citadel on a remote host using a unix domaion socket +int uds_connectsock(char *sockpath) { + int s; + struct sockaddr_un addr; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + fprintf(stderr, "ctdlmigrate: Can't create socket: %s\n", strerror(errno)); + return(-1); + } + + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + fprintf(stderr, "ctdlmigrate: can't connect: %s\n", strerror(errno)); + close(s); + return(-1); + } + + return s; +} + + +// input binary data from socket +void serv_read(int serv_sock, char *buf, int bytes) { + int len = 0; + int rlen = 0; + + while (len < bytes) { + rlen = read(serv_sock, &buf[len], bytes - len); + if (rlen < 1) { + return; + } + len = len + rlen; + } +} + + +// send binary to server +void serv_write(int serv_sock, char *buf, int nbytes) { + int bytes_written = 0; + int retval; + while (bytes_written < nbytes) { + retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); + if (retval < 1) { + return; + } + bytes_written = bytes_written + retval; + } +} + + +// input string from socket - implemented in terms of serv_read() +void serv_gets(int serv_sock, char *buf) { + int i; + + // Read one character at a time. + for (i = 0;; i++) { + serv_read(serv_sock, &buf[i], 1); + if (buf[i] == '\n' || i == (SIZ-1)) + break; + } + + // If we got a long line, discard characters until the newline. + if (i == (SIZ-1)) { + while (buf[i] != '\n') { + serv_read(serv_sock, &buf[i], 1); + } + } + + // Strip all trailing nonprintables (crlf) + buf[i] = 0; +} + + +// send line to server - implemented in terms of serv_write() +void serv_puts(int serv_sock, char *buf) { + serv_write(serv_sock, buf, strlen(buf)); + serv_write(serv_sock, "\n", 1); +} + + +// send formatted printable data to the server +void serv_printf(int serv_sock, const char *format, ...) { + va_list arg_ptr; + char buf[1024]; + + va_start(arg_ptr, format); + if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1) + buf[sizeof buf - 2] = '\n'; + serv_write(serv_sock, buf, strlen(buf)); + va_end(arg_ptr); +} + + +// You know what main() does. If you don't, you shouldn't be trying to understand this program. +int main(int argc, char *argv[]) { + char ctdldir[PATH_MAX]=CTDLDIR; + char yesno[2]; + int cmdexit = 0; // when something fails, set cmdexit to nonzero, and skip to the end + char buf[PATH_MAX]; + + char remote_user[128]; + char remote_host[128]; + char remote_pass[128]; + char *remote_port = "504"; + + int linecount = 0; + int a; + int remote_server_socket = (-1); + int local_admin_socket = (-1); + int progress = 0; + + // Parse command line + while ((a = getopt(argc, argv, "h:")) != EOF) { + switch (a) { + case 'h': + strcpy(ctdldir, optarg); + break; + default: + fprintf(stderr, "ctdlmigrate: usage: ctdlmigrate [-h server_dir]\n"); + return(1); + } + } + + if (chdir(ctdldir) != 0) { + fprintf(stderr, "ctdlmigrate: %s: %s\n", ctdldir, strerror(errno)); + exit(errno); + } + + signal(SIGINT, ctdlmigrate_exit); + signal(SIGQUIT, ctdlmigrate_exit); + signal(SIGTERM, ctdlmigrate_exit); + signal(SIGSEGV, ctdlmigrate_exit); + signal(SIGHUP, ctdlmigrate_exit); + signal(SIGPIPE, ctdlmigrate_exit); + + printf( "\033[2J\033[H\n" + " \033[32m╔═══════════════════════════════════════════════╗\n" + " ║ ║\n" + " ║ \033[33mCitadel over-the-wire migration utility \033[32m║\n" + " ║ ║\n" + " ╚═══════════════════════════════════════════════╝\033[0m\n" + "\n" + "This utility is designed to migrate your Citadel installation\n" + "to a new host system via a network connection, without disturbing\n" + "the source system. The target may be a different CPU architecture\n" + "and/or operating system. The source system should be running\n" + "Citadel version \033[33m%d\033[0m or newer, and the target system should be running\n" + "either the same version or a newer version.\n" + "\n" + "You must run this utility on the TARGET SYSTEM. Any existing data\n" + "on this system will be ERASED. Your target system will be on this\n" + "host in %s.\n" + "\n", + EXPORT_REV_MIN, ctdldir + ); + + getz(yesno, 1, NULL, "Do you wish to continue? "); + puts(yesno); + if (tolower(yesno[0]) != 'y') { + cmdexit = 101; + } + + if (!cmdexit) { + printf( "\033[2J\033[H\n" + "\033[32m╔═══════════════════════════════════════════════╗\n" + "║ ║\n" + "║ \033[33mValidate source and target systems\033[32m ║\n" + "║ ║\n" + "╚═══════════════════════════════════════════════╝\033[0m\n" + "\n\n"); + + printf("First we must validate that the local target system is running\n"); + printf("and ready to receive data.\n"); + printf("Checking connectivity to Citadel in %s...\n", ctdldir); + local_admin_socket = uds_connectsock("citadel-admin.socket"); + if (local_admin_socket < 0) { + cmdexit = 102; + } + } + + if (!cmdexit) { + serv_gets(local_admin_socket, buf); + puts(buf); + if (buf[0] != '2') { + cmdexit = 103; + } + } + + if (!cmdexit) { + serv_puts(local_admin_socket, "ECHO Connection to Citadel Server succeeded."); + serv_gets(local_admin_socket, buf); + puts(buf); + if (buf[0] != '2') { + cmdexit = 104; + } + } + + if (!cmdexit) { + printf("\n"); + printf("OK, this side is ready to go. Now we must connect to the source system.\n\n"); + + getz(remote_host, sizeof remote_host, NULL, "Enter the name or IP address of the source system: "); + getz(remote_user, sizeof remote_user, "admin", " Enter the user name of an administrator account: "); + getz(remote_pass, sizeof remote_pass, NULL, " Enter the password for this account: "); + + remote_server_socket = tcp_connectsock(remote_host, remote_port); + if (remote_server_socket < 0) { + cmdexit = 105; + } + } + + if (!cmdexit) { + serv_gets(remote_server_socket, buf); + puts(buf); + if (buf[0] != '2') { + cmdexit = 106; + } + } + + if (!cmdexit) { + serv_printf(remote_server_socket, "USER %s\n", remote_user); + serv_gets(remote_server_socket, buf); + puts(buf); + if (buf[0] != '3') { + cmdexit = 107; + } + } + + if (!cmdexit) { + serv_printf(remote_server_socket, "PASS %s\n", remote_pass); + serv_gets(remote_server_socket, buf); + puts(buf); + if (buf[0] != '2') { + cmdexit = 108; + } + } + + if (!cmdexit) { + printf( "\033[2J\033[H\n" + "\033[32m╔═══════════════════════════════════════════════════════════════════╗\n" + "║ ║\n" + "║ \033[33mMigrating from: %-50s\033[32m║\n" + "║ ║\n" + "╠═══════════════════════════════════════════════════════════════════╣\n" + "║ ║\n" + "║ Lines received: 0 Percent complete: 0 ║\n" + "║ ║\n" + "╚═══════════════════════════════════════════════════════════════════╝\033[0m\n" + "\n", remote_host + ); + } + + if (!cmdexit) { + serv_puts(remote_server_socket, "MIGR export"); + serv_gets(remote_server_socket, buf); + if (buf[0] != '1') { + printf("\n\033[31m%s\033[0m\n", buf); + cmdexit = 109; + } + } + + if (!cmdexit) { + serv_puts(local_admin_socket, "MIGR import"); + serv_gets(local_admin_socket, buf); + if (buf[0] != '4') { + printf("\n\033[31m%s\033[0m\n", buf); + cmdexit = 110; + } + } + + if (!cmdexit) { + char *ptr; + time_t last_update = time(NULL); + + while (serv_gets(remote_server_socket, buf), strcmp(buf, "000")) { + ptr = strchr(buf, '\n'); + if (ptr) *ptr = 0; // remove the newline character + ++linecount; + if (!strncasecmp(buf, "", 10)) { + progress = atoi(&buf[10]); + printf("\033[8;65H\033[33m%d\033[0m\033[12;0H\n", progress); + } + if (time(NULL) != last_update) { + last_update = time(NULL); + printf("\033[8;19H\033[33m%d\033[0m\033[12;0H\n", linecount); + } + serv_puts(local_admin_socket, buf); + } + + serv_puts(local_admin_socket, "000"); + } + + if ( (cmdexit == 0) && (progress < 100) ) { + printf("\033[31mERROR: source stream ended before 100 percent of data was received.\033[0m\n"); + cmdexit = 111; + } + + if (!cmdexit) { + printf("\033[36mMigration is complete. Restarting the target server.\033[0m\n"); + serv_puts(local_admin_socket, "DOWN 1"); + serv_gets(local_admin_socket, buf); + puts(buf); + printf("\033[36mIt is recommended that you shut down the source server now.\033[0m\n"); + printf("\033[36mRemember to copy over your SSL keys and file libraries if appropriate.\033[0m\n"); + } + + close(remote_server_socket); + close(local_admin_socket); + ctdlmigrate_exit(cmdexit); +} diff --git a/citadel/utils/database_cleanup.sh b/citadel/utils/database_cleanup.sh new file mode 100755 index 000000000..765494679 --- /dev/null +++ b/citadel/utils/database_cleanup.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +die () { + echo Exiting. + exit 1 +} + +DATA_DIR="/usr/local/citadel" + +usage() { + echo "Usage: database_cleanup.sh [ -h citadel_dir ]" + exit 2 +} + +PARSED_ARGUMENTS=$(getopt -a -n database_cleanup.sh -o h: -- "$@") +VALID_ARGUMENTS=$? +if [ "$VALID_ARGUMENTS" != "0" ]; then + usage +fi + +eval set -- "$PARSED_ARGUMENTS" +while : +do + case "$1" in + -h | --alpha) + DATA_DIR=${2} + shift 2 + ;; + # -- means the end of the arguments; drop this, and break out of the while loop + --) shift; break ;; + # If invalid options were passed, then getopt should have reported an error, + # which we checked as VALID_ARGUMENTS when getopt was called... + *) echo "Unexpected option: $1 - this should not happen." + usage + ;; + esac +done + +DATA_DIR=$DATA_DIR/data + +# If we're on a Docker or Easy Install system, use our own db_ tools. +if [ -x /usr/local/ctdlsupport/bin/db_dump ] ; then + export PATH=/usr/local/ctdlsupport/bin:$PATH + RECOVER=/usr/local/ctdlsupport/bin/db_recover + DUMP=/usr/local/ctdlsupport/bin/db_dump + LOAD=/usr/local/ctdlsupport/bin/db_load + +# otherwise look in /usr/local +elif [ -x /usr/local/bin/db_dump ] ; then + export PATH=/usr/local/bin:$PATH + RECOVER=/usr/local/bin/db_recover + DUMP=/usr/local/bin/db_dump + LOAD=/usr/local/bin/db_load + +# usual install +else + if test -f /usr/bin/db_dump; then + RECOVER=/usr/bin/db_recover + DUMP=/usr/bin/db_dump + LOAD=/usr/bin/db_load + else + if test -n "`ls /usr/bin/db?*recover`"; then + # seems we have something debian alike thats adding version in the filename + if test "`ls /usr/bin/db*recover |wc -l`" -gt "1"; then + echo "Warning: you have more than one version of the Berkeley DB utilities installed." 1>&2 + echo "Using the latest one." 1>&2 + RECOVER=`ls /usr/bin/db*recover |sort |tail -n 1` + DUMP=`ls /usr/bin/db*dump |sort |tail -n 1` + LOAD=`ls /usr/bin/db*load |sort |tail -n 1` + else + RECOVER=`ls /usr/bin/db*recover` + DUMP=`ls /usr/bin/db*dump` + LOAD=`ls /usr/bin/db*load` + fi + else + echo "database_cleanup.sh cannot find the Berkeley DB utilities. Exiting." 1>&2 + die + fi + + fi +fi + +# Ok, let's begin. + +clear +cat </tmp/CitaDump.$x || { + echo error $? + die + } + rm -vf $DATA_DIR/$filename +done + +echo Removing old databases +rm -vf $DATA_DIR/* + +for x in 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d +do + filename=cdb.$x + echo Loading $filename + $LOAD -h $DATA_DIR $filename /dev/null 2>/dev/null || exit 1 + +# this check will find the timezone if /etc/localtime is a link to the right timezone file +# or that file has been copied to /etc/localtime and not changed afterwards +LOCALTIMESUM=`md5sum /etc/localtime | awk ' { print $1 } ' 2>/dev/null` +find /usr/share/zoneinfo -type f -print | while read filename +do + THISTIMESUM=`md5sum $filename | awk ' { print $1 } '` + if [ $LOCALTIMESUM = $THISTIMESUM ] ; then + echo $filename | cut -c21- + exit 0 + fi +done 2>/dev/null + +# seems we haven't found the timezone yet, let's see whether /etc/timezone has some info + +if [ -e /etc/timezone ]; then + TIMEZONE="$(head -n 1 /etc/timezone)" + TIMEZONE="${TIMEZONE%% *}" + TIMEZONE="${TIMEZONE##/}" + TIMEZONE="${TIMEZONE%%/}" + TIMEZONE="$(convert_timezone $TIMEZONE)" + if [ -f "/usr/share/zoneinfo/$TIMEZONE" ] ; then + echo $TIMEZONE + exit 0 + fi +fi + +exit 2 diff --git a/citadel/utils/sendcommand.c b/citadel/utils/sendcommand.c new file mode 100644 index 000000000..bd87ff3b4 --- /dev/null +++ b/citadel/utils/sendcommand.c @@ -0,0 +1,222 @@ +/* + * Command-line utility to transmit a server command. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "citadel.h" +#include "citadel_dirs.h" +#include + +int serv_sock = (-1); + +int uds_connectsock(char *sockpath) { + int s; + struct sockaddr_un addr; + + 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) { + fprintf(stderr, "sendcommand: Can't create socket: %s\n", strerror(errno)); + exit(3); + } + + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + fprintf(stderr, "sendcommand: can't connect: %s\n", strerror(errno)); + close(s); + exit(3); + } + + return s; +} + + +/* + * input binary data from socket + */ +void serv_read(char *buf, int bytes) { + int len, rlen; + + len = 0; + while (len < bytes) { + rlen = read(serv_sock, &buf[len], bytes - len); + if (rlen < 1) { + return; + } + len = len + rlen; + } +} + + +/* + * send binary to server + */ +void serv_write(char *buf, int nbytes) { + int bytes_written = 0; + int retval; + while (bytes_written < nbytes) { + retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); + if (retval < 1) { + return; + } + bytes_written = bytes_written + retval; + } +} + + +/* + * input string from socket - implemented in terms of serv_read() + */ +void serv_gets(char *buf) { + int i; + + /* Read one character at a time. + */ + for (i = 0;; i++) { + serv_read(&buf[i], 1); + if (buf[i] == '\n' || i == (SIZ-1)) + break; + } + + /* If we got a long line, discard characters until the newline. + */ + if (i == (SIZ-1)) { + while (buf[i] != '\n') { + serv_read(&buf[i], 1); + } + } + + /* Strip all trailing nonprintables (crlf) + */ + buf[i] = 0; +} + + +/* + * send line to server - implemented in terms of serv_write() + */ +void serv_puts(char *buf) { + serv_write(buf, strlen(buf)); + serv_write("\n", 1); +} + + +/* + * Main loop. Do things and have fun. + */ +int main(int argc, char **argv) { + int a; + int watchdog = 60; + char buf[SIZ]; + int xfermode = 0; + char ctdldir[PATH_MAX]=CTDLDIR; + + /* Parse command line */ + while ((a = getopt(argc, argv, "h:w:")) != EOF) { + switch (a) { + case 'h': + strncpy(ctdldir, optarg, sizeof ctdldir); + break; + case 'w': + watchdog = atoi(optarg); + break; + default: + fprintf(stderr, "sendcommand: usage: sendcommand [-h server_dir] [-w watchdog_timeout]\n"); + return(1); + } + } + + fprintf(stderr, "sendcommand: started (pid=%d) connecting to Citadel server with data directory %s\n", + (int) getpid(), + ctdldir + ); + fflush(stderr); + + if (chdir(ctdldir) != 0) { + fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); + exit(errno); + } + + alarm(watchdog); + serv_sock = uds_connectsock(file_citadel_admin_socket); + serv_gets(buf); + fprintf(stderr, "%s\n", buf); + + strcpy(buf, ""); + for (a=optind; a 0) { + if (buf[strlen(buf)-1] == '\n') { + buf[strlen(buf)-1] = 0; + } + serv_puts(buf); + } + serv_puts("000"); + } + + if ((xfermode == '1') || (xfermode == '8')) { /* receive text */ + while(serv_gets(buf), strcmp(buf, "000")) { + printf("%s\n", buf); + } + } + + if (xfermode == '6') { /* receive binary */ + size_t len = atoi(&buf[4]); + size_t bytes_remaining = len; + + while (bytes_remaining > 0) { + size_t this_block = bytes_remaining; + if (this_block > SIZ) this_block = SIZ; + serv_read(buf, this_block); + fwrite(buf, this_block, 1, stdout); + bytes_remaining -= this_block; + } + } + + close(serv_sock); + alarm(0); /* cancel the watchdog timer */ + + fprintf(stderr, "sendcommand: processing ended.\n"); + if (xfermode == '5') { + return(1); + } + return(0); +} diff --git a/citadel/utils/setup.c b/citadel/utils/setup.c new file mode 100644 index 000000000..dbcd2a301 --- /dev/null +++ b/citadel/utils/setup.c @@ -0,0 +1,871 @@ +// Citadel setup utility +// +// 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. +// +// 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. + +#define SHOW_ME_VAPPEND_PRINTF +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server/citadel.h" +#include "axdefs.h" +#include "../server/sysdep.h" +#include "../server/citadel_dirs.h" + +#ifdef ENABLE_NLS +#ifdef HAVE_XLOCALE_H +#include +#endif +#include +#include +#define _(string) gettext(string) +#else +#define _(string) (string) +#endif + +#define SERVICE_NAME "citadel" +#define PROTO_NAME "tcp" +#define NSSCONF "/etc/nsswitch.conf" + +typedef enum _SetupStep { + eCitadelHomeDir = 0, + eSysAdminName = 1, + eSysAdminPW = 2, + eUID = 3, + eIP_ADDR = 4, + eCTDL_Port = 5, + eAuthType = 6, + eLDAP_Host = 7, + eLDAP_Port = 8, + eLDAP_Base_DN = 9, + eLDAP_Bind_DN = 10, + eLDAP_Bind_PW = 11, + eMaxQuestions = 12 +} eSetupStep; + +///"CREATE_XINETD_ENTRY"; +/* Environment variables, don't translate! */ +const char *EnvNames [eMaxQuestions] = { + "HOME_DIRECTORY", + "SYSADMIN_NAME", + "SYSADMIN_PW", + "CITADEL_UID", + "IP_ADDR", + "CITADEL_PORT", + "ENABLE_UNIX_AUTH", + "LDAP_HOST", + "LDAP_PORT", + "LDAP_BASE_DN", + "LDAP_BIND_DN", + "LDAP_BIND_PW" +}; + +int setup_type = (-1); +int enable_home = 1; +char admin_name[SIZ]; +char admin_pass[SIZ]; +char admin_cmd[SIZ]; +int serv_sock = (-1) ; + +const char *setup_titles[eMaxQuestions]; +const char *setup_text[eMaxQuestions]; + +char *program_title; + +void SetTitles(void) { + int have_run_dir; +#ifndef HAVE_RUN_DIR + have_run_dir = 1; +#else + have_run_dir = 0; +#endif + +#ifdef ENABLE_NLS + setlocale(LC_MESSAGES, getenv("LANG")); + bindtextdomain("citadel-setup", LOCALEDIR"/locale"); + textdomain("citadel-setup"); + bind_textdomain_codeset("citadel-setup","UTF8"); +#endif + + setup_titles[eCitadelHomeDir] = _("Citadel Home Directory"); + if (have_run_dir) + setup_text[eCitadelHomeDir] = _( +"Enter the full pathname of the directory in which the Citadel\n" +"installation you are creating or updating resides. If you\n" +"specify a directory other than the default, you will need to\n" +"specify the -h flag to the server when you start it up.\n"); + else + setup_text[eCitadelHomeDir] = _( +"Enter the subdirectory name for an alternate installation of " +"Citadel. To do a default installation just leave it blank." +"If you specify a directory other than the default, you will need to\n" +"specify the -h flag to the server when you start it up.\n" +"note that it may not have a leading /"); + + setup_titles[eSysAdminName] = _("Citadel administrator username:"); + setup_text[eSysAdminName] = _( +"Please enter the name of the Citadel user account that should be granted " +"administrative privileges once created. If using internal authentication " +"this user account will be created if it does not exist. For external " +"authentication this user account has to exist."); + + setup_titles[eSysAdminPW] = _("Administrator password:"); + setup_text[eSysAdminPW] = _( +"Enter a password for the system administrator. When setup\n" +"completes it will attempt to create the administrator user\n" +"and set the password specified here.\n"); + + setup_titles[eUID] = _("Citadel User ID:"); + setup_text[eUID] = _( +"Citadel needs to run under its own user ID. This would\n" +"typically be called \"citadel\", but if you are running Citadel\n" +"as a public site, you might also call it \"bbs\" or \"guest\".\n" +"The server will run under this user ID. Please specify that\n" +"user ID here. You may specify either a user name or a numeric\n" +"UID.\n"); + + setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:"); + setup_text[eIP_ADDR] = _( +"Please specify the IP address which the server should be listening to. " +"You can name a specific IPv4 or IPv6 address, or you can specify\n" +"\"*\" for \"any address\", \"::\" for \"any IPv6 address\", or \"0.0.0.0\"\n" +"for \"any IPv4 address\". If you leave this blank, Citadel will\n" +"listen on all addresses. " +"This can usually be left to the default unless multiple instances of Citadel " +"are running on the same computer."); + + setup_titles[eCTDL_Port] = _("Server port number:"); + setup_text[eCTDL_Port] = _( +"Specify the TCP port number on which your server will run.\n" +"Normally, this will be port 504, which is the official port\n" +"assigned by the IANA for Citadel servers. You will only need\n" +"to specify a different port number if you run multiple instances\n" +"of Citadel on the same computer and there is something else\n" +"already using port 504.\n"); + + setup_titles[eAuthType] = _("Authentication method to use:"); + setup_text[eAuthType] = _( +"Please choose the user authentication mode. By default Citadel will use its " +"own internal user accounts database. If you choose Host, Citadel users will " +"have accounts on the host system, authenticated via /etc/passwd or a PAM " +"source. LDAP chooses an RFC 2307 compliant directory server, the last option " +"chooses the nonstandard MS Active Directory LDAP scheme." +"\n" +"Do not change this option unless you are sure it is required, since changing " +"back requires a full reinstall of Citadel." +"\n" +" 0. Self contained authentication\n" +" 1. Host system integrated authentication\n" +" 2. External LDAP - RFC 2307 POSIX schema\n" +" 3. External LDAP - MS Active Directory schema\n" +"\n" +"For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n" +"\n" +"ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n"); + + setup_titles[eLDAP_Host] = _("LDAP host:"); + setup_text[eLDAP_Host] = _( +"Please enter the host name or IP address of your LDAP server.\n"); + + setup_titles[eLDAP_Port] = _("LDAP port number:"); + setup_text[eLDAP_Port] = _( +"Please enter the port number of the LDAP service (usually 389).\n"); + + setup_titles[eLDAP_Base_DN] = _("LDAP base DN:"); + setup_text[eLDAP_Base_DN] = _( +"Please enter the Base DN to search for authentication\n" +"(for example: dc=example,dc=com)\n"); + + setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:"); + setup_text[eLDAP_Bind_DN] = _( +"Please enter the DN of an account to use for binding to the LDAP server for " +"performing queries. The account does not require any other privileges. If " +"your LDAP server allows anonymous queries, you can leave this blank.\n"); + + setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:"); + setup_text[eLDAP_Bind_PW] = _( +"If you entered a Bind DN in the previous question, you must now enter\n" +"the password associated with that account. Otherwise, you can leave this\n" +"blank.\n"); + +#if 0 +// Debug loading of locales... Strace does a better job though. + printf("Message catalog directory: %s\n", bindtextdomain("citadel-setup", LOCALEDIR"/locale")); + printf("Text domain: %s\n", textdomain("citadel-setup")); + printf("Text domain Charset: %s\n", bind_textdomain_codeset("citadel-setup","UTF8")); + { + int i; + for (i = 0; i < eMaxQuestions; i++) + printf("%s - %s\n", setup_titles[i], _(setup_titles[i])); + exit(0); + } +#endif +} + + +void title(const char *text) { + printf("\n\033[1m\033[32m<\033[33m%s\033[32m>\033[0m\n", text); +} + + +int yesno(const char *question, int default_value) { + int answer = 0; + char buf[SIZ]; + + do { + printf("%s\n%s [%s] --> ", question, _("Yes/No"), ( default_value ? _("Yes") : _("No") )); + if (fgets(buf, sizeof buf, stdin)) { + answer = tolower(buf[0]); + if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) { + answer = default_value; + } + else if (answer == 'y') { + answer = 1; + } + else if (answer == 'n') { + answer = 0; + } + } + } while ((answer < 0) || (answer > 1)); + return (answer); +} + + +void important_message(const char *title, const char *msgtext) { + char buf[SIZ]; + + printf("\n%s\n%s\n\n", title, msgtext); + printf("%s", _("Press return to continue...")); + if (fgets(buf, sizeof buf, stdin)) { + ; + } +} + + +void important_msgnum(int msgnum) { + important_message(_("Important Message"), setup_text[msgnum]); +} + + +void display_error(char *error_message_format, ...) { + StrBuf *Msg; + va_list arg_ptr; + + Msg = NewStrBuf(); + va_start(arg_ptr, error_message_format); + StrBufVAppendPrintf(Msg, error_message_format, arg_ptr); + va_end(arg_ptr); + + important_message(_("Error"), ChrPtr(Msg)); + FreeStrBuf(&Msg); +} + + +void progress(char *text, long int curr, long int cmax) { + long a = 0; + long i = 0; + + if (curr == 0) { + printf("%s\n", text); + printf("\033[1m\033[33m[\033[32m............................................................................\033[33m]\033[0m\r"); + } + else if (curr == cmax) { + printf("\r%79s\n", ""); + } + else { + printf("\033[1m\033[33m[\033[32m"); + a = (curr * 100) / cmax; + a = a * 76; + a = a / 100; + for (i=0; i/dev/null 2>&1"); + if (rv != 0) { + rv = system("service xinetd restart >/dev/null 2>&1"); + } + if (rv != 0) { + display_error(_("failed to restart xinetd.\n")); + } +} + + +void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue) { + char buf[SIZ] = ""; + char setupmsg[SIZ]; + + strcpy(setupmsg, ""); + + title(prompt_title); + printf("\n%s\n", prompt_text); + printf("%s\n%s\n", _("This is currently set to:"), Target); + printf("%s\n", _("Enter new value or press return to leave unchanged:")); + if (fgets(buf, sizeof buf, stdin)) { + buf[strlen(buf) - 1] = 0; + } + if (!IsEmptyStr(buf)) { + strcpy(Target, buf); + } +} + + +void set_bool_val(int msgpos, int *ip, char *DefValue) { + title(setup_titles[msgpos]); + *ip = yesno(setup_text[msgpos], *ip); +} + + +void set_str_val(int msgpos, char *Target, char *DefValue) +{ + strprompt(setup_titles[msgpos], + setup_text[msgpos], + Target, + DefValue + ); +} + + +// like set_str_val() but for numeric values +void set_int_val(int msgpos, int *target, char *default_value) { + char buf[32]; + sprintf(buf, "%d", *target); + do { + set_str_val(msgpos, buf, default_value); + } while ( (strcmp(buf, "0")) && (atoi(buf) == 0) ); + *target = atoi(buf); +} + + +void edit_value(int curr) { + struct passwd *pw = NULL; + char ctdluidname[256]; + char buf[SIZ]; + char *default_value = NULL; + int ctdluid = 0; + int portnum = 0; + int auth = 0; + int lportnum = 0; + + if (default_value == NULL) { + default_value = ""; + } + + switch (curr) { + + case eSysAdminName: + getconf_str(admin_name, "c_sysadm"); + set_str_val(curr, admin_name, default_value); + setconf_str("c_sysadm", admin_name); + break; + + case eSysAdminPW: + set_str_val(curr, admin_pass, default_value); + break; + + case eUID: + ctdluid = getconf_int("c_ctdluid"); + pw = getpwuid(ctdluid); + if (pw == NULL) { + set_int_val(curr, &ctdluid, default_value); + } + else { + strcpy(ctdluidname, pw->pw_name); + set_str_val(curr, ctdluidname, default_value); + pw = getpwnam(ctdluidname); + if (pw != NULL) { + ctdluid = pw->pw_uid; + } + else if (atoi(ctdluidname) > 0) { + ctdluid = atoi(ctdluidname); + } + } + setconf_int("c_ctdluid", ctdluid); + break; + + case eIP_ADDR: + getconf_str(buf, "c_ip_addr"); + set_str_val(curr, buf, default_value); + setconf_str("c_ip_addr", buf); + break; + + case eCTDL_Port: + portnum = getconf_int("c_port_number"); + set_int_val(curr, &portnum, default_value); + setconf_int("c_port_number", portnum); + break; + + case eAuthType: + auth = getconf_int("c_auth_mode"); + set_int_val(curr, &auth, default_value); + setconf_int("c_auth_mode", auth); + break; + + case eLDAP_Host: + getconf_str(buf, "c_ldap_host"); + if (IsEmptyStr(buf)) { + strcpy(buf, "localhost"); + } + set_str_val(curr, buf, default_value); + setconf_str("c_ldap_host", buf); + break; + + case eLDAP_Port: + lportnum = getconf_int("c_ldap_port"); + if (lportnum == 0) { + lportnum = 389; + } + set_int_val(curr, &lportnum, default_value); + setconf_int("c_ldap_port", lportnum); + break; + + case eLDAP_Base_DN: + getconf_str(buf, "c_ldap_base_dn"); + set_str_val(curr, buf, default_value); + setconf_str("c_ldap_base_dn", buf); + break; + + case eLDAP_Bind_DN: + getconf_str(buf, "c_ldap_bind_dn"); + set_str_val(curr, buf, default_value); + setconf_str("c_ldap_bind_dn", buf); + break; + + case eLDAP_Bind_PW: + getconf_str(buf, "c_ldap_bind_pw"); + set_str_val(curr, buf, default_value); + setconf_str("c_ldap_bind_pw", buf); + break; + } +} + + +// Messages that are no longer in use. +// We keep them here so we don't lose the translations if we need them later. +#if 0 +important_message(_("Setup finished"), +_("Setup of the Citadel server is complete.\n" +"If you will be using WebCit, please run its\n" +"setup program now; otherwise, run './citadel'\n" +"to log in.\n")); +important_message(_("Setup failed"), +_("Setup is finished, but the Citadel server failed to start.\n" +"Go back and check your configuration.\n"); +important_message(_("Setup finished"), +_("Setup is finished. You may now start the server.")); +#endif + + +int main(int argc, char *argv[]) { + int a, i; + int curr; + char buf[1024]; + char aaa[128]; + char ctdldir[PATH_MAX]=CTDLDIR; + struct passwd *pw; + gid_t gid; + char *activity = NULL; + + // Keep a mild groove on + program_title = _("Citadel setup program"); + + // set an invalid setup type + setup_type = (-1); + + // parse command line args + for (a = 0; a < argc; ++a) { + if (!strncmp(argv[a], "-u", 2)) { + strcpy(aaa, argv[a]); + strcpy(aaa, &aaa[2]); + setup_type = atoi(aaa); + } + else if (!strncmp(argv[a], "-h", 2)) { + safestrncpy(ctdldir, &argv[a][2], sizeof ctdldir); + } + } + + if (chdir(ctdldir) != 0) { + fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); + exit(errno); + } + + SetTitles(); + + // Connect to the running Citadel server. + char *connectingmsg = _("Connecting to Citadel server"); + for (i=0; ((i<30) && (serv_sock < 0)) ; ++i) { // wait for server to start up + progress(connectingmsg, i, 30); + serv_sock = uds_connectsock(file_citadel_admin_socket); + sleep(1); + } + progress(connectingmsg, 30, 30); + + if (serv_sock < 0) { + display_error( + "%s: %s %s\n", + _("Setup could not connect to a running Citadel server."), + strerror(errno), file_citadel_admin_socket + ); + exit(1); + } + + // read the server greeting + serv_gets(buf); + if (buf[0] != '2') { + display_error("%s\n", buf); + exit(2); + } + + // Are we connected to the correct Citadel server? + serv_puts("INFO"); + serv_gets(buf); + if (buf[0] != '1') { + display_error("%s\n", buf); + exit(3); + } + a = 0; + while (serv_gets(buf), strcmp(buf, "000")) { + if (a == 5) { + if (atoi(buf) != REV_LEVEL) { + display_error("%s\n", + _("Your setup program and Citadel server are from different versions.") + ); + exit(4); + } + } + ++a; + } + + printf("\n\n\n *** %s ***\n\n", program_title); + + // Go through a series of dialogs prompting for config info + for (curr = 1; curr < eMaxQuestions; ++curr) { + edit_value(curr); + + if ( (curr == eAuthType) + && (getconf_int("c_auth_mode") != AUTHMODE_LDAP) + && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD) + ) { + curr += 5; // skip LDAP questions if we're not authenticating against LDAP + } + + if (curr == eSysAdminName) { + if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { // for native auth mode, fetch the admin's existing pw + snprintf(buf, sizeof buf, "AGUP %s", admin_name); + serv_puts(buf); + serv_gets(buf); + if (buf[0] == '2') { + extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass); + } + } + else { + ++curr; // skip the password question for non-native auth modes + } + } + } + + if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) { + gid = getgid(); + } + else { + gid = pw->pw_gid; + } + + // setup now must be run after Citadel Server is already running, so we don't need this anymore. + //if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) { + //display_error("%s\n", _("failed to create directories")); + //} + + activity = _("Reconfiguring Citadel server"); + progress(activity, 0, 5); + sleep(1); // Let the message appear briefly + + // Create the administrator account. It's ok if the command fails if this user already exists. + if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { + progress(activity, 1, 5); + snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass); + serv_puts(buf); + progress(activity, 2, 5); + serv_gets(buf); + } + progress(activity, 3, 5); + + // Assign the desired password and access level to the administrator account. + if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { + snprintf(buf, sizeof buf, "AGUP %s", admin_name); + serv_puts(buf); + progress(activity, 4, 5); + serv_gets(buf); + if (buf[0] == '2') { + int admin_flags = extract_int(&buf[4], 2); + int admin_times_called = extract_int(&buf[4], 3); + int admin_msgs_posted = extract_int(&buf[4], 4); + snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6", + admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted + ); + serv_puts(buf); + serv_gets(buf); + } + } + progress(activity, 5, 5); + + check_xinetd_entry(); // Check /etc/xinetd.d/telnet + + // Restart citserver + activity = _("Restarting Citadel server to apply changes"); + progress(activity, 0, 51); + + serv_puts("TIME"); + serv_gets(buf); + long original_start_time = extract_long(&buf[4], 3); + + progress(activity, 1, 51); + serv_puts("DOWN 1"); + progress(activity, 2, 51); + serv_gets(buf); + if (buf[0] != '2') { + display_error("%s\n", buf); + exit(6); + } + + close(serv_sock); + serv_sock = (-1); + + for (i=3; i<=6; ++i) { // wait for server to shut down + progress(activity, i, 51); + sleep(1); + } + + for (i=7; ((i<=48) && (serv_sock < 0)) ; ++i) { // wait for server to start up + progress(activity, i, 51); + serv_sock = uds_connectsock(file_citadel_admin_socket); + sleep(1); + } + + progress(activity, 49, 51); + serv_gets(buf); + + progress(activity, 50, 51); + serv_puts("TIME"); + serv_gets(buf); + long new_start_time = extract_long(&buf[4], 3); + + close(serv_sock); + progress(activity, 51, 51); + + if ((original_start_time == new_start_time) || (new_start_time <= 0)) { + display_error("%s\n", _("Setup failed to restart Citadel server. Please restart it manually.")); + exit(7); + } + + exit(0); + return 0; +}