- Added constant sizes for usernames and the nonce in citadel.h
authorBrian Costello <btx@uncensored.citadel.org>
Mon, 14 Aug 2000 22:51:52 +0000 (22:51 +0000)
committerBrian Costello <btx@uncensored.citadel.org>
Mon, 14 Aug 2000 22:51:52 +0000 (22:51 +0000)
- The server now seeds its PRNG with the microsecond time at startup.  The
  random numbers are needed for the APOP auth scheme's nonce
- A nonce is displayed at the banner, conforming to the APOP RFCs
- Added MD5 (APOP) auth via a module PAS2 (password scheme 2)
  This will only work for "real" bbs accounts
- Added APOP command to serv_pop3
- Reorganized a couple of user commands

citadel/Makefile.in
citadel/citadel.c
citadel/citadel.h
citadel/citserver.c
citadel/serv_pop3.c
citadel/serv_pop3.h
citadel/server.h
citadel/user_ops.c
citadel/user_ops.h

index 91afc10279e7d0eaff782aa964e1670e48b7be69..b220a189dc93df3f45322c86c25708c9dd21bc13 100644 (file)
@@ -88,7 +88,7 @@ SOURCES=aidepost.c citadel.c citmail.c citserver.c client_chat.c commands.c \
        serv_smtp.c serv_pop3.c internet_addressing.c parsedate.c genstamp.c \
        domain.c clientsocket.c serv_inetcfg.c serv_rwho.c serv_bio.c \
        serv_moderate.c client_passwords.c serv_imap.c imap_tools.c \
-       serv_network.c
+       serv_network.c serv_pas2.c md5.c
 
 DEP_FILES=$(SOURCES:.c=.d)
 
@@ -105,12 +105,12 @@ serv_modules: $(SERV_MODULES)
 
 citadel$(EXEEXT): ipc_c_tcp$(CX) citadel$(CX) rooms$(CX) routines$(CX) \
        routines2$(CX) messages$(CX)  \
-       client_passwords$(CX) \
+       client_passwords$(CX) md5$(CX) \
        commands$(CX) client_chat$(CX) serv_info$(CX) tools$(CX) $(LIBOBJS)
        $(CC) ipc_c_tcp$(CX) citadel$(CX) rooms$(CX) routines$(CX) \
        routines2$(CX) messages$(CX) \
        commands$(CX) client_chat$(CX) serv_info$(CX) tools$(CX) \
-       client_passwords$(CX) \
+       client_passwords$(CX) md5$(CX) \
        $(LIBOBJS) $(LDFLAGS) -o citadel $(NETLIBS) $(CLIENT_PTLIBS)
 
 netpoll: netpoll.o config.o ipc_c_tcp.o tools.o $(LIBOBJS)
@@ -158,8 +158,8 @@ modules/serv_test.so: serv_test.mo
 modules/serv_test.mo: serv_test.mo
        ln -f serv_test.mo modules
 
-modules/serv_pop3.so: serv_pop3.mo
-       $(LINK_SHARED) -o modules/serv_pop3.so serv_pop3.mo
+modules/serv_pop3.so: serv_pop3.mo md5.mo
+       $(LINK_SHARED) -o modules/serv_pop3.so serv_pop3.mo md5.mo
 
 modules/serv_pop3.mo: serv_pop3.mo
        ln -f serv_pop3.mo modules
@@ -242,6 +242,17 @@ modules/imap_tools.mo: imap_tools.mo
 aidepost: aidepost.o config.o $(LIBOBJS)
        $(CC) aidepost.o config.o $(LIBOBJS) $(LDFLAGS) -o aidepost
 
+modules/serv_pas2.so: serv_pas2.mo md5.mo
+       $(LINK_SHARED) -o modules/serv_pas2.so serv_pas2.mo md5.mo
+
+modules/serv_pas2.mo: serv_pas2.mo
+       ln -f serv_pas2.mo modules
+
+modules/md5.mo: md5.mo
+       ln -f md5.mo modules
+
+
+
 #
 # 'netmailer' needs to run setuid because it generates headers for Internet
 # mail.  If it is not run setuid, all outgoing mail may always show as coming
