X-Git-Url: https://code.citadel.org/?p=citadel.git;a=blobdiff_plain;f=citadel%2Fcontext.c;h=88ddbe21bd6581f3693bfafa0f52612e5e29c021;hp=95bdc46f1bb342a1f7d41336088ecf5f65d92403;hb=e55c9fac2d5ce1ccc9239fb4155428f9c7d1bb6d;hpb=b989eeb350a72848f3db338f7d3300844a6b53f7 diff --git a/citadel/context.c b/citadel/context.c index 95bdc46f1..88ddbe21b 100644 --- a/citadel/context.c +++ b/citadel/context.c @@ -2,98 +2,32 @@ * Citadel context management stuff. * Here's where we (hopefully) have all the code that manipulates contexts. * - * Copyright (c) 1987-2011 by the citadel.org team + * Copyright (c) 1987-2018 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 as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. + * 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. - * - * 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" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* -#include -*/ - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "sysdep_decls.h" -#include "citserver.h" -#include "support.h" -#include "config.h" -#include "database.h" -#include "housekeeping.h" -#include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */ -#include "ecrash.h" - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#ifndef HAVE_SNPRINTF -#include "snprintf.h" -#endif - #include "ctdl_module.h" -#include "threads.h" +#include "serv_extensions.h" +#include "citserver.h" #include "user_ops.h" +#include "locate_host.h" +#include "context.h" #include "control.h" - - +#include "config.h" pthread_key_t MyConKey; /* TSD key for MyContext() */ - - CitContext masterCC; CitContext *ContextList = NULL; - time_t last_purge = 0; /* Last dead session purge */ int num_sessions = 0; /* Current number of sessions */ +int next_pid = 0; /* Flag for single user mode */ static int want_single_user = 0; @@ -116,6 +50,7 @@ int CtdlTrySingleUser(void) return can_do; } + void CtdlEndSingleUser(void) { begin_critical_section(S_SINGLE_USER); @@ -129,21 +64,19 @@ int CtdlWantSingleUser(void) return want_single_user; } + int CtdlIsSingleUser(void) { if (want_single_user) { /* check for only one context here */ if (num_sessions == 1) - return TRUE; + return 1; } - return FALSE; + return 0; } - - - /* * Locate a context by its session number and terminate it if the user is able. * User can NOT terminate their current session. @@ -152,26 +85,38 @@ int CtdlIsSingleUser(void) */ int CtdlTerminateOtherSession (int session_num) { + struct CitContext *CCC = CC; int ret = 0; CitContext *ccptr; + int aide; - if (session_num == CC->cs_pid) { - return TERM_NOTALLOWED; - } + if (session_num == CCC->cs_pid) return TERM_NOTALLOWED; - syslog(LOG_DEBUG, "Locating session to kill\n"); + aide = ( (CCC->user.axlevel >= AxAideU) || (CCC->internal_pgm) ) ; + + syslog(LOG_DEBUG, "context: locating session to kill"); begin_critical_section(S_SESSION_TABLE); for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (session_num == ccptr->cs_pid) { ret |= TERM_FOUND; - if ((ccptr->user.usernum == CC->user.usernum) - || (CC->user.axlevel >= AxAideU)) { + if ((ccptr->user.usernum == CCC->user.usernum) || aide) { ret |= TERM_ALLOWED; - ccptr->kill_me = KILLME_ADMIN_TERMINATE; } + break; } } - end_critical_section(S_SESSION_TABLE); + + if (((ret & TERM_FOUND) != 0) && ((ret & TERM_ALLOWED) != 0)) + { + if (ccptr->user.usernum == CCC->user.usernum) + ccptr->kill_me = KILLME_ADMIN_TERMINATE; + else + ccptr->kill_me = KILLME_IDLE; + end_critical_section(S_SESSION_TABLE); + } + else + end_critical_section(S_SESSION_TABLE); + return ret; } @@ -276,18 +221,16 @@ void terminate_idle_sessions(void) { CitContext *ccptr; time_t now; - int session_to_kill; int killed = 0; int longrunners = 0; now = time(NULL); - session_to_kill = 0; begin_critical_section(S_SESSION_TABLE); for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if ( (ccptr != CC) - && (config.c_sleeping > 0) - && (now - (ccptr->lastcmd) > config.c_sleeping) + && (CtdlGetConfigLong("c_sleeping") > 0) + && (now - (ccptr->lastcmd) > CtdlGetConfigLong("c_sleeping")) ) { if (!ccptr->dont_term) { ccptr->kill_me = KILLME_IDLE; @@ -299,10 +242,12 @@ void terminate_idle_sessions(void) } } end_critical_section(S_SESSION_TABLE); - if (killed > 0) - syslog(LOG_INFO, "Scheduled %d idle sessions for termination\n", killed); - if (longrunners > 0) - syslog(LOG_INFO, "Didn't terminate %d protected idle sessions", longrunners); + if (killed > 0) { + syslog(LOG_INFO, "context: scheduled %d idle sessions for termination", killed); + } + if (longrunners > 0) { + syslog(LOG_INFO, "context: did not terminate %d protected idle sessions", longrunners); + } } @@ -318,7 +263,7 @@ void terminate_all_sessions(void) for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (ccptr->client_socket != -1) { - syslog(LOG_INFO, "terminate_all_sessions() is murdering %s", ccptr->curr_user); + syslog(LOG_INFO, "context: terminate_all_sessions() is murdering %s CC[%d]", ccptr->curr_user, ccptr->cs_pid); close(ccptr->client_socket); ccptr->client_socket = -1; killed++; @@ -326,7 +271,7 @@ void terminate_all_sessions(void) } end_critical_section(S_SESSION_TABLE); if (killed > 0) { - syslog(LOG_INFO, "Flushed %d stuck sessions\n", killed); + syslog(LOG_INFO, "context: flushed %d stuck sessions", killed); } } @@ -338,15 +283,15 @@ void terminate_all_sessions(void) void RemoveContext (CitContext *con) { const char *c; - if (con==NULL) { - syslog(LOG_ERR, "WARNING: RemoveContext() called with NULL!\n"); + if (con == NULL) { + syslog(LOG_ERR, "context: RemoveContext() called with NULL, this should not happen"); return; } c = con->ServiceName; - if (c == NULL) + if (c == NULL) { c = "WTF?"; - syslog(LOG_DEBUG, "RemoveContext(%s) session %d\n", c, con->cs_pid); - cit_backtrace (); + } + syslog(LOG_DEBUG, "context: RemoveContext(%s) session %d", c, con->cs_pid); /* Run any cleanup routines registered by loadable modules. * Note: We have to "become_session()" because the cleanup functions @@ -358,7 +303,7 @@ void RemoveContext (CitContext *con) client_close(); /* If the client is still connected, blow 'em away. */ become_session(NULL); - syslog(LOG_NOTICE, "[%3d] Session ended.\n", con->cs_pid); + syslog(LOG_INFO, "context: [%3d]SRV[%s] Session ended.", con->cs_pid, c); /* * If the client is still connected, blow 'em away. @@ -366,7 +311,7 @@ void RemoveContext (CitContext *con) */ if (con->client_socket > 0) { - syslog(LOG_NOTICE, "Closing socket %d\n", con->client_socket); + syslog(LOG_INFO, "context: closing socket %d", con->client_socket); close(con->client_socket); } @@ -375,14 +320,14 @@ void RemoveContext (CitContext *con) free(con->ldap_dn); con->ldap_dn = NULL; } - + FreeStrBuf(&con->StatusMessage); FreeStrBuf(&con->MigrateBuf); FreeStrBuf(&con->RecvBuf.Buf); if (con->cached_msglist) { free(con->cached_msglist); } - syslog(LOG_DEBUG, "Done with RemoveContext()\n"); + syslog(LOG_DEBUG, "context: done with RemoveContext()"); } @@ -395,11 +340,10 @@ void RemoveContext (CitContext *con) */ CitContext *CreateNewContext(void) { CitContext *me; - static int next_pid = 0; me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { - syslog(LOG_ALERT, "citserver: can't allocate memory!!\n"); + syslog(LOG_ERR, "citserver: malloc() failed: %m"); return NULL; } memset(me, 0, sizeof(CitContext)); @@ -445,11 +389,10 @@ CitContext *CreateNewContext(void) { */ CitContext *CloneContext(CitContext *CloneMe) { CitContext *me; - static int next_pid = 0; me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { - syslog(LOG_ALERT, "citserver: can't allocate memory!!\n"); + syslog(LOG_ERR, "citserver: malloc() failed: %m"); return NULL; } memcpy(me, CloneMe, sizeof(CitContext)); @@ -471,7 +414,10 @@ CitContext *CloneContext(CitContext *CloneMe) { me->openid_data = NULL; me->ldap_dn = NULL; me->session_specific_data = NULL; + + me->CIT_ICAL = NULL; + me->cached_msglist = NULL; me->download_fp = NULL; me->upload_fp = NULL; me->client_socket = 0; @@ -524,6 +470,96 @@ CitContext *CtdlGetContextArray(int *count) +/* + * Back-end function for starting a session + */ +void begin_session(CitContext *con) +{ + /* + * Initialize some variables specific to our context. + */ + con->logged_in = 0; + con->internal_pgm = 0; + con->download_fp = NULL; + con->upload_fp = NULL; + con->cached_msglist = NULL; + con->cached_num_msgs = 0; + con->FirstExpressMessage = NULL; + time(&con->lastcmd); + time(&con->lastidle); + strcpy(con->lastcmdname, " "); + strcpy(con->cs_clientname, "(unknown)"); + strcpy(con->curr_user, NLI); + *con->fake_username = '\0'; + *con->fake_hostname = '\0'; + *con->fake_roomname = '\0'; + *con->cs_clientinfo = '\0'; + safestrncpy(con->cs_host, CtdlGetConfigStr("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; + if (!CC->is_local_socket) { + locate_host(con->cs_host, sizeof con->cs_host, + con->cs_addr, sizeof con->cs_addr, + con->client_socket + ); + } + else { + con->cs_host[0] = 0; + con->cs_addr[0] = 0; +#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)) { + syslog(LOG_ERR, "context: 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. + */ + snprintf(con->cs_clientinfo, sizeof(con->cs_clientinfo), + "PID: "F_PID_T"; UID: "F_UID_T"; GID: "F_XPID_T" ", + credentials.pid, + credentials.uid, + credentials.gid); + } + } +#endif + } + con->cs_flags = 0; + + con->nologin = 0; + if (((CtdlGetConfigInt("c_maxsessions") > 0)&&(num_sessions > CtdlGetConfigInt("c_maxsessions"))) || CtdlWantSingleUser()) { + con->nologin = 1; + } + + if (!CC->is_local_socket) { + syslog(LOG_INFO, "context: session (%s) started from %s (%s)", con->ServiceName, con->cs_host, con->cs_addr); + } + else { + syslog(LOG_INFO, "context: session (%s) started via local socket with uid=%d", con->ServiceName, con->cs_UDSclientUID); + } + + /* Run any session startup routines registered by loadable modules */ + PerformSessionHooks(EVT_START); +} + + /* * This function fills in a context and its user field correctly * Then creates/loads that user @@ -544,16 +580,16 @@ void CtdlFillSystemContext(CitContext *context, char *name) context->state = CON_SYS; context->ServiceName = name; - /* internal_create_user has the side effect of loading the user regardless of wether they + /* internal_create_user has the side effect of loading the user regardless of whether they * already existed or needed to be created */ - internal_create_user (sysname, len, &(context->user), -1) ; + internal_create_user(sysname, &(context->user), -1) ; /* Check to see if the system user needs upgrading */ if (context->user.usernum == 0) { /* old system user with number 0, upgrade it */ context->user.usernum = get_new_user_number(); - syslog(LOG_DEBUG, "Upgrading system user \"%s\" from user number 0 to user number %ld\n", context->user.fullname, context->user.usernum); + syslog(LOG_INFO, "context: upgrading system user \"%s\" from user number 0 to user number %ld", context->user.fullname, context->user.usernum); /* add user to the database */ CtdlPutUser(&(context->user)); cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1); @@ -587,7 +623,7 @@ void context_cleanup(void) rem = ptr->next; --num_sessions; - syslog(LOG_DEBUG, "context_cleanup(): Purging session #%d %s\n", ptr->cs_pid, ptr->ServiceName); + syslog(LOG_DEBUG, "context: context_cleanup() purging session %d", ptr->cs_pid); RemoveContext(ptr); free (ptr); ptr = rem; @@ -647,7 +683,7 @@ void dead_session_purge(int force) { * is allocated privately on this thread's stack. */ while (rem != NULL) { - syslog(LOG_DEBUG, "dead_session_purge(): purging session %d, reason=%d\n", rem->cs_pid, rem->kill_me); + syslog(LOG_DEBUG, "context: dead_session_purge() purging session %d, reason=%d", rem->cs_pid, rem->kill_me); RemoveContext(rem); ptr = rem; rem = rem->next; @@ -678,7 +714,7 @@ void InitializeMasterCC(void) { */ void set_async_waiting(struct CitContext *ccptr) { - syslog(LOG_DEBUG, "Setting async_waiting flag for session %d\n", ccptr->cs_pid); + syslog(LOG_DEBUG, "context: setting async_waiting flag for session %d", ccptr->cs_pid); if (ccptr->is_async) { ccptr->async_waiting++; if (ccptr->state == CON_IDLE) { @@ -686,3 +722,11 @@ void set_async_waiting(struct CitContext *ccptr) } } } + + +CTDL_MODULE_INIT(session) +{ + if (!threading) { + } + return "session"; +}