/* * $Id: session.c,v 0.12 1992/04/14 17:18:33 ceder Exp $ * Copyright (C) 1991 Lysator Academic Computer Association. * * This file is part of the LysKOM server. * * LysKOM 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 1, or (at your option) * any later version. * * LysKOM 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 LysKOM; see the file COPYING. If not, write to * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN, * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. * * Please mail bug reports to bug-lyskom@lysator.liu.se. */ /* * session.c * * Session control and miscellaneous. */ static char *rcsid = "$Id: session.c,v 0.12 1992/04/14 17:18:33 ceder Exp $"; #include <time.h> #include <stdlib.h> #include "lyskomd.h" #include <kom-types.h> #include <services.h> #include "manipulate.h" #include "cache.h" #include "com.h" #include "connections.h" #include "send-async.h" #include <server/smalloc.h> #include "log.h" #include <kom-errno.h> #include "config.h" #include "internal-connections.h" /* * Create an oldstyle username, user%host.domain@host.domain. * The RESULT must be initialized to a string (such as EMPTY_STRING). * A new string will be allocated in RESULT. (The old will be freed). */ static void create_oldstyle_username(String *result, Connection *connection) { if ( s_strcpy(result, connection->username) != OK ) restart_kom("create_oldstyle_username(): strcpy\n"); if ( s_strcat(result, s_fcrea_str((const unsigned char *)"@")) != OK ) restart_kom("create_oldstyle_username: s_strcat\n"); if ( s_strcat(result, connection->hostname) != OK ) restart_kom("prot_a_parse_packet: s_strcat II\n"); } /* * This function is called whenever a person leaves a conf, * i e when he pepsi():s or logout():s. */ extern void leave_conf(void) { Membership * mship; if (active_connection->cwc != 0 ) { if ((mship = locate_membership( active_connection->cwc, ACT_P )) != NULL ) { time(&mship->last_time_read); mark_person_as_changed (active_connection->pers_no); } else { log("ERROR: leave_conf(): Can't find membership of cwc.\n"); } cached_unlock_conf( active_connection->cwc ); active_connection->cwc = 0; } } /* * Log in as user pers_no. If ACTPERS is a supervisor of pers_no the login * will succeed regardless of the passwd. An logout() will automatically * be performed if ACTPERS is logged in. */ extern Success login_old (Pers_no pers_no, const String passwd) { Person *pers_p; GET_P_STAT(pers_p, pers_no, FAILURE); #if 0 if ( !logins_allowed && !pers_p->privileges.wheel) { kom_errno = KOM_LOGIN_DISALLOWED; return FAILURE; } #endif if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) && chk_passwd(pers_p->pwd, passwd) == FAILURE ) { kom_errno = KOM_PWD; return FAILURE; } logout(); /*+++ How many tries are allowed before disconnection? */ active_connection->invisible = FALSE; ACTPERS = pers_no; ACT_P = pers_p; cached_lock_person(pers_no); pers_p->last_login = time(&active_connection->session_start); ++pers_p->sessions; s_strcpy(&pers_p->username, active_connection->username); /* A Person should have separate fields for ident_user and hostname. But for now, we use the syntax username(ident_user)@hostname. */ if (!s_empty(active_connection->ident_user)) { if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)"(")) != OK ) restart_kom("login: s_strcat (\n"); if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK ) restart_kom("login: s_strcat ident_user\n"); if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)")")) != OK ) restart_kom("login: s_strcat )\n"); } if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)"@")) != OK ) restart_kom("prot_a_parse_packet: s_strcat\n"); if ( s_strcat(&pers_p->username, active_connection->hostname) != OK ) restart_kom("prot_a_parse_packet: s_strcat II\n"); mark_person_as_changed( pers_no ); async_login(ACTPERS, active_connection->session_no); return OK; } /* * Log in as user pers_no. If ACTPERS is a supervisor of pers_no the login * will succeed regardless of the passwd. An logout() will automatically * be performed if ACTPERS is logged in. */ extern Success login (Pers_no pers_no, const String passwd, Bool invisible) { Person *pers_p; GET_P_STAT(pers_p, pers_no, FAILURE); #if 0 if ( !logins_allowed && !pers_p->privileges.wheel) { kom_errno = KOM_LOGIN_DISALLOWED; return FAILURE; } #endif if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) && chk_passwd(pers_p->pwd, passwd) == FAILURE ) { kom_errno = KOM_PWD; return FAILURE; } logout(); /*+++ How many tries are allowed before disconnection? */ active_connection->invisible = !!invisible; /* Normalize 17. */ ACTPERS = pers_no; ACT_P = pers_p; cached_lock_person(pers_no); pers_p->last_login = time(&active_connection->session_start); ++pers_p->sessions; s_strcpy(&pers_p->username, active_connection->username); /* A Person should have separate fields for ident_user and hostname. But for now, we use the syntax username(ident_user)@hostname. */ if (!s_empty(active_connection->ident_user)) { if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)"(")) != OK ) restart_kom("login: s_strcat (\n"); if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK ) restart_kom("login: s_strcat ident_user\n"); if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)")")) != OK ) restart_kom("login: s_strcat )\n"); } if ( s_strcat(&pers_p->username, s_fcrea_str((const unsigned char *)"@")) != OK ) restart_kom("prot_a_parse_packet: s_strcat\n"); if ( s_strcat(&pers_p->username, active_connection->hostname) != OK ) restart_kom("prot_a_parse_packet: s_strcat II\n"); mark_person_as_changed( pers_no ); if (!active_connection->invisible) async_login(ACTPERS, active_connection->session_no); return OK; } /* * Log out. Does not disconnect the client. The person is also automatically * logged out if the connection is closed. Takes no action if noone is logged * in on this line. Never fails. */ extern Success logout( void ) { if ( ACTPERS != 0 ) /* Is he logged in? Then log him out. */ { if (!active_connection->invisible) { async_i_am_off( ACTPERS ); async_logout( ACTPERS, active_connection->session_no ); } leave_conf(); ACT_P->total_time_present += difftime(time(&ACT_P->last_login), active_connection->session_start); cached_unlock_person( ACTPERS ); mark_person_as_changed( ACTPERS ); } s_clear(&active_connection -> what_am_i_doing); active_connection->person = NULL; active_connection->cwc = 0; active_connection->pers_no = 0; active_connection->ena_level = 0; return OK; } /* * Change Conference. * * You are not allowed to change to a conference unless you are a * member in the conference. * * You can pepsi(0) to indicate that you are no longer in a certain * conference. * * There are two reasons to use this call: * 1) Other persons want to know what you are doing. * 2) When the server checks that you have permission to * read a certain text it first checks if you current working * conference is a recipient of the text, since that is a * cheap test. If that test fails it will have to read in the * conference structs for the recipients of the text until it * finds an open one. * * In the future the server might read in the conference in advance when * someone pepsi's to it to allow faster response times. */ extern Success pepsi (Conf_no conference) { Who_info info = EMPTY_WHO_INFO; CHK_LOGIN(FAILURE); if ( conference != 0 ) { CHK_EXIST(conference, FAILURE); if ( locate_membership( conference, ACT_P) == NULL ) { kom_errno = KOM_NOT_MEMBER; return FAILURE; } } leave_conf(); active_connection->cwc = conference; if ( conference != 0 ) cached_lock_conf( conference ); if (!active_connection->invisible) { info.person = ACTPERS; info.what_am_i_doing = active_connection->what_am_i_doing; info.working_conference = conference; info.session_no = active_connection->session_no; /* Bug compatibility. */ create_oldstyle_username(&info.username, active_connection); async_i_am_on(info); s_clear(&info.username); } return OK; } /* * Tell the server what you are doing. This string is sent to anyone * who does a 'who_is_on()'. */ extern Success change_what_i_am_doing (String what_am_i_doing) { Who_info info = EMPTY_WHO_INFO; if ( s_strlen( what_am_i_doing ) > WHAT_DO_LEN ) { s_clear ( &what_am_i_doing ); kom_errno = KOM_LONG_STR; return FAILURE; } s_clear ( &active_connection->what_am_i_doing ); active_connection->what_am_i_doing = what_am_i_doing; if (!active_connection->invisible) { info.person = ACTPERS; info.what_am_i_doing = active_connection->what_am_i_doing; create_oldstyle_username(&info.username, active_connection); info.working_conference = active_connection->cwc; info.session_no = active_connection->session_no; async_i_am_on(info); s_clear(&info.username); } return OK; } /* * Get info about what all the currently logged in persons are doing. */ extern Success who_is_on( Who_info_list *result ) { Connection *cptr; int no_of_clients = 0; int i; Session_no session; cptr = active_connection; for ( session = 0; (session = traverse_connections(session)) != 0; ) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) ++no_of_clients; } result->no_of_persons = no_of_clients; result->info = tmp_alloc ( no_of_clients * sizeof(Who_info)); for ( session = 0, i = 0; i < no_of_clients && (session = traverse_connections(session)) != 0; ) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) { result->info[ i ] = EMPTY_WHO_INFO; result->info[ i ].person = cptr->pers_no; result->info[ i ].what_am_i_doing = cptr->what_am_i_doing; /* Backward compatibility: Old clients want the username to be user%host@host. result->info[i].username is free()d in prot_a_output_who_info_list() in prot-a-output.c. */ create_oldstyle_username(&result->info[i].username, cptr); result->info[ i ].working_conference = cptr->cwc; result->info[ i ].session_no = cptr->session_no; ++i; } } if ( i != no_of_clients ) log("who_is_on: i == %d, no_of_clients == %d\n", i, no_of_clients); return OK; } /* * Get info about what all the currently logged in persons are doing. */ extern Success who_is_on_ident( Who_info_ident_list *result ) { Connection *cptr; int no_of_clients = 0; int i; Session_no session; cptr = active_connection; for ( session = 0; (session = traverse_connections(session)) != 0; ) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) ++no_of_clients; } result->no_of_persons = no_of_clients; result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident)); for ( session = 0, i = 0; i < no_of_clients && (session = traverse_connections(session)) != 0; ) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) { result->info[i] = EMPTY_WHO_INFO_IDENT; result->info[i].person = cptr->pers_no; result->info[i].what_am_i_doing = cptr->what_am_i_doing; result->info[i].username = cptr->username; result->info[i].hostname = cptr->hostname; result->info[i].ident_user = cptr->ident_user; result->info[i].working_conference = cptr->cwc; result->info[i].session_no = cptr->session_no; ++i; } } if ( i != no_of_clients ) log("who_is_on_ident: i == %d, no_of_clients == %d\n", i, no_of_clients); return OK; } extern Success get_session_info (Session_no session_no, Session_info *result) { Connection *cptr; CHK_LOGIN(FAILURE); cptr = get_conn_by_number(session_no); if ( cptr != NULL ) { *result = EMPTY_SESSION_INFO; result->person = cptr->pers_no; result->what_am_i_doing = cptr->what_am_i_doing; result->working_conference = cptr->cwc; result->session = cptr->session_no; result->connection_time = cptr->session_start; result->idle_time = difftime(time(NULL), cptr->last_request); /* Backward compatibility. result->username is free()d in prot_a_reply() prot-a.c. */ create_oldstyle_username(&result->username, cptr); return OK; } else { kom_errno = KOM_UNDEF_SESSION; return FAILURE; } } extern Success get_session_info_ident (Session_no session_no, Session_info_ident *result) { Connection *cptr; CHK_LOGIN(FAILURE); cptr = get_conn_by_number(session_no); if ( cptr != NULL ) { *result = EMPTY_SESSION_INFO_IDENT; result->person = cptr->pers_no; result->what_am_i_doing = cptr->what_am_i_doing; result->working_conference = cptr->cwc; result->session = cptr->session_no; result->connection_time = cptr->session_start; result->idle_time = difftime(time(NULL), cptr->last_request); result->username = cptr->username; result->hostname = cptr->hostname; result->ident_user = cptr->ident_user; return OK; } else { kom_errno = KOM_UNDEF_SESSION; return FAILURE; } } extern Success who_am_i (Session_no *session_no) { *session_no = active_connection->session_no; return OK; } extern Success disconnect (Session_no session_no) { Connection *cptr; if ( session_no != active_connection->session_no ) CHK_LOGIN(FAILURE); cptr = get_conn_by_number(session_no); if ( cptr != NULL ) { if ( is_supervisor(cptr->pers_no, NULL, ACTPERS, ACT_P) || session_no == active_connection->session_no ) { add_to_kill_list(cptr); return OK; } else { kom_errno = KOM_PERM; return FAILURE; } } else { kom_errno = KOM_UNDEF_SESSION; return FAILURE; } } /* Get less info */ extern Success who_is_on_old( Who_info_list_old *result ) { Connection *cptr; int no_of_clients = 0; int i; Session_no session = 0; while ( (session = traverse_connections(session)) != 0) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) ++no_of_clients; } result->no_of_persons = no_of_clients; result->info = tmp_alloc ( no_of_clients * sizeof(Who_info)); for (session = 0, i = 0; i < no_of_clients && (session = traverse_connections(session)) != 0;) { cptr = get_conn_by_number(session); if ( cptr->person != NULL && cptr->invisible == FALSE ) { result->info[ i ] = EMPTY_WHO_INFO_OLD; result->info[ i ].person = cptr->pers_no; result->info[ i ].what_am_i_doing = cptr->what_am_i_doing; result->info[ i ].working_conference = cptr->cwc; ++i; } } if ( i != no_of_clients ) log("who_is_on_old: i == %d, no_of_clients == %d\n", i, no_of_clients); return OK; } /* * Ask the server what it thinks the time is. */ extern Success get_time( time_t *clock ) { time(clock); return OK; } /* * Set ena_level. 0 means don't use any privileges. /// */ extern Success enable (u_char ena_level) { CHK_LOGIN(FAILURE); active_connection->ena_level = ena_level; return OK; }