index 9e4ffc9b9f13eeb114537227ba7ddc31da237618..e3a8e4c043b739f7e1b2767e325bde6836fac2c6 100644 (file)
 #include "client_passwords.h"
 #include "citadel_decls.h"
 #include "tools.h"
+#include "acconfig.h"
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
 #endif
 
+#include "md5.h"
+
 struct march {
        struct march *next;
        char march_name[ROOMNAMELEN];
        char march_floor;
        char march_order;
-};
+       };
 
 #define IFEXPERT if (userflags&US_EXPERT)
 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
@@ -834,6 +837,9 @@ int main(int argc, char **argv)
        int a, b, mcmd;
        char aaa[100], bbb[100];/* general purpose variables */
        char argbuf[32];        /* command line buf */
+       char nonce[NONCE_SIZE];
+       char *sptr, *sptr2;     /* USed to extract the nonce */
+       char hexstring[MD5_HEXSTRING_SIZE];
        volatile int termn8 = 0;
        int stored_password = 0;
        char password[256];
@@ -856,6 +862,29 @@ int main(int argc, char **argv)
                printf("%s\n", &aaa[4]);
                logoff(atoi(aaa));
        }
+
+/* If there is a [nonce] at the end, put the nonce in <nonce>, else nonce
+ * is zeroized.
+ */
+       
+       if ((sptr = strchr(aaa, '<')) == NULL)
+       {
+          nonce[0] = '\0';
+       }
+       else
+       {
+          if ((sptr2 = strchr(sptr, '>')) == NULL)
+          {
+             nonce[0] = '\0';
+          }
+          else
+          {
+             sptr2++;
+             *sptr2 = '\0';
+             strncpy(nonce, sptr, NONCE_SIZE);
+          }
+       }
+       
        get_serv_info();
 
        look_for_ansi();
@@ -876,10 +905,18 @@ GSTA:     /* See if we have a username and password on disk */
        if (rc_remember_passwords) {
                get_stored_password(hostbuf, portbuf, fullname, password);
                if (strlen(fullname) > 0) {
-                       sprintf(aaa, "USER %s", fullname);
+                       snprintf(aaa, sizeof(aaa)-1, "USER %s", fullname);
                        serv_puts(aaa);
                        serv_gets(aaa);
-                       sprintf(aaa, "PASS %s", password);
+                       if (nonce[0])
+                       {
+                               sprintf(aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring));
+                       }
+                       else    /* Else no APOP */
+                       {
+                               snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
+                       }
+                       
                        serv_puts(aaa);
                        serv_gets(aaa);
                        if (aaa[0] == '2') {
@@ -928,7 +965,16 @@ GSTA:      /* See if we have a username and password on disk */
                newprompt("\rPlease enter your password: ", password, -19);
        }
        strproc(password);
-       snprintf(aaa, sizeof aaa, "PASS %s", password);
+
+       if (nonce[0])
+       {
+               sprintf(aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring));
+       }
+       else    /* Else no APOP */
+       {
+                       snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
+       }
+       
        serv_puts(aaa);
        serv_gets(aaa);
        if (aaa[0] == '2') {
index 7e208054600c0403a005e7f5c279860ae015044f..aec23f41826ee7a53f3c9a4fc0ac79f78091c3d0 100644 (file)
  */
 typedef unsigned char CIT_UBYTE;
 
-#define ROOMNAMELEN    128
+/* Various length constants */
+
+#define ROOMNAMELEN    128             /* The size of the roomname structure */
+#define NONCE_SIZE     128             /* Added by <bc> to allow for APOP auth 
+                                        * it is BIG becuase there is a hostname
+                                        * in the nonce, as per the APOP RFC.
+                                        */
+                                        
+#define USERNAME_SIZE  32              /* The size of a username string */
 
 /*
  * Message expiration policy stuff
index 89f65d295c86c3f3a2f7d1adcd4c07438cdd792a..95085d2e8417987562996a803a29f172678db899 100644 (file)
@@ -21,6 +21,7 @@
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/time.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include "citadel.h"
@@ -51,6 +52,8 @@ int do_defrag = 0;
  * Various things that need to be initialized at startup
  */
 void master_startup(void) {
+       struct timeval tv;
+       
        lprintf(7, "Opening databases\n");
        open_databases();
 
@@ -65,7 +68,13 @@ void master_startup(void) {
        create_room(AIDEROOM,           3, "", 0);
        create_room(SYSCONFIGROOM,      3, "", 0);
        create_room(config.c_twitroom,  0, "", 0);
-       }
+
+/* Seed the PRNG */
+       
+       lprintf(7, "Seeding the pseudo-random number generator...\n");
+       gettimeofday(&tv, NULL);
+       srand(tv.tv_usec);
+}
 
 /*
  * Cleanup routine to be called when the server is shutting down.
@@ -744,6 +753,11 @@ void begin_session(struct CitContext *con)
        strcpy(con->cs_clientname, "(unknown)");
        strcpy(con->curr_user, NLI);
        strcpy(con->net_node,"");
+       con->fake_username[0] = '\0';
+       con->fake_postname[0] = '\0';
+       con->fake_hostname[0] = '\0';
+       con->fake_roomname[0] = '\0';
+       memset(con->cs_nonce, NONCE_SIZE, 0);
        snprintf(con->temp, sizeof con->temp, tmpnam(NULL));
        safestrncpy(con->cs_host, config.c_fqdn, sizeof con->cs_host);
        con->cs_host[sizeof con->cs_host - 1] = 0;
@@ -775,6 +789,8 @@ void begin_session(struct CitContext *con)
 
 
 void citproto_begin_session() {
+       struct timeval  tv;
+       
        if (CC->nologin==1) {
                cprintf("%d %s: Too many users are already online "
                        "(maximum is %d)\n",
@@ -782,8 +798,16 @@ void citproto_begin_session() {
                        config.c_nodename, config.c_maxsessions);
                }
        else {
-               cprintf("%d %s Citadel/UX server ready.\n",
-                       OK, config.c_nodename);
+               gettimeofday(&tv, NULL);
+               memset(CC->cs_nonce, NONCE_SIZE, 0);
+               snprintf(CC->cs_nonce, NONCE_SIZE, "<%d%ld@%s>", rand(), tv.tv_usec, config.c_nodename);
+
+/* RFC 1725 et al specify a PID to be placed in front of the nonce.
+ * Quoth BTX: That would be stupid.
+ */
+               
+               cprintf("%d %s Citadel/UX server ready %s.\n",
+                       OK, config.c_nodename, CC->cs_nonce);
                }
 }
 
