session.c 24.9 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
 * $Id: session.c,v 0.53 1999/06/26 15:49:20 ceder Exp $
3
 * Copyright (C) 1991-1994, 1996-1999  Lysator Academic Computer Association.
Linus Tolke's avatar
Linus Tolke committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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. 
 */
Per Cederqvist's avatar
Per Cederqvist committed
25
26
27
28
29
30
/*
 * session.c
 *
 * Session control and miscellaneous.
 */

David Byers's avatar
David Byers committed
31
32
33
34
35

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

36
static const char *
37
rcsid = "$Id: session.c,v 0.53 1999/06/26 15:49:20 ceder Exp $";
38
39
#include "rcs.h"
USE(rcsid);
Per Cederqvist's avatar
Per Cederqvist committed
40

Per Cederqvist's avatar
Per Cederqvist committed
41
42
#include <stdio.h>
#include <setjmp.h>
Per Cederqvist's avatar
Per Cederqvist committed
43
#include <time.h>
Per Cederqvist's avatar
Per Cederqvist committed
44
#include <sys/types.h>
Per Cederqvist's avatar
Per Cederqvist committed
45

46
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
48
49
#include "s-string.h"
#include "kom-types.h"
#include "services.h"
Per Cederqvist's avatar
Per Cederqvist committed
50
#include "com.h"
51
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
52
#include "connections.h"
Per Cederqvist's avatar
Per Cederqvist committed
53
54
55
56
#include "internal-connections.h"
#include "manipulate.h"
#include "lyskomd.h"
#include "kom-errno.h"
Per Cederqvist's avatar
Per Cederqvist committed
57
#include "log.h"
Per Cederqvist's avatar
Per Cederqvist committed
58
59
#include "cache.h"
#include "send-async.h"
David Byers's avatar
David Byers committed
60
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
61
#include "server/smalloc.h"
62
#include "param.h"
Per Cederqvist's avatar
Per Cederqvist committed
63
#include "kom-memory.h"
64
#include "string-malloc.h"
65
#include "server-time.h"
66
67
68
69
70
71
72
73
74
75

/*
 * 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)
{
76
    if ( s_strcpy(result, connection->username) != OK )
77
78
	restart_kom("create_oldstyle_username(): strcpy\n");

79
    if ( s_strcat(result, s_fcrea_str("@")) != OK )
80
81
	restart_kom("create_oldstyle_username: s_strcat\n");

82
    if ( s_strcat(result, connection->hostname) != OK )
83
84
85
	restart_kom("prot_a_parse_packet: s_strcat II\n");
}

Per Cederqvist's avatar
Per Cederqvist committed
86
87
/*
 * This function is called whenever a person leaves a conf,
88
 * i e when he change_conference():s or logout():s.
Per Cederqvist's avatar
Per Cederqvist committed
89
90
91
 */

