From: Art Cancro Date: Wed, 3 Mar 2021 00:48:05 +0000 (-0500) Subject: moved utils directory files into the root X-Git-Tag: v939~101 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=ee511c807bbb15b0231f7aae485c3eb38e8e01bf moved utils directory files into the root --- diff --git a/citadel/Makefile.in b/citadel/Makefile.in index c21e3dc6d..d5ec717bc 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -68,8 +68,8 @@ LOCALEDIR=@LOCALEDIR@ .SILENT: -SOURCES=utils/citmail.c utils/setup.c utils/chkpw.c \ - utils/sendcommand.c utils/ctdlmigrate.c utils/chkpwd.c \ +SOURCES=citmail.c setup.c chkpw.c \ + sendcommand.c ctdlmigrate.c chkpwd.c \ citadel_dirs.c \ citserver.c clientsocket.c config.c control.c $(DATABASE) \ domain.c serv_extensions.c genstamp.c \ @@ -93,7 +93,6 @@ mkdir-init: @for d in `/bin/ls $(VPATH)/user_modules/`; do \ (mkdir -p user_modules/$$d ) ; \ done - mkdir -p utils mkdir locale svn_revision.c: ${SOURCES} @@ -137,28 +136,28 @@ citserver$(EXEEXT): $(SERV_OBJS) echo "CC $<" $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) -c $< -o $@ -citmail$(EXEEXT): utils/citmail.o citadel_dirs.o - $(CC) utils/citmail.o citadel_dirs.o \ +citmail$(EXEEXT): citmail.o citadel_dirs.o + $(CC) citmail.o citadel_dirs.o \ $(LDFLAGS) -o citmail$(EXEEXT) $(LIBS) # setup does need LIBS defined, because it uses network functions which are in -lsocket -lnsl on Solaris. -setup$(EXEEXT): utils/setup.o citadel_dirs.o - $(CC) utils/setup.o citadel_dirs.o \ +setup$(EXEEXT): setup.o citadel_dirs.o + $(CC) setup.o citadel_dirs.o \ $(LDFLAGS) -o setup$(EXEEXT) $(LIBS) $(SETUP_LIBS) -ctdlmigrate$(EXEEXT): utils/ctdlmigrate.o citadel_dirs.o - $(CC) utils/ctdlmigrate.o citadel_dirs.o \ +ctdlmigrate$(EXEEXT): ctdlmigrate.o citadel_dirs.o + $(CC) ctdlmigrate.o citadel_dirs.o \ $(LDFLAGS) -o ctdlmigrate$(EXEEXT) $(LIBS) -chkpwd$(EXEEXT): utils/chkpwd.o auth.o - $(CC) utils/chkpwd.o auth.o $(LDFLAGS) -o chkpwd$(EXEEXT) $(chkpwd_LIBS) +chkpwd$(EXEEXT): chkpwd.o auth.o + $(CC) chkpwd.o auth.o $(LDFLAGS) -o chkpwd$(EXEEXT) $(chkpwd_LIBS) -chkpw$(EXEEXT): utils/chkpw.o auth.o citadel_dirs.o - $(CC) utils/chkpw.o auth.o citadel_dirs.o \ +chkpw$(EXEEXT): chkpw.o auth.o citadel_dirs.o + $(CC) chkpw.o auth.o citadel_dirs.o \ $(LDFLAGS) -o chkpw$(EXEEXT) $(chkpwd_LIBS) -sendcommand$(EXEEXT): utils/sendcommand.o citadel_dirs.o $(LIBOBJS) - $(CC) utils/sendcommand.o citadel_dirs.o \ +sendcommand$(EXEEXT): sendcommand.o citadel_dirs.o $(LIBOBJS) + $(CC) sendcommand.o citadel_dirs.o \ $(LIBOBJS) $(LDFLAGS) -o sendcommand$(EXEEXT) $(LIBS) .PHONY: install-data install-doc install-exec clean cleaner distclean @@ -289,7 +288,6 @@ install-exec-new: all clean: rm -vfr locale/* rm -vf *.o - rm -vf utils/*.o ;\ rm -vf *.o ;\ for i in $(srcdir)/modules/* ; do \ rm -vf $$i/*.o ;\ @@ -309,7 +307,6 @@ distclean: cleaner find . -name '*~' -o -name '.#*' | xargs rm -vf rm -vf po/Makefile rm -vf Makefile configure sysdep.h config.cache config.log config.status *.d package-version.txt - rm -vf utils/*.d ; for i in $(srcdir)/modules/* ; do \ rm -vf $$i/*.d ;\ done diff --git a/citadel/chkpw.c b/citadel/chkpw.c new file mode 100644 index 000000000..9691b7343 --- /dev/null +++ b/citadel/chkpw.c @@ -0,0 +1,144 @@ +/* + * 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 + + +#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; + char ctdldir[PATH_MAX]=CTDLDIR; + + 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 new file mode 100644 index 000000000..4dfc594e2 --- /dev/null +++ b/citadel/chkpwd.c @@ -0,0 +1,53 @@ +/* + * 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; 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 "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/citmail.c b/citadel/citmail.c new file mode 100644 index 000000000..777edb701 --- /dev/null +++ b/citadel/citmail.c @@ -0,0 +1,345 @@ +/* + * 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. + * + * 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 "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; + strncpy(addr.sun_path, sockpath, sizeof addr.sun_path); + + 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 "citadel.h" +#include "axdefs.h" +#include "sysdep.h" +#include "config.h" +#include "citadel_dirs.h" + + + +/* + * Replacement for gets() that doesn't throw a compiler warning. + * We're only using it for some simple prompts, so we don't need + * to worry about attackers exploiting it. + */ +void getz(char *buf) { + char *ptr; + + ptr = fgets(buf, SIZ, stdin); + if (!ptr) { + buf[0] = 0; + return; + } + + ptr = strchr(buf, '\n'); + if (ptr) *ptr = 0; +} + + + + + +int main(int argc, char *argv[]) { + char ctdldir[PATH_MAX]=CTDLDIR; + char yesno[5]; + char sendcommand[PATH_MAX]; + int cmdexit; + char cmd[PATH_MAX]; + char buf[PATH_MAX]; + char socket_path[PATH_MAX]; + char remote_user[SIZ]; + char remote_host[SIZ]; + char remote_sendcommand[PATH_MAX]; + FILE *sourcefp = NULL; + FILE *targetfp = NULL; + int linecount = 0; + char spinning[4] = "-\\|/" ; + int exitcode = 0; + + CtdlMakeTempFileName(socket_path, sizeof socket_path); + if (chdir(ctdldir) != 0) { + fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); + exit(errno); + } + + + printf( "\033[2J\033[H\n" + "-------------------------------------------\n" + "Over-the-wire migration utility for Citadel\n" + "-------------------------------------------\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 %d or newer, and the target system should be running\n" + "either the same version or a newer version. You will also need\n" + "the 'rsync' utility, and OpenSSH v4 or newer.\n" + "\n" + "You must run this utility on the TARGET SYSTEM. Any existing data\n" + "on this system will be ERASED.\n" + "\n" + "Do you wish to continue? " + , + EXPORT_REV_MIN + ); + + if ((fgets(yesno, sizeof yesno, stdin) == NULL) || (tolower(yesno[0]) != 'y')) { + exit(0); + } + + printf("\n\nGreat! First we will check some things out here on our target\n" + "system to make sure it is ready to receive data.\n\n"); + + printf("Locating 'sendcommand' and checking connectivity to Citadel...\n"); + snprintf(sendcommand, sizeof sendcommand, "%s/sendcommand", ctdl_utilbin_dir); + snprintf(cmd, sizeof cmd, "%s 'NOOP'", sendcommand); + cmdexit = system(cmd); + if (cmdexit != 0) { + printf("\nctdlmigrate was unable to attach to the Citadel server\n" + "here on the target system. Is Citadel running?\n\n"); + exit(1); + } + printf("\nOK, this side is ready to go. Now we must connect to the source system.\n\n"); + + printf("Enter the host name or IP address of the source system\n" + "(example: ctdl.foo.org)\n" + "--> "); + getz(remote_host); + +get_remote_user: + printf("\nEnter the name of a user on %s who has full access to Citadel files\n" + "(usually root)\n--> ", + remote_host); + getz(remote_user); + if (IsEmptyStr(remote_user)) + goto get_remote_user; + + printf("\nEstablishing an SSH connection to the source system...\n\n"); + unlink(socket_path); + snprintf(cmd, sizeof cmd, "ssh -MNf -S %s %s@%s", socket_path, remote_user, remote_host); + cmdexit = system(cmd); + printf("\n"); + if (cmdexit != 0) { + printf("This program was unable to establish an SSH session to the source system.\n\n"); + exitcode = cmdexit; + goto THEEND; + } + + printf("\nTesting a command over the connection...\n\n"); + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s 'echo Remote commands are executing successfully.'", + socket_path, remote_user, remote_host); + cmdexit = system(cmd); + printf("\n"); + if (cmdexit != 0) { + printf("Remote commands are not succeeding.\n\n"); + exitcode = cmdexit; + goto THEEND; + } + + printf("\nLocating the remote 'sendcommand' and Citadel installation...\n"); + snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/local/citadel/sendcommand"); + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", + socket_path, remote_user, remote_host, remote_sendcommand); + cmdexit = system(cmd); + if (cmdexit != 0) { + snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/sbin/sendcommand"); + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", + socket_path, remote_user, remote_host, remote_sendcommand); + cmdexit = system(cmd); + } + if (cmdexit != 0) { + printf("\nUnable to locate Citadel programs on the remote system. Please enter\n" + "the name of the directory on %s which contains the 'sendcommand' program.\n" + "(example: /opt/foo/citadel)\n" + "--> ", remote_host); + getz(buf); + snprintf(remote_sendcommand, sizeof remote_sendcommand, "%s/sendcommand", buf); + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", + socket_path, remote_user, remote_host, remote_sendcommand); + cmdexit = system(cmd); + } + printf("\n"); + if (cmdexit != 0) { + printf("ctdlmigrate was unable to attach to the remote Citadel system.\n\n"); + exitcode = cmdexit; + goto THEEND; + } + + printf("ctdlmigrate will now begin a database migration...\n"); + printf(" if the system doesn't start working, \n"); + printf(" have a look at the syslog for pending jobs needing to be terminated.\n"); + + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s -w3600 MIGR export", + socket_path, remote_user, remote_host, remote_sendcommand); + sourcefp = popen(cmd, "r"); + if (!sourcefp) { + printf("\n%s\n\n", strerror(errno)); + exitcode = 2; + goto THEEND; + } + + snprintf(cmd, sizeof cmd, "%s -w3600 MIGR import", sendcommand); + targetfp = popen(cmd, "w"); + if (!targetfp) { + printf("\n%s\n\n", strerror(errno)); + exitcode = 3; + goto THEEND; + } + + while (fgets(buf, sizeof buf, sourcefp) != NULL) { + if (fwrite(buf, strlen(buf), 1, targetfp) < 1) { + exitcode = 4; + printf("%s\n", strerror(errno)); + goto FAIL; + } + ++linecount; + if ((linecount % 100) == 0) { + printf("%c\r", spinning[((linecount / 100) % 4)]); + fflush(stdout); + } + } + +FAIL: if (sourcefp) pclose(sourcefp); + if (targetfp) pclose(targetfp); + if (exitcode != 0) goto THEEND; + + /* We need to copy a bunch of other stuff, and will do so using rsync */ + + snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s MIGR listdirs", + socket_path, remote_user, remote_host, remote_sendcommand); + sourcefp = popen(cmd, "r"); + if (!sourcefp) { + printf("\n%s\n\n", strerror(errno)); + exitcode = 2; + goto THEEND; + } + while ((fgets(buf, sizeof buf, sourcefp)) && (strcmp(buf, "000"))) { + buf[strlen(buf)-1] = 0; + + if (!strncasecmp(buf, "files|", 6)) { + snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", + socket_path, remote_user, remote_host, &buf[6], ctdl_file_dir); + } + else if (!strncasecmp(buf, "messages|", 9)) { + snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", + socket_path, remote_user, remote_host, &buf[9], ctdl_message_dir); + } + else if (!strncasecmp(buf, "keys|", 5)) { + snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", + socket_path, remote_user, remote_host, &buf[5], ctdl_key_dir); + } + else { + strcpy(cmd, "false"); /* cheap and sleazy way to throw an error */ + } + printf("%s\n", cmd); + cmdexit = system(cmd); + if (cmdexit != 0) { + exitcode += cmdexit; + } + } + pclose(sourcefp); + +THEEND: if (exitcode == 0) { + printf("\n\n *** Citadel migration was successful! *** \n\n"); + } + else { + printf("\n\n *** Citadel migration was unsuccessful. *** \n\n"); + } + printf("\nShutting down the socket connection...\n\n"); + snprintf(cmd, sizeof cmd, "ssh -S %s -N -O exit %s@%s", + socket_path, remote_user, remote_host); + cmdexit = system(cmd); + printf("\n"); + if (cmdexit != 0) { + printf("There was an error shutting down the socket.\n\n"); + exitcode = cmdexit; + } + + unlink(socket_path); + exit(exitcode); +} diff --git a/citadel/sendcommand.c b/citadel/sendcommand.c new file mode 100644 index 000000000..7d8e08985 --- /dev/null +++ b/citadel/sendcommand.c @@ -0,0 +1,243 @@ +/* + * 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; + + StartLibCitadel(SIZ); + + /* 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 new file mode 100644 index 000000000..9083fb8d4 --- /dev/null +++ b/citadel/setup.c @@ -0,0 +1,907 @@ +/* + * 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/chkpw.c b/citadel/utils/chkpw.c deleted file mode 100644 index 9691b7343..000000000 --- a/citadel/utils/chkpw.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 1987-2021 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#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; - char ctdldir[PATH_MAX]=CTDLDIR; - - 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 deleted file mode 100644 index 4dfc594e2..000000000 --- a/citadel/utils/chkpwd.c +++ /dev/null @@ -1,53 +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; 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 "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/citmail.c b/citadel/utils/citmail.c deleted file mode 100644 index 777edb701..000000000 --- a/citadel/utils/citmail.c +++ /dev/null @@ -1,345 +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. - * - * 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 "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; - strncpy(addr.sun_path, sockpath, sizeof addr.sun_path); - - 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 "citadel.h" -#include "axdefs.h" -#include "sysdep.h" -#include "config.h" -#include "citadel_dirs.h" - - - -/* - * Replacement for gets() that doesn't throw a compiler warning. - * We're only using it for some simple prompts, so we don't need - * to worry about attackers exploiting it. - */ -void getz(char *buf) { - char *ptr; - - ptr = fgets(buf, SIZ, stdin); - if (!ptr) { - buf[0] = 0; - return; - } - - ptr = strchr(buf, '\n'); - if (ptr) *ptr = 0; -} - - - - - -int main(int argc, char *argv[]) { - char ctdldir[PATH_MAX]=CTDLDIR; - char yesno[5]; - char sendcommand[PATH_MAX]; - int cmdexit; - char cmd[PATH_MAX]; - char buf[PATH_MAX]; - char socket_path[PATH_MAX]; - char remote_user[SIZ]; - char remote_host[SIZ]; - char remote_sendcommand[PATH_MAX]; - FILE *sourcefp = NULL; - FILE *targetfp = NULL; - int linecount = 0; - char spinning[4] = "-\\|/" ; - int exitcode = 0; - - CtdlMakeTempFileName(socket_path, sizeof socket_path); - if (chdir(ctdldir) != 0) { - fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); - exit(errno); - } - - - printf( "\033[2J\033[H\n" - "-------------------------------------------\n" - "Over-the-wire migration utility for Citadel\n" - "-------------------------------------------\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 %d or newer, and the target system should be running\n" - "either the same version or a newer version. You will also need\n" - "the 'rsync' utility, and OpenSSH v4 or newer.\n" - "\n" - "You must run this utility on the TARGET SYSTEM. Any existing data\n" - "on this system will be ERASED.\n" - "\n" - "Do you wish to continue? " - , - EXPORT_REV_MIN - ); - - if ((fgets(yesno, sizeof yesno, stdin) == NULL) || (tolower(yesno[0]) != 'y')) { - exit(0); - } - - printf("\n\nGreat! First we will check some things out here on our target\n" - "system to make sure it is ready to receive data.\n\n"); - - printf("Locating 'sendcommand' and checking connectivity to Citadel...\n"); - snprintf(sendcommand, sizeof sendcommand, "%s/sendcommand", ctdl_utilbin_dir); - snprintf(cmd, sizeof cmd, "%s 'NOOP'", sendcommand); - cmdexit = system(cmd); - if (cmdexit != 0) { - printf("\nctdlmigrate was unable to attach to the Citadel server\n" - "here on the target system. Is Citadel running?\n\n"); - exit(1); - } - printf("\nOK, this side is ready to go. Now we must connect to the source system.\n\n"); - - printf("Enter the host name or IP address of the source system\n" - "(example: ctdl.foo.org)\n" - "--> "); - getz(remote_host); - -get_remote_user: - printf("\nEnter the name of a user on %s who has full access to Citadel files\n" - "(usually root)\n--> ", - remote_host); - getz(remote_user); - if (IsEmptyStr(remote_user)) - goto get_remote_user; - - printf("\nEstablishing an SSH connection to the source system...\n\n"); - unlink(socket_path); - snprintf(cmd, sizeof cmd, "ssh -MNf -S %s %s@%s", socket_path, remote_user, remote_host); - cmdexit = system(cmd); - printf("\n"); - if (cmdexit != 0) { - printf("This program was unable to establish an SSH session to the source system.\n\n"); - exitcode = cmdexit; - goto THEEND; - } - - printf("\nTesting a command over the connection...\n\n"); - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s 'echo Remote commands are executing successfully.'", - socket_path, remote_user, remote_host); - cmdexit = system(cmd); - printf("\n"); - if (cmdexit != 0) { - printf("Remote commands are not succeeding.\n\n"); - exitcode = cmdexit; - goto THEEND; - } - - printf("\nLocating the remote 'sendcommand' and Citadel installation...\n"); - snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/local/citadel/sendcommand"); - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", - socket_path, remote_user, remote_host, remote_sendcommand); - cmdexit = system(cmd); - if (cmdexit != 0) { - snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/sbin/sendcommand"); - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", - socket_path, remote_user, remote_host, remote_sendcommand); - cmdexit = system(cmd); - } - if (cmdexit != 0) { - printf("\nUnable to locate Citadel programs on the remote system. Please enter\n" - "the name of the directory on %s which contains the 'sendcommand' program.\n" - "(example: /opt/foo/citadel)\n" - "--> ", remote_host); - getz(buf); - snprintf(remote_sendcommand, sizeof remote_sendcommand, "%s/sendcommand", buf); - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP", - socket_path, remote_user, remote_host, remote_sendcommand); - cmdexit = system(cmd); - } - printf("\n"); - if (cmdexit != 0) { - printf("ctdlmigrate was unable to attach to the remote Citadel system.\n\n"); - exitcode = cmdexit; - goto THEEND; - } - - printf("ctdlmigrate will now begin a database migration...\n"); - printf(" if the system doesn't start working, \n"); - printf(" have a look at the syslog for pending jobs needing to be terminated.\n"); - - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s -w3600 MIGR export", - socket_path, remote_user, remote_host, remote_sendcommand); - sourcefp = popen(cmd, "r"); - if (!sourcefp) { - printf("\n%s\n\n", strerror(errno)); - exitcode = 2; - goto THEEND; - } - - snprintf(cmd, sizeof cmd, "%s -w3600 MIGR import", sendcommand); - targetfp = popen(cmd, "w"); - if (!targetfp) { - printf("\n%s\n\n", strerror(errno)); - exitcode = 3; - goto THEEND; - } - - while (fgets(buf, sizeof buf, sourcefp) != NULL) { - if (fwrite(buf, strlen(buf), 1, targetfp) < 1) { - exitcode = 4; - printf("%s\n", strerror(errno)); - goto FAIL; - } - ++linecount; - if ((linecount % 100) == 0) { - printf("%c\r", spinning[((linecount / 100) % 4)]); - fflush(stdout); - } - } - -FAIL: if (sourcefp) pclose(sourcefp); - if (targetfp) pclose(targetfp); - if (exitcode != 0) goto THEEND; - - /* We need to copy a bunch of other stuff, and will do so using rsync */ - - snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s MIGR listdirs", - socket_path, remote_user, remote_host, remote_sendcommand); - sourcefp = popen(cmd, "r"); - if (!sourcefp) { - printf("\n%s\n\n", strerror(errno)); - exitcode = 2; - goto THEEND; - } - while ((fgets(buf, sizeof buf, sourcefp)) && (strcmp(buf, "000"))) { - buf[strlen(buf)-1] = 0; - - if (!strncasecmp(buf, "files|", 6)) { - snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", - socket_path, remote_user, remote_host, &buf[6], ctdl_file_dir); - } - else if (!strncasecmp(buf, "messages|", 9)) { - snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", - socket_path, remote_user, remote_host, &buf[9], ctdl_message_dir); - } - else if (!strncasecmp(buf, "keys|", 5)) { - snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", - socket_path, remote_user, remote_host, &buf[5], ctdl_key_dir); - } - else { - strcpy(cmd, "false"); /* cheap and sleazy way to throw an error */ - } - printf("%s\n", cmd); - cmdexit = system(cmd); - if (cmdexit != 0) { - exitcode += cmdexit; - } - } - pclose(sourcefp); - -THEEND: if (exitcode == 0) { - printf("\n\n *** Citadel migration was successful! *** \n\n"); - } - else { - printf("\n\n *** Citadel migration was unsuccessful. *** \n\n"); - } - printf("\nShutting down the socket connection...\n\n"); - snprintf(cmd, sizeof cmd, "ssh -S %s -N -O exit %s@%s", - socket_path, remote_user, remote_host); - cmdexit = system(cmd); - printf("\n"); - if (cmdexit != 0) { - printf("There was an error shutting down the socket.\n\n"); - exitcode = cmdexit; - } - - unlink(socket_path); - exit(exitcode); -} diff --git a/citadel/utils/sendcommand.c b/citadel/utils/sendcommand.c deleted file mode 100644 index 7d8e08985..000000000 --- a/citadel/utils/sendcommand.c +++ /dev/null @@ -1,243 +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; - - StartLibCitadel(SIZ); - - /* 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 deleted file mode 100644 index 9083fb8d4..000000000 --- a/citadel/utils/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; -}