index 2827c7cdef883ca2088a29ab828e67964859ae43..715445e8e41e9e7651636482f4ce67804fac8ca3 100644 (file)
@@ -14,6 +14,8 @@
  *    method  of authentication which would require some major changes to the
  *    Citadel server core.
  *
+ *    This is no longer true- APOP is implemented.
+ *
  * -> The deprecated "LAST" command is included in this implementation, because
  *    there exist mail clients which insist on using it (such as Bynari
  *    TradeMail, and certain versions of Eudora).
@@ -33,6 +35,7 @@
 #include <sys/wait.h>
 #include <string.h>
 #include <limits.h>
+#include <ctype.h>
 #include "citadel.h"
 #include "server.h"
 #include <time.h>
@@ -49,7 +52,7 @@
 #include "tools.h"
 #include "internet_addressing.h"
 #include "serv_pop3.h"
-
+#include "md5.h"
 
 long SYM_POP3;
 
@@ -80,15 +83,19 @@ void pop3_cleanup_function(void) {
  * Here's where our POP3 session begins its happy day.
  */
 void pop3_greeting(void) {
-
+       struct timeval  tv;
+       
        strcpy(CC->cs_clientname, "POP3 session");
+       gettimeofday(&tv, NULL);
+       memset(CC->cs_nonce, NONCE_SIZE, 0);
+       snprintf(CC->cs_nonce, NONCE_SIZE, "<%d%ld@%s>", rand(), tv.tv_usec, config.c_fqdn);
        CC->internal_pgm = 1;
        CtdlAllocUserData(SYM_POP3, sizeof(struct citpop3));
        POP3->msgs = NULL;
        POP3->num_msgs = 0;
 
-       cprintf("+OK Welcome to the Citadel/UX POP3 server at %s\r\n",
-               config.c_fqdn);
+       cprintf("+OK Welcome to the Citadel/UX POP3 server %s\r\n",
+               CC->cs_nonce, config.c_fqdn);
 }
 
 
@@ -169,27 +176,88 @@ int pop3_grab_mailbox(void) {
        return(POP3->num_msgs);
 }
 
+void pop3_login(void)
+{
+       int msgs;
+       
+       msgs = pop3_grab_mailbox();
+       if (msgs >= 0) {
+               cprintf("+OK %s is logged in (%d messages)\r\n",
+                       CC->usersupp.fullname, msgs);
+               lprintf(9, "POP3 password login successful\n");
+       }
+       else {
+               cprintf("-ERR Can't open your mailbox\r\n");
+       }
+       
+}
+
+void pop3_apop(char *argbuf)
+{
+   char username[256];
+   char userdigest[MD5_HEXSTRING_SIZE];
+   char realdigest[MD5_HEXSTRING_SIZE];
+   char *sptr;
+   
+   if (CC->logged_in)
+   {
+       cprintf("-ERR You are already logged in; not in the AUTHORIZATION phase.\r\n");
+       return;
+   }
+   
+   if ((sptr = strchr(argbuf, ' ')) == NULL)
+   {
+       cprintf("Invalid APOP line.\r\n");
+       return;
+   }
+   
+   *sptr++ = '\0';
+   
+   while ((*sptr) && isspace(*sptr))
+      sptr++;
+   
+   strncpy(username, argbuf, sizeof(username)-1);
+   username[sizeof(username)-1] = '\0';
+   
+   memset(userdigest, MD5_HEXSTRING_SIZE, 0);
+   strncpy(userdigest, sptr, MD5_HEXSTRING_SIZE-1);
+   
+   if (CtdlLoginExistingUser(username) != login_ok)
+   {
+       cprintf("-ERR No such user.\r\n");
+       return;
+   }
+   
+   if (getuser(&CC->usersupp, CC->curr_user))
+   {
+       cprintf("-ERR No such user.\r\n");
+       return;
+   }
+   
+   make_apop_string(CC->usersupp.password, CC->cs_nonce, realdigest);
+   if (!strncasecmp(realdigest, userdigest, MD5_HEXSTRING_SIZE-1))
+   {
+       pop3_login();
+   }
+   else
+   {
+       cprintf("-ERR That is NOT the password!  Go away!\r\n");
+   }
+}
+
+
 /*
  * Authorize with password (implements POP3 "PASS" command)
  */
 void pop3_pass(char *argbuf) {
        char password[256];
-       int msgs;
 
        strcpy(password, argbuf);
        striplt(password);
 
        lprintf(9, "Trying <%s>\n", password);
        if (CtdlTryPassword(password) == pass_ok) {
-               msgs = pop3_grab_mailbox();
-               if (msgs >= 0) {
-                       cprintf("+OK %s is logged in (%d messages)\r\n",
-                               CC->usersupp.fullname, msgs);
-                       lprintf(9, "POP3 password login successful\n");
-               }
-               else {
-                       cprintf("-ERR Can't open your mailbox\r\n");
-               }
+               pop3_login();
        }
        else {
                cprintf("-ERR That is NOT the password!  Go away!\r\n");
@@ -493,6 +561,11 @@ void pop3_command_loop(void) {
                pop3_pass(&cmdbuf[5]);
        }
 
+       else if (!strncasecmp(cmdbuf, "APOP", 4))
+       {
+               pop3_apop(&cmdbuf[5]);
+       }
+
        else if (!CC->logged_in) {
                cprintf("-ERR Not logged in.\r\n");
        }
@@ -540,6 +613,7 @@ void pop3_command_loop(void) {
 char *Dynamic_Module_Init(void)
 {
        SYM_POP3 = CtdlGetDynamicSymbol();
+       printf("Registering POP3 port %d\n", config.c_pop3_port);
        CtdlRegisterServiceHook(config.c_pop3_port,
                                NULL,
                                pop3_greeting,
index fbb8ef24f77b400305dc627707316f2d83c2c64e..40b527c0cd3d9fb88fba4b900ae04c95cb5a11a7 100644 (file)
@@ -29,3 +29,5 @@ void pop3_user(char *argbuf);
 void pop3_pass(char *argbuf);
 void pop3_list(char *argbuf);
 void pop3_command_loop(void);
+void pop3_login(void);
+
index 9f9e10fb0bdd64799b779b0098ad9fdd6dd8a3b7..1e44a2e439505b2159052e4efba19b5cf3e6c78e 100644 (file)
@@ -58,7 +58,7 @@ struct CitContext {
        int state;              /* thread state (see CON_ values below) */
        int kill_me;            /* Set to nonzero to flag for termination */
 
-       char curr_user[32];     /* name of current user */
+       char curr_user[USERNAME_SIZE];  /* name of current user */
        int logged_in;          /* logged in */
        int internal_pgm;       /* authenticated as internal program */
        char temp[32];          /* temp file name */
@@ -82,6 +82,9 @@ struct CitContext {
        char cs_clientname[32]; /* name of client software */
        char cs_host[26];       /* host logged in from */
 
+       /* Beginning of cryptography - session nonce */
+       char cs_nonce[NONCE_SIZE];              /* The nonce for this session's next auth transaction */
+
        FILE *download_fp;      /* Fields relating to file transfer */
        FILE *upload_fp;
        char upl_file[256];
@@ -100,10 +103,11 @@ struct CitContext {
        int disable_exp;        /* Set to 1 to disable incoming pages */
 
        /* Masquerade... */
-       char fake_username[32]; /* Fake username <bc>                */
-       char fake_postname[32]; /* Fake postname <bc>                */
+       char fake_username[USERNAME_SIZE];      /* Fake username <bc>                */
+       char fake_postname[USERNAME_SIZE];      /* Fake postname <bc>                */
        char fake_hostname[25]; /* Name of the fake hostname <bc>    */
        char fake_roomname[ROOMNAMELEN];        /* Name of the fake room <bc> */
+       
 
        /* Dynamically allocated session data */
        struct CtdlSessData *FirstSessData;
@@ -147,7 +151,7 @@ struct ChatLine {
        int chat_seq;
        time_t chat_time;
        char chat_text[256];
-       char chat_username[32];
+       char chat_username[USERNAME_SIZE];
        char chat_room[ROOMNAMELEN];
 };
 
index 3f9033b4b89e7432a9a47fbdc500643803ebfa0f..ce88b2cd62ba6992ca4f165b99267f1ace08834a 100644 (file)
@@ -354,10 +354,6 @@ void session_startup(void) {
 
        lgetuser(&CC->usersupp,CC->curr_user);
        ++(CC->usersupp.timescalled);
-       CC->fake_username[0] = '\0';
-       CC->fake_postname[0] = '\0';
-       CC->fake_hostname[0] = '\0';
-       CC->fake_roomname[0] = '\0';
        time(&CC->usersupp.lastcall);
 
        /* If this user's name is the name of the system administrator
@@ -464,6 +460,12 @@ static int validpw(uid_t uid, const char *pass)
        }
 #endif
 
+void do_login()
+{
+       (CC->logged_in) = 1;
+       session_startup();
+       logged_in_response();
+}
 
 
 int CtdlTryPassword(char *password)
@@ -499,8 +501,7 @@ int CtdlTryPassword(char *password)
 #endif
 
        if (!code) {
-               (CC->logged_in) = 1;
-               session_startup();
+               do_login();
                return pass_ok;
                }
        else {
@@ -530,7 +531,6 @@ void cmd_pass(char *buf)
                        cprintf("%d Wrong password.\n", ERROR);
                        return;
                case pass_ok:
-                       logged_in_response();
                        return;
                cprintf("%d Can't find user record!\n",
                        ERROR+INTERNAL_ERROR);
index 79bc46bb52d6ff645de2160e7a6ac3f891617630..b023eef299209f8d567f4bce48ab0f672ff05b34 100644 (file)
@@ -13,6 +13,7 @@ void logout (struct CitContext *who);
 void cmd_pass (char *buf);
 int purge_user (char *pname);
 int create_user (char *newusername);
+void do_login(void);
 void cmd_newu (char *cmdbuf);
 void cmd_setp (char *new_pw);
 void cmd_getu (void);