extern void
David Byers's avatar
Server    
David Byers committed
92
leave_conf(Connection *conn)
Per Cederqvist's avatar
Per Cederqvist committed
93
94
95
{
    Membership * mship;

David Byers's avatar
Server    
David Byers committed
96
97
    /* FIXME NOW */
    if (conn->cwc != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
98
    {
David Byers's avatar
Server    
David Byers committed
99
	if ((mship = locate_membership( conn->cwc, conn->person ))
Per Cederqvist's avatar
Per Cederqvist committed
100
101
	    != NULL )
	{
102
	    mship->last_time_read = current_time;
David Byers's avatar
Server    
David Byers committed
103
	    mark_person_as_changed (conn->pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
104
105
106
	}
	else
	{
David Byers's avatar
David Byers committed
107
	    kom_log("ERROR: leave_conf(): Can't find membership of cwc.\n");
Per Cederqvist's avatar
Per Cederqvist committed
108
109
	}
	
David Byers's avatar
Server    
David Byers committed
110
111
	cached_unlock_conf( conn->cwc );
	conn->cwc = 0;
Per Cederqvist's avatar
Per Cederqvist committed
112
113
114
115
116
117
118
119
120
    }
}

/*
 * 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
121
122
login_old (Pers_no       pers_no,
	   const String  passwd)
Per Cederqvist's avatar
Per Cederqvist committed
123
124
{
    Person *pers_p;
David Byers's avatar
Server    
David Byers committed
125
126
    
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
127
    GET_P_STAT(pers_p, pers_no, FAILURE);
128

Per Cederqvist's avatar
Per Cederqvist committed
129
130
131
#if 0
    if ( !logins_allowed  && !pers_p->privileges.wheel)
    {
132
        err_stat = 0;
Per Cederqvist's avatar
Per Cederqvist committed
133
134
135
136
137
	kom_errno = KOM_LOGIN_DISALLOWED;
	return FAILURE;
    }
#endif
    
138
    if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) &&
David Byers's avatar
Server    
David Byers committed
139
         !ENA(wheel, 8) &&      /* OK -- In an RPC call */
140
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
Per Cederqvist's avatar
Per Cederqvist committed
141
    {
142
        err_stat = pers_no;
Per Cederqvist's avatar
Per Cederqvist committed
143
144
145
146
	kom_errno = KOM_PWD;
	return FAILURE;
    }

147
    logout();	/*FIXME: How many tries are allowed before disconnection? */
Per Cederqvist's avatar
Per Cederqvist committed
148

149
    active_connection->flags.invisible = FALSE;
150

Per Cederqvist's avatar
Per Cederqvist committed
151
152
153
154
155
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
156
    pers_p->last_login = active_connection->session_start = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
157
158
159
    ++pers_p->sessions;

    s_strcpy(&pers_p->username, active_connection->username);
160
161
162
163
164
165

    /* 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))
    {
166
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
167
168
	    restart_kom("login: s_strcat (\n");

Per Cederqvist's avatar
Per Cederqvist committed
169
	if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK )
170
171
	    restart_kom("login: s_strcat ident_user\n");

172
	if ( s_strcat(&pers_p->username, s_fcrea_str(")")) != OK )
173
174
175
	    restart_kom("login: s_strcat )\n");
    }

176
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
177
178
	restart_kom("prot_a_parse_packet: s_strcat\n");

Per Cederqvist's avatar
Per Cederqvist committed
179
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
180
181
	restart_kom("prot_a_parse_packet: s_strcat II\n");

Per Cederqvist's avatar
Per Cederqvist committed
182
    mark_person_as_changed( pers_no );
183
184
185
186

    if (param.log_login == TRUE)
    {
	char *id = s_crea_c_str (pers_p->username);
David Byers's avatar
David Byers committed
187
	kom_log ("Login %d %s\n", ACTPERS, id);
188
189
190
	string_free (id);
    }

Per Cederqvist's avatar
Per Cederqvist committed
191
    async_login(ACTPERS, active_connection->session_no);
192

Per Cederqvist's avatar
Per Cederqvist committed
193
194
195
    return OK;
}

196
197
198
199
200
201
202
203
204
205
206
/*
 * 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;
207
    Bool same_person;
208

David Byers's avatar
Server    
David Byers committed
209
    CHK_CONNECTION(FAILURE);
210
211
212
213
214
    GET_P_STAT(pers_p, pers_no, FAILURE);

#if 0
    if ( !logins_allowed  && !pers_p->privileges.wheel)
    {
215
        err_stat = 0;
216
217
218
219
220
	kom_errno = KOM_LOGIN_DISALLOWED;
	return FAILURE;
    }
#endif
    
221
    if ( !is_supervisor(pers_no, NULL, ACTPERS, ACT_P) &&
David Byers's avatar
Server    
David Byers committed
222
         !ENA(wheel, 8) &&      /* OK -- In an RPC call */
223
         chk_passwd(pers_p->pwd, passwd) == FAILURE )
224
    {
225
        err_stat = pers_no;
226
227
228
229
	kom_errno = KOM_PWD;
	return FAILURE;
    }

230
    same_person = (ACTPERS == pers_no) ? TRUE : FALSE;
231

232
233
    logout();	/*+++ How many tries are allowed before disconnection? */

234
    if (invisible)
235
      active_connection->flags.invisible = TRUE;
236
    else
237
      active_connection->flags.invisible = FALSE;
238

239
240
241
    /* 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. */
242
    if (same_person == FALSE)
243
244
	++pers_p->sessions;

245
246
247
248
249
    ACTPERS = pers_no;
    ACT_P   = pers_p;

    cached_lock_person(pers_no);
        
250
    pers_p->last_login = active_connection->session_start = current_time;
251
252
253
254
255
256
257
258

    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))
    {
259
	if ( s_strcat(&pers_p->username, s_fcrea_str("(")) != OK )
260
261
	    restart_kom("login: s_strcat (\n");

Per Cederqvist's avatar
Per Cederqvist committed
262
	if ( s_strcat(&pers_p->username, active_connection->ident_user) != OK )
263
264
	    restart_kom("login: s_strcat ident_user\n");

Per Cederqvist's avatar
Per Cederqvist committed
265
	if ( s_strcat(&pers_p->username,
266
		      s_fcrea_str(")")) != OK )
267
268
269
	    restart_kom("login: s_strcat )\n");
    }

