]> code.citadel.org Git - citadel.git/blobdiff - citadel/citserver.c
threads are using signals and the GC code is #ifdef if available.
[citadel.git] / citadel / citserver.c
index df75a28a0d06c4f7c8e0d546d56134ef09ab1439..43adab030721f81580a34d019b336ce569898029 100644 (file)
@@ -3,6 +3,21 @@
  *
  * Main source module for the Citadel server
  *
+ * Copyright (c) 1987-2009 by the citadel.org team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include "sysdep.h"
@@ -58,6 +73,7 @@
 #include "policy.h"
 #include "control.h"
 #include "euidindex.h"
+#include "context.h"
 #include "svn_revision.h"
 
 #ifndef HAVE_SNPRINTF
 #include "ctdl_module.h"
 
 
-struct CitContext *ContextList = NULL;
-struct CitContext* next_session = NULL;
 char *unique_session_numbers;
 int ScheduledShutdown = 0;
 time_t server_startup_time;
 int panic_fd;
 
-/**
- * \brief print the actual stack frame.
+/*
+ * print the actual stack frame.
  */
 void cit_backtrace(void)
 {
@@ -97,8 +111,8 @@ void cit_backtrace(void)
 #endif
 }
 
-/**
- * \brief print the actual stack frame.
+/*
+ * print the actual stack frame.
  */
 void cit_panic_backtrace(int SigNum)
 {
@@ -129,6 +143,7 @@ void master_startup(void) {
        unsigned int seed;
        FILE *urandom;
        struct ctdlroom qrbuf;
+       int rv;
        
        CtdlLogPrintf(CTDL_DEBUG, "master_startup() started\n");
        time(&server_startup_time);
@@ -143,27 +158,27 @@ void master_startup(void) {
        check_ref_counts();
 
        CtdlLogPrintf(CTDL_INFO, "Creating base rooms (if necessary)\n");
-       create_room(config.c_baseroom,  0, "", 0, 1, 0, VIEW_BBS);
-       create_room(AIDEROOM,           3, "", 0, 1, 0, VIEW_BBS);
-       create_room(SYSCONFIGROOM,      3, "", 0, 1, 0, VIEW_BBS);
-       create_room(config.c_twitroom,  0, "", 0, 1, 0, VIEW_BBS);
+       CtdlCreateRoom(config.c_baseroom,       0, "", 0, 1, 0, VIEW_BBS);
+       CtdlCreateRoom(AIDEROOM,                3, "", 0, 1, 0, VIEW_BBS);
+       CtdlCreateRoom(SYSCONFIGROOM,           3, "", 0, 1, 0, VIEW_BBS);
+       CtdlCreateRoom(config.c_twitroom,       0, "", 0, 1, 0, VIEW_BBS);
 
        /* The "Local System Configuration" room doesn't need to be visible */
-        if (lgetroom(&qrbuf, SYSCONFIGROOM) == 0) {
+        if (CtdlGetRoomLock(&qrbuf, SYSCONFIGROOM) == 0) {
                 qrbuf.QRflags2 |= QR2_SYSTEM;
-                lputroom(&qrbuf);
+                CtdlPutRoomLock(&qrbuf);
         }
 
        /* Aide needs to be public postable, else we're not RFC conformant. */
-        if (lgetroom(&qrbuf, AIDEROOM) == 0) {
+        if (CtdlGetRoomLock(&qrbuf, AIDEROOM) == 0) {
                 qrbuf.QRflags2 |= QR2_SMTP_PUBLIC;
-                lputroom(&qrbuf);
+                CtdlPutRoomLock(&qrbuf);
         }
 
        CtdlLogPrintf(CTDL_INFO, "Seeding the pseudo-random number generator...\n");
        urandom = fopen("/dev/urandom", "r");
        if (urandom != NULL) {
-               fread(&seed, sizeof seed, 1, urandom);
+               rv = fread(&seed, sizeof seed, 1, urandom);
                fclose(urandom);
        }
        else {
@@ -228,53 +243,13 @@ void master_cleanup(int exitcode) {
        
        if (restart_server != 0)
                exit(1);
-       if ((running_as_daemon != 0) && (exitcode == 0))
+       if ((running_as_daemon != 0) && ((exitcode == 0) ))
                exitcode = CTDLEXIT_SHUTDOWN;
        exit(exitcode);
 }
 
 
 
-/*
- * Terminate a session.
- */
-void RemoveContext (struct CitContext *con)
-{
-       if (con==NULL) {
-               CtdlLogPrintf(CTDL_ERR,
-                       "WARNING: RemoveContext() called with NULL!\n");
-               return;
-       }
-       CtdlLogPrintf(CTDL_DEBUG, "RemoveContext() session %d\n", con->cs_pid);
-
-       /* Run any cleanup routines registered by loadable modules.
-        * Note: We have to "become_session()" because the cleanup functions
-        *       might make references to "CC" assuming it's the right one.
-        */
-       become_session(con);
-       logout();
-       PerformSessionHooks(EVT_STOP);
-       become_session(NULL);
-
-       CtdlLogPrintf(CTDL_NOTICE, "[%3d] Session ended.\n", con->cs_pid);
-
-       /* If the client is still connected, blow 'em away. */
-       CtdlLogPrintf(CTDL_DEBUG, "Closing socket %d\n", con->client_socket);
-       close(con->client_socket);
-
-       /* If using AUTHMODE_LDAP, free the DN */
-       if (con->ldap_dn) {
-               free(con->ldap_dn);
-               con->ldap_dn = NULL;
-       }
-
-       CtdlLogPrintf(CTDL_DEBUG, "Done with RemoveContext()\n");
-}
-
-
-
-
-
 /*
  * cmd_info()  -  tell the client about this server
  */
@@ -382,10 +357,7 @@ int is_public_client(void)
 
 #define LOCALHOSTSTR "127.0.0.1"
 
-       snprintf(public_clients_file, 
-                        sizeof public_clients_file,
-                        "%s/public_clients",
-                        ctdl_etc_dir);
+       snprintf(public_clients_file, sizeof public_clients_file, "%s/public_clients", ctdl_etc_dir);
 
        /*
         * Check the time stamp on the public_clients file.  If it's been
@@ -521,7 +493,8 @@ void cmd_iden(char *argbuf)
                (rev_level / 100),
                (rev_level % 100),
                desc,
-               CC->cs_host);
+               CC->cs_host
+       );
        cprintf("%d Ok\n",CIT_OK);
 }
 
@@ -665,8 +638,8 @@ void cmd_emsg(char *mname)
  * user also knows the rooms.
  */
 void GenerateRoomDisplay(char *real_room,
-                       struct CitContext *viewed,
-                       struct CitContext *viewer) {
+                       CitContext *viewed,
+                       CitContext *viewer) {
 
        int ra;
 
@@ -733,35 +706,19 @@ int CtdlAccessCheck(int required_level) {
 void cmd_term(char *cmdbuf)
 {
        int session_num;
-       struct CitContext *ccptr;
-       int found_it = 0;
-       int allowed = 0;
+       int terminated = 0;
 
        session_num = extract_int(cmdbuf, 0);
-       if (session_num == CC->cs_pid) {
+
+       terminated = CtdlTerminateOtherSession(session_num);
+
+       if (terminated < 0) {
                cprintf("%d You can't kill your own session.\n", ERROR + ILLEGAL_VALUE);
                return;
        }
 
-       CtdlLogPrintf(CTDL_DEBUG, "Locating session to kill\n");
-       begin_critical_section(S_SESSION_TABLE);
-       for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
-               if (session_num == ccptr->cs_pid) {
-                       found_it = 1;
-                       if ((ccptr->user.usernum == CC->user.usernum)
-                          || (CC->user.axlevel >= 6)) {
-                               allowed = 1;
-                               ccptr->kill_me = 1;
-                       }
-                       else {
-                               allowed = 0;
-                       }
-               }
-       }
-       end_critical_section(S_SESSION_TABLE);
-
-       if (found_it) {
-               if (allowed) {
+       if (terminated & TERM_FOUND) {
+               if (terminated == TERM_KILLED) {
                        cprintf("%d Session terminated.\n", CIT_OK);
                }
                else {
@@ -775,9 +732,6 @@ void cmd_term(char *cmdbuf)
 }
 
 
-
-
-
 /* 
  * get the paginator prompt
  */
@@ -785,6 +739,7 @@ void cmd_more(char *argbuf) {
        cprintf("%d %s\n", CIT_OK, config.c_moreprompt);
 }
 
+
 /*
  * echo 
  */
@@ -794,9 +749,8 @@ void cmd_echo(char *etext)
 }
 
 
-
 /* 
- * identify as internal program
+ * Perform privilege escalation for an internal program
  */
 void cmd_ipgm(char *argbuf)
 {
@@ -809,8 +763,7 @@ void cmd_ipgm(char *argbuf)
         */
        if (!CC->is_local_socket) {
                sleep(5);
-               cprintf("%d Authentication failed.\n",
-                       ERROR + PASSWORD_REQUIRED);
+               cprintf("%d Authentication failed.\n", ERROR + PASSWORD_REQUIRED);
        }
        else if (secret == config.c_ipgm_secret) {
                CC->internal_pgm = 1;
@@ -820,8 +773,7 @@ void cmd_ipgm(char *argbuf)
        }
        else {
                sleep(5);
-               cprintf("%d Authentication failed.\n",
-                       ERROR + PASSWORD_REQUIRED);
+               cprintf("%d Authentication failed.\n", ERROR + PASSWORD_REQUIRED);
                CtdlLogPrintf(CTDL_ERR, "Warning: ipgm authentication failed.\n");
                CC->kill_me = 1;
        }
@@ -857,9 +809,11 @@ void cmd_down(char *argbuf) {
        {
                cprintf(Reply, CIT_OK + SERVER_SHUTTING_DOWN); 
        }
+       CC->kill_me = 1; /* Even the DOWN command has to follow correct proceedure when disconecting */
        CtdlThreadStopAll();
 }
 
+
 /*
  * Halt the server without exiting the server process.
  */
@@ -872,6 +826,7 @@ void cmd_halt(char *argbuf) {
        shutdown_and_halt = 1;
 }
 
+
 /*
  * Schedule or cancel a server shutdown
  */
@@ -925,7 +880,7 @@ void cmd_asyn(char *argbuf)
  * RFC 1725 et al specify a PID to be placed in front of the nonce.
  * Quoth BTX: That would be stupid.
  */
-void generate_nonce(struct CitContext *con) {
+void generate_nonce(CitContext *con) {
        struct timeval tv;
 
        memset(con->cs_nonce, NONCE_SIZE, 0);
@@ -936,12 +891,10 @@ void generate_nonce(struct CitContext *con) {
 }
 
 
-
-
 /*
  * Back-end function for starting a session
  */
-void begin_session(struct CitContext *con)
+void begin_session(CitContext *con)
 {
        socklen_t len;
        struct sockaddr_in sin;
@@ -966,6 +919,7 @@ void begin_session(struct CitContext *con)
        generate_nonce(con);
        safestrncpy(con->cs_host, config.c_fqdn, sizeof con->cs_host);
        safestrncpy(con->cs_addr, "", sizeof con->cs_addr);
+       con->cs_UDSclientUID = -1;
        con->cs_host[sizeof con->cs_host - 1] = 0;
        len = sizeof sin;
        if (!CC->is_local_socket) {
@@ -978,6 +932,34 @@ void begin_session(struct CitContext *con)
        }
        else {
                strcpy(con->cs_host, "");
+#ifdef HAVE_STRUCT_UCRED
+               {
+                       /* as http://www.wsinnovations.com/softeng/articles/uds.html told us... */
+                       struct ucred credentials;
+                       socklen_t ucred_length = sizeof(struct ucred);
+                       
+                       /*fill in the user data structure */
+                       if(getsockopt(con->client_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) {
+                               CtdlLogPrintf(CTDL_NOTICE, "could obtain credentials from unix domain socket");
+                               
+                       }
+                       else {          
+                               /* the process ID of the process on the other side of the socket */
+                               /* credentials.pid; */
+                               
+                               /* the effective UID of the process on the other side of the socket  */
+                               con->cs_UDSclientUID = credentials.uid;
+                               
+                               /* the effective primary GID of the process on the other side of the socket */
+                               /* credentials.gid; */
+                               
+                               /* To get supplemental groups, we will have to look them up in our account
+                                  database, after a reverse lookup on the UID to get the account name.
+                                  We can take this opportunity to check to see if this is a legit account.
+                               */
+                       }
+               }
+#endif
        }
        con->cs_flags = 0;
        con->upload_type = UPL_FILE;
@@ -1009,36 +991,39 @@ void citproto_begin_session() {
                CC->kill_me = 1;
        }
        else {
-               cprintf("%d %s Citadel server ready.\n",
-                       CIT_OK, config.c_nodename);
+               cprintf("%d %s Citadel server ready.\n", CIT_OK, config.c_nodename);
+               CC->can_receive_im = 1;
        }
 }
 
 
-
 void cmd_noop(char *argbuf)
 {
        cprintf("%d%cok\n", CIT_OK, CtdlCheckExpress() );
 }
 
+
 void cmd_qnop(char *argbuf)
 {
        /* do nothing, this command returns no response */
 }
 
+
 void cmd_quit(char *argbuf)
 {
        cprintf("%d Goodbye.\n", CIT_OK);
        CC->kill_me = 1;
 }
 
+
 void cmd_lout(char *argbuf)
 {
        if (CC->logged_in) 
-               logout();
+               CtdlUserLogout();
        cprintf("%d logged out.\n", CIT_OK);
 }
 
+
 /*
  * This loop recognizes all server commands.
  */
@@ -1112,34 +1097,31 @@ void do_async_loop(void) {
 }
 
 
-
-
-
-
-
 /*****************************************************************************/
 /*                      MODULE INITIALIZATION STUFF                          */
 /*****************************************************************************/
 
 CTDL_MODULE_INIT(citserver)
 {
-       CtdlRegisterProtoHook(cmd_noop, "NOOP", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_qnop, "QNOP", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_quit, "QUIT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_lout, "LOUT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_asyn, "ASYN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_info, "INFO", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_mesg, "MESG", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_emsg, "EMSG", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_echo, "ECHO", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_more, "MORE", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_iden, "IDEN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_ipgm, "IPGM", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_term, "TERM", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_down, "DOWN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_halt, "HALT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_scdn, "SCDN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_time, "TIME", "Autoconverted. TODO: document me.");
+       if (!threading) {
+               CtdlRegisterProtoHook(cmd_noop, "NOOP", "no operation");
+               CtdlRegisterProtoHook(cmd_qnop, "QNOP", "no operation with no response");
+               CtdlRegisterProtoHook(cmd_quit, "QUIT", "log out and disconnect from server");
+               CtdlRegisterProtoHook(cmd_lout, "LOUT", "log out but do not disconnect from server");
+               CtdlRegisterProtoHook(cmd_asyn, "ASYN", "enable asynchronous server responses");
+               CtdlRegisterProtoHook(cmd_info, "INFO", "fetch server capabilities and configuration");
+               CtdlRegisterProtoHook(cmd_mesg, "MESG", "fetch system banners");
+               CtdlRegisterProtoHook(cmd_emsg, "EMSG", "submit system banners");
+               CtdlRegisterProtoHook(cmd_echo, "ECHO", "echo text back to the client");
+               CtdlRegisterProtoHook(cmd_more, "MORE", "fetch the paginator prompt");
+               CtdlRegisterProtoHook(cmd_iden, "IDEN", "identify the client software and location");
+               CtdlRegisterProtoHook(cmd_ipgm, "IPGM", "perform privilege escalation for internal programs");
+               CtdlRegisterProtoHook(cmd_term, "TERM", "terminate another running session");
+               CtdlRegisterProtoHook(cmd_down, "DOWN", "perform a server shutdown");
+               CtdlRegisterProtoHook(cmd_halt, "HALT", "halt the server without exiting the server process");
+               CtdlRegisterProtoHook(cmd_scdn, "SCDN", "schedule or cancel a server shutdown");
+               CtdlRegisterProtoHook(cmd_time, "TIME", "fetch the date and time from the server");
+       }
         /* return our Subversion id for the Log */
        return "$Id$";
 }