Skip to content
Snippets Groups Projects
Select Git revision
  • f8c206ed23e98a62c2b4d17237d6c0a2f6050843
  • master default
  • wip-slh-dsa-sha2-128s
  • master-updates
  • release-3.10-fixes
  • getopt-prototype
  • fix-bcrypt-warning
  • refactor-hmac
  • wip-use-alignas
  • trim-sha3-context
  • fix-gitlab-ci
  • check-fat-emulate
  • delete-digest_func-size
  • slh-dsa-shake-128f-nettle
  • slh-dsa-shake-128s-nettle
  • slh-dsa-shake-128s
  • delete-openpgp
  • ppc64-sha512
  • delete-md5-compat
  • cleanup-hmac-tests
  • ppc64-sha256
  • nettle_3.10.2_release_20250626
  • nettle_3.10.1_release_20241230
  • nettle_3.10_release_20240616
  • nettle_3.10rc2
  • nettle_3.10rc1
  • nettle_3.9.1_release_20230601
  • nettle_3.9_release_20230514
  • nettle_3.8.1_release_20220727
  • nettle_3.8_release_20220602
  • nettle_3.7.3_release_20210606
  • nettle_3.7.2_release_20210321
  • nettle_3.7.1_release_20210217
  • nettle_3.7_release_20210104
  • nettle_3.7rc1
  • nettle_3.6_release_20200429
  • nettle_3.6rc3
  • nettle_3.6rc2
  • nettle_3.6rc1
  • nettle_3.5.1_release_20190627
  • nettle_3.5_release_20190626
41 results