270
    if ( s_strcat(&pers_p->username, s_fcrea_str("@")) != OK )
271
272
	restart_kom("prot_a_parse_packet: s_strcat\n");

Per Cederqvist's avatar
Per Cederqvist committed
273
    if ( s_strcat(&pers_p->username, active_connection->hostname) != OK )
274
275
276
277
	restart_kom("prot_a_parse_packet: s_strcat II\n");

    mark_person_as_changed( pers_no );

278
    if (param.log_login == TRUE && same_person == FALSE)
279
280
    {
	char *id = s_crea_c_str (pers_p->username);
David Byers's avatar
David Byers committed
281
	kom_log ("Login %d %s\n", ACTPERS, id);
282
283
284
	string_free (id);
    }

285
    if (!active_connection->flags.invisible)
286
287
288
289
290
	async_login(ACTPERS, active_connection->session_no);
    
    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
291
292
293
294
295
296
297
298
299

/*
 * 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 )
{
David Byers's avatar
Server    
David Byers committed
300
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
301
302
    if ( ACTPERS != 0 )		/* Is he logged in? Then log him out. */
    {
303
	if (!active_connection->flags.invisible)
304
305
306
	{
	    async_logout( ACTPERS, active_connection->session_no );
	}
Per Cederqvist's avatar
Per Cederqvist committed
307
	
David Byers's avatar
Server    
David Byers committed
308
	leave_conf(active_connection);
309
	ACT_P->last_login = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
310
	ACT_P->total_time_present +=
311
	    ldifftime(current_time, active_connection->session_start);
Per Cederqvist's avatar
Per Cederqvist committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

	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.
 *
335
336
 * You can change_conference(0) to indicate that you are no longer in
 * a certain conference.
Per Cederqvist's avatar
Per Cederqvist committed
337
338
339
340
341
342
343
344
345
346
347
 *
 * 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
348
 * someone change_conference's to it to allow faster response times.
Per Cederqvist's avatar
Per Cederqvist committed
349
350
 */
extern Success
351
change_conference (Conf_no		conference)		
Per Cederqvist's avatar
Per Cederqvist committed
352
{
353
354
    Who_info	 info;
  
David Byers's avatar
Server    
David Byers committed
355
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
356
    CHK_LOGIN(FAILURE);
David Byers's avatar
Server    
David Byers committed
357

Per Cederqvist's avatar
Per Cederqvist committed
358
359
360
361
362
363
    if (  conference != 0 )
    {
	CHK_EXIST(conference, FAILURE);

	if ( locate_membership( conference, ACT_P) == NULL )
	{
364
            err_stat = conference;
Per Cederqvist's avatar
Per Cederqvist committed
365
366
367
368
369
	    kom_errno = KOM_NOT_MEMBER;
	    return FAILURE;
	}
    }

David Byers's avatar
Server    
David Byers committed
370
    leave_conf(active_connection);
Per Cederqvist's avatar
Per Cederqvist committed
371
372
373
374
375
    
    active_connection->cwc = conference;
    if ( conference != 0 )
	cached_lock_conf( conference );

David Byers's avatar
Server    
David Byers committed
376
    init_who_info(&info);
377
    if (!active_connection->flags.invisible)
378
379
380
381
382
    {
	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;
383
384
385
386

	/* Bug compatibility. */
	create_oldstyle_username(&info.username, active_connection);

387
	async_i_am_on(info);
388
389

	s_clear(&info.username);
390
    }
Per Cederqvist's avatar
Per Cederqvist committed
391
392
393
394
395
396
397
398
399
400
401
402
    
    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)
{
403
404
    Who_info info;
    
David Byers's avatar
Server    
David Byers committed
405
    CHK_CONNECTION(FAILURE);
406
    init_who_info(&info);
Per Cederqvist's avatar
Per Cederqvist committed
407

408
    if ( s_strlen( what_am_i_doing ) > param.what_do_len )
Per Cederqvist's avatar
Per Cederqvist committed
409
410
    {
	s_clear ( &what_am_i_doing );
411
        err_stat = param.what_do_len;
Per Cederqvist's avatar
Per Cederqvist committed
412
413
414
415
416
417
418
	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;

419
    if (!active_connection->flags.invisible)
420
421
422
    {
	info.person = ACTPERS;
	info.what_am_i_doing = active_connection->what_am_i_doing;
423
	create_oldstyle_username(&info.username, active_connection);
424
425
	info.working_conference = active_connection->cwc;
	info.session_no = active_connection->session_no;
Per Cederqvist's avatar
Per Cederqvist committed
426
    
427
	async_i_am_on(info);
428
429

	s_clear(&info.username);
430
    }
Per Cederqvist's avatar
Per Cederqvist committed
431
432
433
434

    return OK;
}

435

Per Cederqvist's avatar
Per Cederqvist committed
436
437
438
439
440
441
442
443
444
445
446
/*
 * 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;
    
David Byers's avatar
Server    
David Byers committed
447
448
    CHK_CONNECTION(FAILURE);

Per Cederqvist's avatar
Per Cederqvist committed
449
    cptr = active_connection;
450
451
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
452
453
454
    {
	cptr = get_conn_by_number(session);

455
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
456
	    ++no_of_clients;
457
458

        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
459
460
461
462
463
    }

    result->no_of_persons = no_of_clients;
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info));

464
465
466
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
467
468
469
    {
	cptr = get_conn_by_number(session);

470
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
471
	{
472
	    init_who_info(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
473
474
	    result->info[ i ].person = cptr->pers_no;
	    result->info[ i ].what_am_i_doing = cptr->what_am_i_doing;
475
476
477
478

	    /* 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. */
479
	    create_oldstyle_username(&result->info[i].username, cptr);
480

Per Cederqvist's avatar
Per Cederqvist committed
481
482
483
484
	    result->info[ i ].working_conference = cptr->cwc;
	    result->info[ i ].session_no = cptr->session_no;
	    ++i;
	}
485
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
486
487
488
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
489
	kom_log("who_is_on: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
490
491
492
493
494
	    i, no_of_clients);

    return OK;
}

