I can't see the screen with my sunglasses on
[citadel.git] / citadel / utils / setup.c
1 // Citadel setup utility
2 //
3 // Copyright (c) 1987-2022 by the citadel.org team
4 //
5 // This program is open source software.  Use, duplication, or disclosure
6 // is subject to the terms of the GNU General Public License, version 3.
7
8 #define SHOW_ME_VAPPEND_PRINTF
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/wait.h>
18 #include <signal.h>
19 #include <netdb.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <pwd.h>
23 #include <time.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <assert.h>
27 #include <libcitadel.h>
28 #include "../server/citadel.h"
29 #include "axdefs.h"
30 #include "../server/sysdep.h"
31 #include "../server/citadel_dirs.h"
32
33 #ifdef ENABLE_NLS
34 #ifdef HAVE_XLOCALE_H
35 #include <xlocale.h>
36 #endif
37 #include <libintl.h>
38 #include <locale.h>
39 #define _(string)       gettext(string)
40 #else
41 #define _(string)       (string)
42 #endif
43
44 #define SERVICE_NAME    "citadel"
45 #define PROTO_NAME      "tcp"
46 #define NSSCONF         "/etc/nsswitch.conf"
47
48 typedef enum _SetupStep {
49         eCitadelHomeDir = 0,
50         eSysAdminName = 1,
51         eSysAdminPW = 2,
52         eUID = 3,
53         eIP_ADDR = 4,
54         eCTDL_Port = 5,
55         eAuthType = 6,
56         eLDAP_Host = 7,
57         eLDAP_Port = 8,
58         eLDAP_Base_DN = 9,
59         eLDAP_Bind_DN = 10,
60         eLDAP_Bind_PW = 11,
61         eMaxQuestions = 12
62 } eSetupStep;
63
64 ///"CREATE_XINETD_ENTRY";
65 /* Environment variables, don't translate! */
66 const char *EnvNames [eMaxQuestions] = {
67         "HOME_DIRECTORY",
68         "SYSADMIN_NAME",
69         "SYSADMIN_PW",
70         "CITADEL_UID",
71         "IP_ADDR",
72         "CITADEL_PORT",
73         "ENABLE_UNIX_AUTH",
74         "LDAP_HOST",
75         "LDAP_PORT",
76         "LDAP_BASE_DN",
77         "LDAP_BIND_DN",
78         "LDAP_BIND_PW"
79 };
80
81 int setup_type = (-1);
82 int enable_home = 1;
83 char admin_name[SIZ];
84 char admin_pass[SIZ];
85 char admin_cmd[SIZ];
86 int serv_sock = (-1) ;
87
88 const char *setup_titles[eMaxQuestions];
89 const char *setup_text[eMaxQuestions];
90
91 char *program_title;
92
93 void SetTitles(void) {
94         int have_run_dir;
95 #ifndef HAVE_RUN_DIR
96         have_run_dir = 1;
97 #else
98         have_run_dir = 0;
99 #endif
100
101 #ifdef ENABLE_NLS
102         setlocale(LC_MESSAGES, getenv("LANG"));
103         bindtextdomain("citadel-setup", LOCALEDIR"/locale");
104         textdomain("citadel-setup");
105         bind_textdomain_codeset("citadel-setup","UTF8");
106 #endif
107
108         setup_titles[eCitadelHomeDir] = _("Citadel Home Directory");
109         if (have_run_dir)
110                 setup_text[eCitadelHomeDir] = _(
111 "Enter the full pathname of the directory in which the Citadel\n"
112 "installation you are creating or updating resides.  If you\n"
113 "specify a directory other than the default, you will need to\n"
114 "specify the -h flag to the server when you start it up.\n");
115         else
116                 setup_text[eCitadelHomeDir] = _(
117 "Enter the subdirectory name for an alternate installation of "
118 "Citadel. To do a default installation just leave it blank."
119 "If you specify a directory other than the default, you will need to\n"
120 "specify the -h flag to the server when you start it up.\n"
121 "note that it may not have a leading /");
122
123         setup_titles[eSysAdminName] = _("Citadel administrator username:");
124         setup_text[eSysAdminName] = _(
125 "Please enter the name of the Citadel user account that should be granted "
126 "administrative privileges once created. If using internal authentication "
127 "this user account will be created if it does not exist. For external "
128 "authentication this user account has to exist.");
129
130         setup_titles[eSysAdminPW] = _("Administrator password:");
131         setup_text[eSysAdminPW] = _(
132 "Enter a password for the system administrator. When setup\n"
133 "completes it will attempt to create the administrator user\n"
134 "and set the password specified here.\n");
135
136         setup_titles[eUID] = _("Citadel User ID:");
137         setup_text[eUID] = _(
138 "Citadel needs to run under its own user ID.  This would\n"
139 "typically be called \"citadel\", but if you are running Citadel\n"
140 "as a public site, you might also call it \"bbs\" or \"guest\".\n"
141 "The server will run under this user ID.  Please specify that\n"
142 "user ID here.  You may specify either a user name or a numeric\n"
143 "UID.\n");
144
145         setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:");
146         setup_text[eIP_ADDR] = _(
147 "Please specify the IP address which the server should be listening to. "
148 "You can name a specific IPv4 or IPv6 address, or you can specify\n"
149 "\"*\" for \"any address\", \"::\" for \"any IPv6 address\", or \"0.0.0.0\"\n"
150 "for \"any IPv4 address\". If you leave this blank, Citadel will\n"
151 "listen on all addresses. "
152 "This can usually be left to the default unless multiple instances of Citadel "
153 "are running on the same computer.");
154
155         setup_titles[eCTDL_Port] = _("Server port number:");
156         setup_text[eCTDL_Port] = _(
157 "Specify the TCP port number on which your server will run.\n"
158 "Normally, this will be port 504, which is the official port\n"
159 "assigned by the IANA for Citadel servers.  You will only need\n"
160 "to specify a different port number if you run multiple instances\n"
161 "of Citadel on the same computer and there is something else\n"
162 "already using port 504.\n");
163
164         setup_titles[eAuthType] = _("Authentication method to use:");
165         setup_text[eAuthType] = _(
166 "Please choose the user authentication mode. By default Citadel will use its "
167 "own internal user accounts database. If you choose Host, Citadel users will "
168 "have accounts on the host system, authenticated via /etc/passwd or a PAM "
169 "source. LDAP chooses an RFC 2307 compliant directory server, the last option "
170 "chooses the nonstandard MS Active Directory LDAP scheme."
171 "\n"
172 "Do not change this option unless you are sure it is required, since changing "
173 "back requires a full reinstall of Citadel."
174 "\n"
175 " 0. Self contained authentication\n"
176 " 1. Host system integrated authentication\n"
177 " 2. External LDAP - RFC 2307 POSIX schema\n"
178 " 3. External LDAP - MS Active Directory schema\n"
179 "\n"
180 "For help: http://www.citadel.org/authmodes.html\n"
181 "\n"
182 "ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n");
183
184         setup_titles[eLDAP_Host] = _("LDAP host:");
185         setup_text[eLDAP_Host] = _(
186 "Please enter the host name or IP address of your LDAP server.\n");
187
188         setup_titles[eLDAP_Port] = _("LDAP port number:");
189         setup_text[eLDAP_Port] = _(
190 "Please enter the port number of the LDAP service (usually 389).\n");
191
192         setup_titles[eLDAP_Base_DN] = _("LDAP base DN:");
193         setup_text[eLDAP_Base_DN] = _(
194 "Please enter the Base DN to search for authentication\n"
195 "(for example: dc=example,dc=com)\n");
196
197         setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:");
198         setup_text[eLDAP_Bind_DN] = _(
199 "Please enter the DN of an account to use for binding to the LDAP server for "
200 "performing queries. The account does not require any other privileges. If "
201 "your LDAP server allows anonymous queries, you can leave this blank.\n");
202
203         setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:");
204         setup_text[eLDAP_Bind_PW] = _(
205 "If you entered a Bind DN in the previous question, you must now enter\n"
206 "the password associated with that account.  Otherwise, you can leave this\n"
207 "blank.\n");
208 }
209
210
211 void cls(void) {
212         printf("\033[2J\033[H\033[44m\033[1m\033[K\n");
213         printf("  %s  \033[K\n", program_title);
214         printf("\033[K\n");
215         printf("\033[0m\n");
216 }
217
218
219 void title(const char *text) {
220         cls();
221         printf("\033[1m\033[32m<\033[33m%s\033[32m>\033[0m\n", text);
222 }
223
224
225 int yesno(const char *question, int default_value) {
226         int answer = 0;
227         char buf[SIZ];
228
229         do {
230                 printf("\033[31m\033[32m%s\n%s [\033[33m%s\033[32m]\033[0m --> ", question, _("Yes/No"), ( default_value ? _("Yes") : _("No") ));
231                 if (fgets(buf, sizeof buf, stdin)) {
232                         answer = tolower(buf[0]);
233                         if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) {
234                                 answer = default_value;
235                         }
236                         else if (answer == 'y') {
237                                 answer = 1;
238                         }
239                         else if (answer == 'n') {
240                                 answer = 0;
241                         }
242                 }
243         } while ((answer < 0) || (answer > 1));
244         return (answer);
245 }
246
247
248 void important_message(const char *title, const char *msgtext) {
249         char buf[SIZ];
250
251         cls();
252         printf("%s\n%s\n\n", title, msgtext);
253         printf("%s", _("Press return to continue..."));
254         if (fgets(buf, sizeof buf, stdin)) {
255                 ;
256         }
257 }
258
259
260 void important_msgnum(int msgnum) {
261         important_message(_("Important Message"), setup_text[msgnum]);
262 }
263
264
265 void display_error(char *error_message_format, ...) {
266         StrBuf *Msg;
267         va_list arg_ptr;
268
269         Msg = NewStrBuf();
270         va_start(arg_ptr, error_message_format);
271         StrBufVAppendPrintf(Msg, error_message_format, arg_ptr);
272         va_end(arg_ptr);
273
274         important_message(_("Error"), ChrPtr(Msg));
275         FreeStrBuf(&Msg);
276 }
277
278
279 void progress(char *text, long int curr, long int cmax) {
280         long a = 0;
281         long i = 0;
282
283         if (curr == 0) {
284                 cls();
285                 printf("%s\n", text);
286                 printf("\033[1m\033[33m[\033[32m............................................................................\033[33m]\033[0m\r");
287         }
288         else if (curr == cmax) {
289                 printf("\r%79s\n", "");
290         }
291         else {
292                 printf("\033[1m\033[33m[\033[32m");
293                 a = (curr * 100) / cmax;
294                 a = a * 76;
295                 a = a / 100;
296                 for (i=0; i<a; ++i) {
297                         printf("*");
298                 }
299                 printf("\033[0m\r");
300         }
301         fflush(stdout);
302 }
303
304
305 int uds_connectsock(char *sockpath) {
306         int s;
307         struct sockaddr_un addr;
308
309         memset(&addr, 0, sizeof(addr));
310         addr.sun_family = AF_UNIX;
311         strcpy(addr.sun_path, sockpath);
312
313         s = socket(AF_UNIX, SOCK_STREAM, 0);
314         if (s < 0) {
315                 return(-1);
316         }
317
318         if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
319                 close(s);
320                 return(-1);
321         }
322
323         return s;
324 }
325
326
327 // input binary data from socket
328 void serv_read(char *buf, int bytes) {
329         int len, rlen;
330
331         len = 0;
332         while (len < bytes) {
333                 rlen = read(serv_sock, &buf[len], bytes - len);
334                 if (rlen < 1) {
335                         return;
336                 }
337                 len = len + rlen;
338         }
339 }
340
341
342 // send binary to server
343 void serv_write(char *buf, int nbytes) {
344         int bytes_written = 0;
345         int retval;
346         while (bytes_written < nbytes) {
347                 retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written);
348                 if (retval < 1) {
349                         return;
350                 }
351                 bytes_written = bytes_written + retval;
352         }
353 }
354
355
356 // input string from socket - implemented in terms of serv_read()
357 void serv_gets(char *buf) {
358         int i;
359
360         // Read one character at a time.
361         for (i = 0;; i++) {
362                 serv_read(&buf[i], 1);
363                 if (buf[i] == '\n' || i == (SIZ-1))
364                         break;
365         }
366
367         // If we got a long line, discard characters until the newline.
368         if (i == (SIZ-1)) {
369                 while (buf[i] != '\n') {
370                         serv_read(&buf[i], 1);
371                 }
372         }
373
374         // Strip all trailing nonprintables (crlf)
375         buf[i] = 0;
376 }
377
378
379 // send line to server - implemented in terms of serv_write()
380 void serv_puts(char *buf) {
381         serv_write(buf, strlen(buf));
382         serv_write("\n", 1);
383 }
384
385
386 // Convenience functions to get/set system configuration entries
387 void getconf_str(char *buf, char *key) {
388         char cmd[SIZ];
389         char ret[SIZ];
390
391         sprintf(cmd, "CONF GETVAL|%s", key);
392         serv_puts(cmd);
393         serv_gets(ret);
394         if (ret[0] == '2') {
395                 extract_token(buf, &ret[4], 0, '|', SIZ);
396         }
397         else {
398                 strcpy(buf, "");
399         }
400 }
401
402
403 int getconf_int(char *key) {
404         char buf[SIZ];
405         getconf_str(buf, key);
406         return atoi(buf);
407 }
408
409
410 void setconf_str(char *key, char *val) {
411         char buf[SIZ];
412
413         sprintf(buf, "CONF PUTVAL|%s|%s", key, val);
414         serv_puts(buf);
415         serv_gets(buf);
416 }
417
418
419 void setconf_int(char *key, int val) {
420         char buf[SIZ];
421
422         sprintf(buf, "CONF PUTVAL|%s|%d", key, val);
423         serv_puts(buf);
424         serv_gets(buf);
425 }
426
427
428 // On systems which use xinetd, see if we can offer to install Citadel as
429 // the default telnet target.
430 void check_xinetd_entry(void) {
431         char *filename = "/etc/xinetd.d/telnet";
432         FILE *fp;
433         char buf[SIZ];
434         int already_citadel = 0;
435         int rv;
436
437         fp = fopen(filename, "r+");
438         if (fp == NULL) return;         // Not there.  Oh well...
439
440         while (fgets(buf, sizeof buf, fp) != NULL) {
441                 if (strstr(buf, "/citadel") != NULL) {
442                         already_citadel = 1;
443                 }
444         }
445         fclose(fp);
446         if (already_citadel) return;    // Already set up this way.
447
448         // Otherwise, prompt the user to create an entry.
449         if (getenv("CREATE_XINETD_ENTRY") != NULL) {
450                 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
451                         return;
452                 }
453         }
454         else {
455                 snprintf(buf, sizeof buf,
456                          _("Setup can configure the \"xinetd\" service to automatically\n"
457                            "connect incoming telnet sessions to Citadel, bypassing the\n"
458                            "host system login: prompt.  Would you like to do this?\n"
459                          )
460                 );
461                 if (yesno(buf, 1) == 0) {
462                         return;
463                 }
464         }
465
466         fp = fopen(filename, "w");
467         fprintf(fp,
468                 "# description: telnet service for Citadel users\n"
469                 "service telnet\n"
470                 "{\n"
471                 "       disable = no\n"
472                 "       flags           = REUSE\n"
473                 "       socket_type     = stream\n"
474                 "       wait            = no\n"
475                 "       user            = root\n"
476                 "       server          = /usr/sbin/in.telnetd\n"
477                 "       server_args     = -h -L %s/citadel\n"
478                 "       log_on_failure  += USERID\n"
479                 "}\n",
480                 ctdl_bin_dir
481         );
482         fclose(fp);
483
484         // Now try to restart the service.  (This only works on systemd; others will need to restart it manually.)
485         rv = system("systemctl restart xinetd >/dev/null 2>&1");
486         if (rv != 0) {
487                 rv = system("service xinetd restart >/dev/null 2>&1");
488         }
489         if (rv != 0) {
490                 display_error(_("failed to restart xinetd.\n"));
491         }
492 }
493
494
495 void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue) {
496         char buf[SIZ] = "";
497         char setupmsg[SIZ];
498
499         strcpy(setupmsg, "");
500
501         title(prompt_title);
502         printf("\n%s\n", prompt_text);
503         printf("%s\n%s\n", _("This is currently set to:"), Target);
504         printf("%s\n", _("Enter new value or press return to leave unchanged:"));
505         if (fgets(buf, sizeof buf, stdin)) {
506                 buf[strlen(buf) - 1] = 0;
507         }
508         if (!IsEmptyStr(buf)) {
509                 strcpy(Target, buf);
510         }
511 }
512
513
514 void set_bool_val(int msgpos, int *ip, char *DefValue) {
515         title(setup_titles[msgpos]);
516         *ip = yesno(setup_text[msgpos], *ip);
517 }
518
519
520 void set_str_val(int msgpos, char *Target, char *DefValue) {
521         strprompt(setup_titles[msgpos], 
522                   setup_text[msgpos], 
523                   Target, 
524                   DefValue
525         );
526 }
527
528
529 // like set_str_val() but for numeric values
530 void set_int_val(int msgpos, int *target, char *default_value) {
531         char buf[32];
532         sprintf(buf, "%d", *target);
533         do {
534                 set_str_val(msgpos, buf, default_value);
535         } while ( (strcmp(buf, "0")) && (atoi(buf) == 0) );
536         *target = atoi(buf);
537 }
538
539
540 void edit_value(int curr) {
541         struct passwd *pw = NULL;
542         char ctdluidname[256];
543         char buf[SIZ];
544         char *default_value = NULL;
545         int ctdluid = 0;
546         int portnum = 0;
547         int auth = 0;
548         int lportnum = 0;
549
550         if (default_value == NULL) {
551                 default_value = "";
552         }
553
554         switch (curr) {
555
556         case eSysAdminName:
557                 getconf_str(admin_name, "c_sysadm");
558                 set_str_val(curr, admin_name, default_value);
559                 setconf_str("c_sysadm", admin_name);
560                 break;
561
562         case eSysAdminPW:
563                 set_str_val(curr, admin_pass, default_value);
564                 break;
565         
566         case eUID:
567                 ctdluid = getconf_int("c_ctdluid");
568                 pw = getpwuid(ctdluid);
569                 if (pw == NULL) {
570                         set_int_val(curr, &ctdluid, default_value);
571                 }
572                 else {
573                         strcpy(ctdluidname, pw->pw_name);
574                         set_str_val(curr, ctdluidname, default_value);
575                         pw = getpwnam(ctdluidname);
576                         if (pw != NULL) {
577                                 ctdluid = pw->pw_uid;
578                         }
579                         else if (atoi(ctdluidname) > 0) {
580                                 ctdluid = atoi(ctdluidname);
581                         }
582                 }
583                 setconf_int("c_ctdluid", ctdluid);
584                 break;
585
586         case eIP_ADDR:
587                 getconf_str(buf, "c_ip_addr");
588                 set_str_val(curr, buf, default_value);
589                 setconf_str("c_ip_addr", buf);
590                 break;
591
592         case eCTDL_Port:
593                 portnum = getconf_int("c_port_number");
594                 set_int_val(curr, &portnum, default_value);
595                 setconf_int("c_port_number", portnum);
596                 break;
597
598         case eAuthType:
599                 auth = getconf_int("c_auth_mode");
600                 set_int_val(curr, &auth, default_value);
601                 setconf_int("c_auth_mode", auth);
602                 break;
603
604         case eLDAP_Host:
605                 getconf_str(buf, "c_ldap_host");
606                 if (IsEmptyStr(buf)) {
607                         strcpy(buf, "localhost");
608                 }
609                 set_str_val(curr, buf, default_value);
610                 setconf_str("c_ldap_host", buf);
611                 break;
612
613         case eLDAP_Port:
614                 lportnum = getconf_int("c_ldap_port");
615                 if (lportnum == 0) {
616                         lportnum = 389;
617                 }
618                 set_int_val(curr, &lportnum, default_value);
619                 setconf_int("c_ldap_port", lportnum);
620                 break;
621
622         case eLDAP_Base_DN:
623                 getconf_str(buf, "c_ldap_base_dn");
624                 set_str_val(curr, buf, default_value);
625                 setconf_str("c_ldap_base_dn", buf);
626                 break;
627
628         case eLDAP_Bind_DN:
629                 getconf_str(buf, "c_ldap_bind_dn");
630                 set_str_val(curr, buf, default_value);
631                 setconf_str("c_ldap_bind_dn", buf);
632                 break;
633
634         case eLDAP_Bind_PW:
635                 getconf_str(buf, "c_ldap_bind_pw");
636                 set_str_val(curr, buf, default_value);
637                 setconf_str("c_ldap_bind_pw", buf);
638                 break;
639         }
640 }
641
642
643 // Messages that are no longer in use.
644 // We keep them here so we don't lose the translations if we need them later.
645 void unused_messages(void) {
646         important_message(_("Setup finished"),
647                 _("Setup of the Citadel server is complete.\n"
648                 "If you will be using WebCit, please run its\n"
649                 "setup program now; otherwise, run './citadel'\n"
650                 "to log in.\n")
651         );
652         important_message(_("Setup failed"),
653                 _("Setup is finished, but the Citadel server failed to start.\n"
654                 "Go back and check your configuration.\n")
655         );
656         important_message(_("Setup finished"),
657                 _("Setup is finished.  You may now start the server.")
658         );
659 }
660
661
662 int main(int argc, char *argv[]) {
663         int a, i;
664         int curr;
665         char buf[1024]; 
666         char aaa[128];
667         char ctdldir[PATH_MAX]=CTDLDIR;
668         struct passwd *pw;
669         gid_t gid;
670         char *activity = NULL;
671         
672         // Keep a mild groove on
673         program_title = _("Citadel Server setup");
674
675         // set an invalid setup type
676         setup_type = (-1);
677
678         // parse command line args
679         for (a = 0; a < argc; ++a) {
680                 if (!strncmp(argv[a], "-u", 2)) {
681                         strcpy(aaa, argv[a]);
682                         strcpy(aaa, &aaa[2]);
683                         setup_type = atoi(aaa);
684                 }
685                 else if (!strncmp(argv[a], "-h", 2)) {
686                         safestrncpy(ctdldir, &argv[a][2], sizeof ctdldir);
687                 }
688         }
689
690         if (chdir(ctdldir) != 0) {
691                 fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno));
692                 exit(errno);
693         }
694
695         SetTitles();
696
697         // Connect to the running Citadel server.
698         char *connectingmsg = _("Connecting to Citadel server");
699         for (i=0; ((i<30) && (serv_sock < 0)) ; ++i) {          // wait for server to start up
700                 progress(connectingmsg, i, 30);
701                 serv_sock = uds_connectsock(file_citadel_admin_socket);
702                 sleep(1);
703         }
704         progress(connectingmsg, 30, 30);
705
706         if (serv_sock < 0) { 
707                 display_error(
708                         "%s: %s %s\n", 
709                         _("Setup could not connect to a running Citadel server."),
710                         strerror(errno), file_citadel_admin_socket
711                 );
712                 exit(1);
713         }
714
715         // read the server greeting
716         serv_gets(buf);
717         if (buf[0] != '2') {
718                 display_error("%s\n", buf);
719                 exit(2);
720         }
721
722         // Are we connected to the correct Citadel server?
723         serv_puts("INFO");
724         serv_gets(buf);
725         if (buf[0] != '1') {
726                 display_error("%s\n", buf);
727                 exit(3);
728         }
729         a = 0;
730         while (serv_gets(buf), strcmp(buf, "000")) {
731                 if (a == 5) {
732                         if (atoi(buf) != REV_LEVEL) {
733                                 display_error("%s\n", _("Your setup program and Citadel server are from different versions."));
734                                 exit(4);
735                         }
736                 }
737                 ++a;
738         }
739
740         printf("\n\n\n         *** %s ***\n\n", program_title);
741
742         // Go through a series of dialogs prompting for config info
743         for (curr = 1; curr < eMaxQuestions; ++curr) {
744                 edit_value(curr);
745
746                 if (    (curr == eAuthType)
747                         && (getconf_int("c_auth_mode") != AUTHMODE_LDAP)
748                         && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD)
749                 ) {
750                         curr += 5;      // skip LDAP questions if we're not authenticating against LDAP
751                 }
752
753                 if (curr == eSysAdminName) {
754                         if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { // for native auth mode, fetch the admin's existing pw
755                                 snprintf(buf, sizeof buf, "AGUP %s", admin_name);
756                                 serv_puts(buf);
757                                 serv_gets(buf);
758                                 if (buf[0] == '2') {
759                                         extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass);
760                                 }
761                         }
762                         else {
763                                 ++curr;         // skip the password question for non-native auth modes
764                         }
765                 }
766         }
767
768         if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) {
769                 gid = getgid();
770         }
771         else {
772                 gid = pw->pw_gid;
773         }
774
775         // setup now must be run after Citadel Server is already running, so we don't need this anymore.
776         //if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) {
777                 //display_error("%s\n", _("failed to create directories"));
778         //}
779                 
780         activity = _("Reconfiguring Citadel server");
781         progress(activity, 0, 5);
782         sleep(1);                                       // Let the message appear briefly
783
784         // Create the administrator account.  It's ok if the command fails if this user already exists.
785         if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
786                 progress(activity, 1, 5);
787                 snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass);
788                 serv_puts(buf);
789                 progress(activity, 2, 5);
790                 serv_gets(buf);
791         }
792         progress(activity, 3, 5);
793
794         // Assign the desired password and access level to the administrator account.
795         if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
796                 snprintf(buf, sizeof buf, "AGUP %s", admin_name);
797                 serv_puts(buf);
798                 progress(activity, 4, 5);
799                 serv_gets(buf);
800                 if (buf[0] == '2') {
801                         int admin_flags = extract_int(&buf[4], 2);
802                         int admin_times_called = extract_int(&buf[4], 3);
803                         int admin_msgs_posted = extract_int(&buf[4], 4);
804                         snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6",
805                                 admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted
806                         );
807                         serv_puts(buf);
808                         serv_gets(buf);
809                 }
810         }
811         progress(activity, 5, 5);
812
813         check_xinetd_entry();   // Check /etc/xinetd.d/telnet
814
815         // Restart citserver
816         activity = _("Restarting Citadel server to apply changes");
817         progress(activity, 0, 51);
818
819         serv_puts("TIME");
820         serv_gets(buf);
821         long original_start_time = extract_long(&buf[4], 3);
822
823         progress(activity, 1, 51);
824         serv_puts("DOWN 1");
825         progress(activity, 2, 51);
826         serv_gets(buf);
827         if (buf[0] != '2') {
828                 display_error("%s\n", buf);
829                 exit(6);
830         }
831
832         close(serv_sock);
833         serv_sock = (-1);
834
835         for (i=3; i<=6; ++i) {                                  // wait for server to shut down
836                 progress(activity, i, 51);
837                 sleep(1);
838         }
839
840         for (i=7; ((i<=48) && (serv_sock < 0)) ; ++i) {         // wait for server to start up
841                 progress(activity, i, 51);
842                 serv_sock = uds_connectsock(file_citadel_admin_socket);
843                 sleep(1);
844         }
845
846         progress(activity, 49, 51);
847         serv_gets(buf);
848
849         progress(activity, 50, 51);
850         serv_puts("TIME");
851         serv_gets(buf);
852         long new_start_time = extract_long(&buf[4], 3);
853
854         close(serv_sock);
855         progress(activity, 51, 51);
856
857         if ((original_start_time == new_start_time) || (new_start_time <= 0)) {
858                 display_error("%s\n", _("Setup failed to restart Citadel server.  Please restart it manually."));
859                 exit(7);
860         }
861
862         exit(0);
863         return 0;
864 }