aes-set-key-internal.c

  • session.c 21.71 KiB
    /*
     * $Id: session.c,v 0.36 1996/08/03 01:32:12 ceder Exp $
     * Copyright (C) 1991, 1992, 1993, 1994, 1996  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.36 1996/08/03 01:32:12 ceder Exp $";
    #include "rcs.h"
    USE(rcsid);
    
    #include <stdio.h>
    #include <setjmp.h>
    #ifdef HAVE_STDARG_H
    #  include <stdarg.h>
    #endif
    #include <time.h>
    #include <sys/types.h>
    
    #include "ldifftime.h"
    #include "s-string.h"
    #include "kom-types.h"
    #include "services.h"
    #include "com.h"
    #include "async.h"
    #include "connections.h"
    #include "internal-connections.h"
    #include "manipulate.h"
    #include "lyskomd.h"
    #include "kom-errno.h"
    #include "log.h"
    #include "cache.h"
    #include "send-async.h"
    #include "config.h"
    #include "server/smalloc.h"
    #include "param.h"
    #include "kom-memory.h"
    #include "string-malloc.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 change_conference():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->flags.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 );
    
        if (param.log_login == TRUE)
        {
    	char *id = s_crea_c_str (pers_p->username);
    	log ("Login %d %s\n", ACTPERS, id);
    	string_free (id);
        }
    
        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;
        Bool same_person;
    
        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;
        }
    
        same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
    
        logout();	/*+++ How many tries are allowed before disconnection? */
    
        if (invisible)
          active_connection->flags.invisible = TRUE;
        else
          active_connection->flags.invisible = FALSE;
    
        /* Don't count this as a new session if the person already was
           logged on.  The elisp-client version 0.38.1 logs on invisibly
           automatically to indicate that the user is inactve. */
        if (same_person == FALSE)
    	++pers_p->sessions;
    
        ACTPERS = pers_no;
        ACT_P   = pers_p;
    
        cached_lock_person(pers_no);
            
        pers_p->last_login = time(&active_connection->session_start);
    
        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 (param.log_login == TRUE && same_person == FALSE)
        {
    	char *id = s_crea_c_str (pers_p->username);
    	log ("Login %d %s\n", ACTPERS, id);
    	string_free (id);
        }
    
        if (!active_connection->flags.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->flags.invisible)
    	{
    	    async_logout( ACTPERS, active_connection->session_no );
    	}
    	
    	leave_conf();
    	ACT_P->total_time_present +=
    	    ldifftime(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 change_conference(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 change_conference's to it to allow faster response times.
     */
    extern Success
    change_conference (Conf_no		conference)		
    {
        Who_info	 info;
      
        init_who_info(&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->flags.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;
        
        init_who_info(&info);
    
        if ( s_strlen( what_am_i_doing ) > param.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->flags.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->flags.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->flags.invisible == FALSE )
    	{
    	    init_who_info(&result->info[ i ]);
    	    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->flags.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->flags.invisible == FALSE )
    	{
    	    init_who_info_ident(&result->info[i]);
    	    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;
    }
    
    
    /*
     * Get info about what all the currently logged in persons are doing.
     */
    extern Success
    who_is_on_dynamic(int want_visible,
    		  int want_invisible,
    		  Dynamic_session_info_list *result)
    {
        Connection *cptr;
        long	    no_of_clients = 0;
        long	    i;
        Session_no      session;
        int             include_it = 0;
        time_t	    tn;
    
        tn = time(NULL);
        cptr = active_connection;
    
        for ( session = 0; (session = traverse_connections(session)) != 0; )
        {
    	cptr = get_conn_by_number(session);
    
    	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
    	    include_it = want_invisible;
    	else
    	    include_it = want_visible;
    
    	if (include_it != 0)
    	    ++no_of_clients;
        }
    
        result->no_of_sessions = no_of_clients;
        result->sessions = tmp_alloc(no_of_clients * sizeof(Dynamic_session_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->flags.invisible == TRUE)
    	    include_it = want_invisible;
    	else
    	    include_it = want_visible;
    	    
    	if (include_it != 0)
    	{
    	    init_dynamic_session_info(&result->sessions[i]);
    	    result->sessions[i].session = cptr->session_no;
    	    result->sessions[i].person = cptr->pers_no;
    	    result->sessions[i].working_conference = cptr->cwc;
    	    result->sessions[i].idle_time = ldifftime(tn, cptr->active_time);
    
    	    result->sessions[i].flags = cptr->flags;
    
    	    /* Special case: sessions that are not logged in are
    	       always invisible. */
    	    if (cptr->person == NULL)
    		result->sessions[i].flags.invisible = TRUE;
    
    	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
    	    ++i;
    	}
        }
    
        if ( i != no_of_clients )
    	log("who_is_on_dynamic: i == %ld, no_of_clients == %ld\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 )
        {
    	init_session_info(result);
    	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 = ldifftime(time(NULL), cptr->active_time);
    
    	/* 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_static_session_info (Session_no session_no,
    			 Static_session_info *result)
    {
        Connection *cptr;
    
        CHK_LOGIN(FAILURE);
    
        cptr = get_conn_by_number(session_no);
    
        if ( cptr != NULL )
        {
    	init_static_session_info(result);
    
    	result->username = cptr->username;
    	result->hostname = cptr->hostname;
    	result->ident_user = cptr->ident_user;
    	result->connection_time = cptr->session_start;
    
    	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 )
        {
    	init_session_info_ident(result);
    	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 = ldifftime(time(NULL), cptr->active_time);
    	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) == TRUE
    	    || 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->flags.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->flags.invisible == FALSE )
    	{
    	    init_who_info_old(&result->info[ i ]);
    	    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;
    }
    
    extern  Success
    set_client_version (const String client_name,
    		    const String client_version)
    {
        if (s_strlen(client_name) > param.conf_name_len
    	|| s_strlen(client_version) > param.conf_name_len)
        {
    	kom_errno = KOM_LONG_STR;
    	return FAILURE;
        }
    
        s_strcpy(&active_connection->client_name, client_name);
        s_strcpy(&active_connection->client_version, client_version);
        return OK;
    }
    
    extern  Success
    get_client_name (Session_no session_no,
    		 String *result)
    {
        Connection *cptr;
    
        CHK_LOGIN(FAILURE);
    
        cptr = get_conn_by_number(session_no);
    
        if ( cptr != NULL )
        {
    	*result = cptr->client_name;
    	return OK;
        }
        else
        {
    	kom_errno = KOM_UNDEF_SESSION;
    	return FAILURE;
        }
    }
    
    extern  Success
    get_client_version (Session_no session_no,
    		    String *result)
    {
        Connection *cptr;
    
        CHK_LOGIN(FAILURE);
    
        cptr = get_conn_by_number(session_no);
    
        if ( cptr != NULL )
        {
    	*result = cptr->client_version;
    	return OK;
        }
        else
        {
    	kom_errno = KOM_UNDEF_SESSION;
    	return FAILURE;
        }
    }
    
    
    extern Success
    accept_async(Number_list *num_list)
    {
        int         i;
    
        /*
         * Check agains maliciously long arrays
         */
        
        if (num_list->data == NULL && num_list->length > 0)
        {
            kom_errno = KOM_LONG_ARRAY;
            return FAILURE;
        }
    
    
        /*
         * Clear the accept list
         */
        
        for (i = 0; i < ay_dummy_last; i++)
        {
            active_connection->want_async[i] = FALSE;
        }
    
    
        /*
         * Enter the new accept list -- silently ignore requests for
         * messages that this version of the server doesn't understand.
         */
        
        for (i = 0; i < num_list->length; i++)
        {
            if (num_list->data[i] >= 0 &&
                num_list->data[i] < ay_dummy_last)
                active_connection->want_async[num_list->data[i]] = TRUE;
        }
    
        return OK;
    }
    
    
    extern Success
    query_async(Number_list *result)
    {
        /* (This static buffer is mentioned in async.h). */
        static long        temp[ay_dummy_last];
        int         i;
    
        result->length = 0;
        for (i = 0; i < ay_dummy_last; i++)
        {
            if (active_connection->want_async[i] != FALSE)
            {
                temp[result->length] = i;
                result->length += 1;
            }
        }
        result->data = temp;
    
        return OK;
    }
    
    extern Success
    user_active(void)
    {
        time(&active_connection->active_time);
        active_connection->flags.user_active_used = TRUE;
        return OK;
    }