495
496
497
498
499
500
501
502
503
504
505
/*
 * 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;
    
David Byers's avatar
Server    
David Byers committed
506
507
    CHK_CONNECTION(FAILURE);

508
    cptr = active_connection;
509
510
    session = traverse_connections(0);
    while (session != 0)
511
512
513
    {
	cptr = get_conn_by_number(session);

514
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
515
	    ++no_of_clients;
516
517

        session = traverse_connections(session);
518
519
520
    }

    result->no_of_persons = no_of_clients;
521
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info_ident));
522

523
524
525
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
526
527
528
    {
	cptr = get_conn_by_number(session);

529
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
530
	{
531
	    init_who_info_ident(&result->info[i]);
532
533
534
535
536
537
538
539
540
	    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;
	}
541
        session = traverse_connections(session);
542
543
544
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
545
	kom_log("who_is_on_ident: i == %d, no_of_clients == %d\n",
546
547
548
549
550
	    i, no_of_clients);

    return OK;
}

Per Cederqvist's avatar
Per Cederqvist committed
551

552
553
554
555
556
557
/*
 * Get info about what all the currently logged in persons are doing.
 */
extern Success
who_is_on_dynamic(int want_visible,
		  int want_invisible,
558
		  long active_last,
559
560
561
562
563
564
565
566
		  Dynamic_session_info_list *result)
{
    Connection *cptr;
    long	    no_of_clients = 0;
    long	    i;
    Session_no      session;
    int             include_it = 0;

David Byers's avatar
Server    
David Byers committed
567
    CHK_CONNECTION(FAILURE);
568
    cptr = active_connection;
569
570
    session = traverse_connections(0);
    while (session != 0)
571
572
573
    {
	cptr = get_conn_by_number(session);

574
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
575
576
577
578
	    include_it = want_invisible;
	else
	    include_it = want_visible;

579
580
	if (active_last != 0
	    && ldifftime(current_time, cptr->active_time) > active_last
581
582
583
	    && cptr->flags.user_active_used)
	    include_it = 0;

584
585
	if (include_it != 0)
	    ++no_of_clients;
586
587

        session = traverse_connections(session);
588
589
590
591
592
    }

    result->no_of_sessions = no_of_clients;
    result->sessions = tmp_alloc(no_of_clients * sizeof(Dynamic_session_info));

593
594
595
    i = 0;
    session = traverse_connections(0);
    while ( i < no_of_clients && session != 0)
596
597
598
    {
	cptr = get_conn_by_number(session);

599
	if (cptr->person == NULL || cptr->flags.invisible == TRUE)
600
601
602
603
	    include_it = want_invisible;
	else
	    include_it = want_visible;
	    
604
605
	if (active_last != 0
	    && ldifftime(current_time, cptr->active_time) > active_last
606
607
608
	    && cptr->flags.user_active_used)
	    include_it = 0;

609
610
611
612
613
614
	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;
615
616
	    result->sessions[i].idle_time = ldifftime(current_time,
						      cptr->active_time);
617

618
619
620
621
622
623
	    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;
624
625
626
627

	    result->sessions[i].what_am_i_doing = cptr->what_am_i_doing;
	    ++i;
	}
628
629

        session = traverse_connections(session);
630
631
632
    }

    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
633
	kom_log("who_is_on_dynamic: i == %ld, no_of_clients == %ld\n",
634
635
636
637
638
639
	    i, no_of_clients);

    return OK;
}


Per Cederqvist's avatar
Per Cederqvist committed
640
641
642
643
644
645
extern  Success
get_session_info  (Session_no session_no,
		   Session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
646
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
647
648
649
650
651
652
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
653
	init_session_info(result);
Per Cederqvist's avatar
Per Cederqvist committed
654
655
656
657
658
	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;
659
	result->idle_time = ldifftime(current_time, cptr->active_time);
Per Cederqvist's avatar
Per Cederqvist committed
660

661
662
	/* Backward compatibility. result->username is free()d in
	   prot_a_reply() prot-a.c. */
663
	create_oldstyle_username(&result->username, cptr);
664
665
666
667
668

	return OK;
    }
    else
    {
669
        err_stat = session_no;
670
671
672
673
674
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

675
676
677
678
679
680
extern  Success
get_static_session_info (Session_no session_no,
			 Static_session_info *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
681
    CHK_CONNECTION(FAILURE);
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    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
    {
699
        err_stat = session_no;
700
701
702
703
704
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

705
706
707
708
709
710
extern  Success
get_session_info_ident  (Session_no session_no,
			 Session_info_ident *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
711
    CHK_CONNECTION(FAILURE);
712
713
714
715
716
717
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
718
	init_session_info_ident(result);
719
720
721
722
723
	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;
724
	result->idle_time = ldifftime(current_time, cptr->active_time);
725
726
727
728
	result->username = cptr->username;
	result->hostname = cptr->hostname;
	result->ident_user = cptr->ident_user;

Per Cederqvist's avatar
Per Cederqvist committed
729
730
731
732
	return OK;
    }
    else
    {
733
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
734
735
736
737
738
739
740
741
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
who_am_i (Session_no *session_no)
{
David Byers's avatar
Server    
David Byers committed
742
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
743
744
745
746
747
748
749
750
751
752
753
    *session_no = active_connection->session_no;
    return OK;
}



extern  Success
disconnect (Session_no session_no)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
754
    CHK_CONNECTION(FAILURE);
755
756
    if ( session_no != active_connection->session_no &&
         session_no != 0 )
Per Cederqvist's avatar
Per Cederqvist committed
757
758
759
760
761
762
	CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
763
764
	if ( session_no == active_connection->session_no   ||
             session_no == 0 ||
David Byers's avatar
Server    
David Byers committed
765
             ENA(wheel, 8) ||   /* OK -- In an RPC call */
766
767
             is_supervisor(cptr->pers_no, NULL, ACTPERS, ACT_P) == TRUE
             )
Per Cederqvist's avatar
Per Cederqvist committed
768
	{
769
	    add_to_kill_list(cptr);
Per Cederqvist's avatar
Per Cederqvist committed
770
771
772
773
	    return OK;
	}
	else
	{
774
            err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
775
776
777
778
779
780
	    kom_errno = KOM_PERM;
	    return FAILURE;
	}
    }
    else
    {
781
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
782
783
784
785
786
787
788
789
790
791
792
793
794
	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;
795
    Session_no	    session;
Per Cederqvist's avatar
Per Cederqvist committed
796
797

    
David Byers's avatar
Server    
David Byers committed
798
    CHK_CONNECTION(FAILURE);
799
800
    session = traverse_connections(0);
    while (session != 0)
Per Cederqvist's avatar
Per Cederqvist committed
801
802
803
    {
	cptr = get_conn_by_number(session);

804
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
805
	    ++no_of_clients;
806
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
807
808
809
810
811
    }

    result->no_of_persons = no_of_clients;
    result->info = tmp_alloc ( no_of_clients * sizeof(Who_info));

812
813
814
    i = 0;
    session = traverse_connections(0);
    while (session != 0 && i < no_of_clients)
Per Cederqvist's avatar
Per Cederqvist committed
815
816
817
    {
	cptr = get_conn_by_number(session);

818
	if ( cptr->person != NULL && cptr->flags.invisible == FALSE )
Per Cederqvist's avatar
Per Cederqvist committed
819
	{
820
	    init_who_info_old(&result->info[ i ]);
Per Cederqvist's avatar
Per Cederqvist committed
821
822
823
824
825
	    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;
	}
826
        session = traverse_connections(session);
Per Cederqvist's avatar
Per Cederqvist committed
827
828
829
    }
    
    if ( i != no_of_clients )
David Byers's avatar
David Byers committed
830
	kom_log("who_is_on_old: i == %d, no_of_clients == %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
831
832
833
834
835
836
837
838
839
	    i, no_of_clients);

    return OK;
}

/*
 * Ask the server what it thinks the time is.
 */
extern Success
840
get_time( time_t *clk )
Per Cederqvist's avatar
Per Cederqvist committed
841
{
David Byers's avatar
Server    
David Byers committed
842
    CHK_CONNECTION(FAILURE);
843
    *clk = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
844
845
846
847
848
849
850
851
852
853
854
855
    
    return OK;
}



/*
 * Set ena_level. 0 means don't use any privileges. ///
 */
extern Success
enable (u_char ena_level)
{
David Byers's avatar
Server    
David Byers committed
856
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
857
858
859
860
    CHK_LOGIN(FAILURE);
    active_connection->ena_level = ena_level;
    return OK;
}
Per Cederqvist's avatar
Per Cederqvist committed
861
862
863
864
865

extern  Success
set_client_version (const String client_name,
		    const String client_version)
{
David Byers's avatar
Server    
David Byers committed
866
867
    CHK_CONNECTION(FAILURE);

David Byers's avatar
David Byers committed
868
869
    if (s_strlen(client_name) > param.client_data_len
	|| s_strlen(client_version) > param.client_data_len)
Per Cederqvist's avatar
Per Cederqvist committed
870
    {
David Byers's avatar
David Byers committed
871
        err_stat = param.client_data_len;
Per Cederqvist's avatar
Per Cederqvist committed
872
873
874
	kom_errno = KOM_LONG_STR;
	return FAILURE;
    }
875
876
877
878
879
880
881
    if (s_empty(active_connection->client_name) == FALSE
	|| s_empty(active_connection->client_version) == FALSE)
    {
	err_stat = 0;
	kom_errno = KOM_CLIENT_IS_CRAZY;
	return FAILURE;
    }
Per Cederqvist's avatar
Per Cederqvist committed
882
883
884
885
886
887
888
889
890
891
892
893

    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;

David Byers's avatar
Server    
David Byers committed
894
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
895
896
897
898
899
900
901
902
903
904
905
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_name;
	return OK;
    }
    else
    {
906
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
907
908
909
910
911
912
913
914
915
916
917
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}

extern  Success
get_client_version (Session_no session_no,
		    String *result)
{
    Connection *cptr;

David Byers's avatar
Server    
David Byers committed
918
    CHK_CONNECTION(FAILURE);
Per Cederqvist's avatar
Per Cederqvist committed
919
920
921
922
923
924
925
926
927
928
929
    CHK_LOGIN(FAILURE);

    cptr = get_conn_by_number(session_no);

    if ( cptr != NULL )
    {
	*result = cptr->client_version;
	return OK;
    }
    else
    {
930
        err_stat = session_no;
Per Cederqvist's avatar
Per Cederqvist committed
931
932
933
934
	kom_errno = KOM_UNDEF_SESSION;
	return FAILURE;
    }
}
935
936
937
938
939
940


extern Success
accept_async(Number_list *num_list)
{
    int         i;
941
    Success     result;
942
    int		found;
943
944
    

David Byers's avatar
Server    
David Byers committed
945
946
    CHK_CONNECTION(FAILURE);
    
947
    result = OK;
948
949
950
951
952

    /*
     * Check agains maliciously long arrays
     */
    
David Byers's avatar
David Byers committed
953
954
955
956
957
    /* FIXME: The following test only needs one branch depending on
       FIXME: which implementation of prot_a_parse_num_list we go with. */

    if (num_list->length > param.accept_async_len ||
        (num_list->data == NULL && num_list->length > 0))
958
    {
959
        err_stat = 0;
960
        kom_errno = KOM_LONG_ARRAY;
961
962
963
964
965
966
967
968
969
970
        return FAILURE;
    }


    /*
     * Clear the accept list
     */
    
    for (i = 0; i < ay_dummy_last; i++)
    {
971
        active_connection->want_async[i] = FALSE;
972
973
974
975
    }


    /*
976
     * Enter the new accept list -- non-silently ignore requests for
977
     * messages that this version of the server doesn't understand.
978
979
980
981
     */
    
    for (i = 0; i < num_list->length; i++)
    {
982
	found = 0;
983
984
        if (num_list->data[i] >= 0 &&
            num_list->data[i] < ay_dummy_last)
985
986
987
988
989
990
991
992
993
994
995
996
997
998
	{
	    switch ((Async)num_list->data[i])
	    {
	    case ay_new_text_old:
	    case ay_new_name:
	    case ay_i_am_on:
	    case ay_sync_db:
	    case ay_leave_conf:
	    case ay_login:
	    case ay_rejected_connection:
	    case ay_send_message:
	    case ay_logout:
	    case ay_deleted_text:
	    case ay_new_text:
David Byers's avatar
David Byers committed
999
1000
1001
            case ay_new_recipient:
            case ay_sub_recipient:
            case ay_new_membership:
1002
1003
1004
#ifdef DEBUG_CALLS
	    case ay_garb_ended:
#endif
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
		found = 1;
		active_connection->want_async[num_list->data[i]] = TRUE;
		break;
	    case ay_dummy_last:
		break;
		/* Trick: since we don't use a default label here gcc
		   will warn if new values are added to the Async enum
		   but not to this switch. */
	    }
	}
	
	if (!found && result == OK) /* Remember the first offender. */
1017
1018
1019
1020
1021
        {
            err_stat  = num_list->data[i];
            kom_errno = KOM_UNKNOWN_ASYNC;
            result    = FAILURE;
        }
1022
1023
    }

1024
    return result;
1025
1026
1027
1028
1029
1030
}


extern Success
query_async(Number_list *result)
{
1031
    /* (This static buffer is mentioned in async.h). */
1032
1033
1034
    static long        temp[ay_dummy_last];
    int         i;

David Byers's avatar
Server    
David Byers committed
1035
    CHK_CONNECTION(FAILURE);
1036
1037
1038
    result->length = 0;
    for (i = 0; i < ay_dummy_last; i++)
    {
1039
        if (active_connection->want_async[i] != FALSE)
1040
1041
1042
1043
1044
1045
1046
1047
1048
        {
            temp[result->length] = i;
            result->length += 1;
        }
    }
    result->data = temp;

    return OK;
}
1049
1050
1051
1052

extern Success
user_active(void)
{
David Byers's avatar
Server    
David Byers committed
1053
    CHK_CONNECTION(FAILURE);
1054
    active_connection->active_time = current_time;
1055
    active_connection->flags.user_active_used = TRUE;
1056
1057
    return OK;
}