modules/pc/protocol_config.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- find_command
- show_commands
- command_purify
- command_help
- command_quit
- show_const
- show_consts
- show_props
- show_threads
- show_whois
- show_access
- show_acl
- command_execute
- command_show
- command_repeat
- set_const
- set_consts
- set_props
- set_acl
- command_set
- command_sql
- process_input
- log_config
- authenticate_user
- PC_interact
1 /***************************************
2 $Revision: 1.24 $
3
4 Protocol config module (pc). This is the protocol that the admin uses to
5 talk to the server.
6
7 Status: NOT REVUED, NOT TESTED
8
9 ******************/ /******************
10 Filename : protocol_config.c
11 Authors : ottrey@ripe.net
12 marek@ripe.net
13 To Do : Add a facility to take callbacks instead of
14 hard-coding menu options.
15 Add in all the menu support provided by the GLib
16 libraries.
17 (Remove strtok if multiple threads are to be used.)
18 use gnu readline with expansion and history
19 ******************/ /******************
20 Copyright (c) 1999 RIPE NCC
21
22 All Rights Reserved
23
24 Permission to use, copy, modify, and distribute this software and its
25 documentation for any purpose and without fee is hereby granted,
26 provided that the above copyright notice appear in all copies and that
27 both that copyright notice and this permission notice appear in
28 supporting documentation, and that the name of the author not be
29 used in advertising or publicity pertaining to distribution of the
30 software without specific, written prior permission.
31
32 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
33 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
34 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
35 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
36 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
37 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38 ***************************************/
39 #include <stdio.h>
40 #include <stdlib.h>
41 /*** solaris' header file doesn't contain the crypt definition...
42 #include <unistd.h> */
43
44 extern char* crypt(const char *, const char *); /* crypt stuff */
45 #include <time.h> /* Time stuff */
46 #include <sys/ioctl.h> /* Terminal control stuff */
47 #include <termio.h> /* Terminal control stuff */
48
49 #include "mysql_driver.h"
50 #include "constants.h"
51 #include "properties.h"
52 #include "thread.h"
53 #include "protocol_config.h"
54 #include "access_control.h"
55 #include "socket.h"
56 #include "ta.h"
57
58 /*+ Each command has a +*/
59 typedef struct _command {
60 const char *name; /*+ Name to be invoked. +*/
61 char *(*function)(char *, sk_conn_st *); /*+ Function to be invoked. +*/
62 const char *help; /*+ Command help. +*/
63 } Command;
64
65 /*
66 * Forward declarations
67 */
68 static char *command_help(char *input, sk_conn_st *condat);
69 static char *command_quit(char *input, sk_conn_st *condat);
70 static char *command_show(char *input, sk_conn_st *condat);
71 static char *command_repeat(char *input, sk_conn_st *condat);
72 static char *show_const(char *input, sk_conn_st *condat);
73 static char *show_consts(char *input, sk_conn_st *condat);
74 static char *show_props(char *input, sk_conn_st *condat);
75 static char *show_threads(char *input, sk_conn_st *condat);
76 static char *show_whois(char *input, sk_conn_st *condat);
77 static char *show_access(char *input, sk_conn_st *condat);
78 static char *show_acl(char *input, sk_conn_st *condat);
79 static char *command_set(char *input, sk_conn_st *condat);
80 static char *set_const(char *input, sk_conn_st *condat);
81 static char *set_consts(char *input, sk_conn_st *condat);
82 static char *set_props(char *input, sk_conn_st *condat);
83 static char *command_sql(char *input, sk_conn_st *condat);
84 static char *command_purify(char *input, sk_conn_st *condat);
85 static char *set_acl(char *input, sk_conn_st *condat);
86
87 /*+
88 * Contains the command definitions
89 +*/
90
91 extern void purify_new_inuse(void);
92
93 static struct _command command[] = {
94 {"help" , command_help , HELP_HELP },
95 {"quit" , command_quit , HELP_QUIT },
96 {"show" , command_show , HELP_SHOW },
97 {"repeat" , command_repeat , HELP_REPEAT },
98 {"set" , command_set , HELP_SET },
99 {"sql" , command_sql , HELP_SQL },
100 {"purify" , command_purify , "trigger a new memory-in-use report" },
101 {NULL , NULL , NULL }
102 };
103
104 /*+
105 * Contains the show commands
106 +*/
107 static struct _command show[] = {
108 {"const" , show_const , HELP_SHOW_CONST },
109 {"consts" , show_consts , HELP_SHOW_CONSTS },
110 {"props" , show_props , HELP_SHOW_PROPS },
111 {"threads" , show_threads , HELP_SHOW_THREAD },
112 {"whois" , show_whois , HELP_SHOW_WHOIS },
113 {"access" , show_access , HELP_SHOW_ACCESS },
114 {"acl" , show_acl , HELP_SHOW_ACL },
115 {NULL , NULL , NULL }
116 };
117
118 /*+
119 * Contains the set commands
120 +*/
121 static struct _command set[] = {
122 {"const" , set_const , HELP_SET_CONST },
123 {"consts" , set_consts , HELP_SET_CONSTS },
124 {"props" , set_props , HELP_SET_PROPS },
125 {"acl" , set_acl , HELP_SET_ACL },
126 {NULL , NULL , NULL }
127 };
128
129 static int find_command(char *comm_name, Command *comm) {
/* [<][>][^][v][top][bottom][index][help] */
130 int i, index;
131 char comm_buffer[STR_L];
132
133 if (comm_name != NULL) {
134 strcpy(comm_buffer, comm_name);
135 strtok(comm_buffer, " \t");
136 for (i=0, index=-1; comm[i].name != NULL; i++) {
137 if ( strcmp(comm_buffer, comm[i].name) == 0) {
138 index = i;
139 break;
140 }
141 }
142 }
143 else {
144 index = -2;
145 }
146
147 return index;
148 } /* find_command() */
149
150 static char *show_commands(Command *comm) {
/* [<][>][^][v][top][bottom][index][help] */
151 char *str;
152 char help_buffer[STR_XL];
153 char help_comm[STR_M];
154 int i;
155
156 sprintf(help_buffer, " commands are:\n\n");
157 i = 0;
158 while (comm[i].name != NULL) {
159 sprintf(help_comm, "%s\t%s\n", comm[i].name, comm[i].help);
160 strcat(help_buffer, help_comm);
161 i++;
162 }
163
164 /* str = (char *)calloc(1, strlen(help_buffer)+1); */
165 dieif( wr_malloc((void **)&str, strlen(help_buffer)+1) != UT_OK);
166 strcpy(str, help_buffer);
167
168 return str;
169 } /* show_commands() */
170
171
172 /*
173 * Command functions
174 */
175
176 static char *command_purify(char *input, sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
177 {
178 char *str;
179 dieif( wr_malloc((void **)&str, 4) != UT_OK);
180 #if 0
181 purify_new_inuse();
182 strcpy(str, "OK");
183 #else
184 strcpy(str, "NOP");
185 #endif
186
187 return str;
188 }
189
190 static char *command_help(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
191 char *str;
192 char *str1;
193 char output_buffer[STR_XXL];
194 char *command_name;
195 int index;
196
197 strcpy(output_buffer, "");
198
199 strtok(input, " \t");
200 command_name = (char *)strtok(NULL, " \t");
201
202 index = find_command(command_name, command);
203
204 switch (index) {
205 case -2:
206 strcat(output_buffer, "Main");
207 str1 = show_commands(command);
208 strcat(output_buffer, str1);
209 wr_free(str1);
210 break;
211
212 case -1:
213 strcat(output_buffer, HELP_ERROR);
214 strcat(output_buffer, command_name);
215 break;
216
217 default:
218 strcat(output_buffer, command[index].help);
219 }
220
221 /*
222 str = (char *)CopyString(output_buffer);
223 */
224 /* str = (char *)calloc(1, strlen(output_buffer)+1); */
225 dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);
226 strcpy(str, output_buffer);
227
228 return str;
229 } /* command_help() */
230
231 static char *command_quit(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
232 /* Administrator wishes to quit. */
233 return NULL;
234 } /* command_quit() */
235
236 static char *show_const(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
237 /* Administrator wishes to show constants. */
238 char *result;
239 char *name;
240 char *tmp_input;
241
242 /* tmp_input = (char *)calloc(1, strlen(input)+1); */
243 dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);
244 strcpy(tmp_input, input);
245
246 /* The name will be the third token in stuff */
247 strtok(tmp_input, " ");
248 strtok(NULL, " ");
249 name = (char *)strtok(NULL, " ");
250
251 result = CO_const_to_string(name);
252
253 wr_free(tmp_input);
254 return result;
255
256 } /* show_const() */
257
258 static char *show_consts(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
259 /* Administrator wishes to show constants. */
260 return CO_to_string();
261
262 } /* show_consts() */
263
264 static char *show_props(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
265 /* Administrator wishes to show properties. */
266 return PR_to_string();
267
268 } /* show_props() */
269
270 static char *show_threads(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
271 /* Administrator wishes to show thread information. */
272 return TA_tostring();
273
274 } /* show_thread() */
275
276 static char *show_whois(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
277 /* Administrator wishes to show whois query information. */
278 return wr_string("WQ_to_string();");
279
280 } /* show_whois() */
281
282 static char *show_access(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
283 /* Administrator wishes to show whois query information. */
284
285 char line[128];
286 int cnt;
287 er_ret_t err;
288
289 if( act_runtime->top_ptr != NULL ) {
290 char *header = AC_to_string_header();
291
292 /* print header */
293 SK_cd_puts(condat,header);
294 wr_free(header);
295
296 cnt = rx_walk_tree(act_runtime->top_ptr, AC_rxwalkhook_print,
297 RX_WALK_SKPGLU, /* print no glue nodes */
298 255, 0, 0, condat, &err);
299 sprintf(line,"Found %d nodes\n", cnt);
300 SK_cd_puts(condat,line);
301 }
302
303 return wr_string("");
304
305 } /* show_access() */
306
307 static char *show_acl(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
308 /* Administrator wishes to show access control list. */
309
310 char line[128];
311 int cnt;
312 er_ret_t err;
313
314 if( act_acl->top_ptr != NULL ) {
315 char *header = AC_acl_to_string_header();
316
317 /* print header */
318 SK_cd_puts(condat,header);
319 wr_free(header);
320
321 cnt = rx_walk_tree(act_acl->top_ptr, AC_rxwalkhook_print_acl,
322 RX_WALK_SKPGLU, /* print no glue nodes */
323 255, 0, 0, condat, &err);
324 sprintf(line,"Found %d nodes\n", cnt);
325 SK_cd_puts(condat,line);
326 }
327
328 return wr_string("");
329
330 } /* show_acl() */
331
332 static char *command_execute(char *input, char *comm_name,
/* [<][>][^][v][top][bottom][index][help] */
333 Command *comm, sk_conn_st *condat) {
334 char *str;
335 char *str1;
336 char output_buffer[STR_XXL];
337 char *name;
338 int index;
339 char *tmp_input;
340
341 /* Make a copy of the input */
342 /* tmp_input = (char *)calloc(1, strlen(input)+1); */
343 dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);
344 strcpy(tmp_input, input);
345
346 strtok(tmp_input, " \t");
347 name = (char *)strtok(NULL, " \t");
348
349 index = find_command(name, comm);
350
351 switch (index) {
352 case -2:
353 str1 = show_commands(comm);
354 sprintf(output_buffer, "%s%s", comm_name, str1);
355 wr_free(str1);
356 break;
357
358 case -1:
359 sprintf(output_buffer, "%s invalid command: %s", comm_name, name);
360 break;
361
362 default:
363 sprintf(output_buffer, "%s", comm[index].function(input, condat));
364 }
365
366 /*
367 str = (char *)CopyString(output_buffer);
368 */
369 /* str = (char *)calloc(1, strlen(output_buffer)+1); */
370 dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);
371 strcpy(str, output_buffer);
372
373 wr_free(tmp_input);
374
375 return str;
376 } /* command_execute() */
377
378 static char *command_show(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
379 return command_execute(input, "Show", show, condat);
380 } /* command_show() */
381
382 static char *command_repeat(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
383 char *command_ptr;
384
385 /* Goto the bit after "repeat n " */
386 for (command_ptr=input+7; command_ptr[0] != ' ' || (command_ptr[0] >= '0' && command_ptr[0] <= '9'); command_ptr++);
387
388 return command_ptr+1;
389
390 } /* command_show() */
391
392 static char *set_const(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
393 /* Administrator wishes to set a constant. */
394 char *result;
395 char result_buf[STR_M];
396 char *tmp_input;
397 char *name;
398 char *value;
399 int value_len;
400 char *stuff;
401 char *str;
402
403 /* tmp_input = (char *)calloc(1, strlen(input)+1); */
404 dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);
405 strcpy(tmp_input, input);
406
407 stuff = (char *)strtok(tmp_input, "=");
408
409 /* The value will be after the '=' */
410 value = (char *)strtok(NULL, "=");
411
412 /* The name will be the third token in stuff */
413 strtok(stuff, " ");
414 strtok(NULL, " ");
415 name = (char *)strtok(NULL, " ");
416
417 /* Remove any quotes */
418 if (value[0] == '"') {
419 value++;
420 }
421 value_len=strlen(value);
422 if (value[value_len-1] == '"') {
423 value[value_len-1]='\0';
424 }
425
426 printf("set_const name=(%s), value=(%s)\n", name, value);
427 if (CO_set_const(name, value) == 0) {
428 strcpy(result_buf, "Constant successfully set\n");
429 }
430 else {
431 str = CO_const_to_string(name);
432 sprintf(result_buf, "Constant not successfully set\nReverting to: %s=%s\n", name, str);
433 wr_free(str);
434 }
435
436 /* result = (char *)calloc(1, strlen(result_buf)+1); */
437 dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);
438 strcpy(result, result_buf);
439
440 wr_free(tmp_input);
441 return result;
442 } /* set_const() */
443
444 static char *set_consts(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
445 /* Administrator wishes to set constants. */
446 return CO_set();
447 } /* set_consts() */
448
449 static char *set_props(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
450 /* Administrator wishes to set properties. */
451 return PR_set();
452 } /* set_props() */
453
454 static char *set_acl(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
455
456 /* first 8 characters are "set acl " so skip them */
457
458 if( ! NOERR( AC_asc_acl_command_set( input+8, "Manual"))) {
459 return wr_string("Error\n");
460 }
461 else {
462 return wr_string("OK");
463 }
464 }
465
466 static char *command_set(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
467 return command_execute(input, "Set", set, condat);
468 } /* command_set() */
469
470 static char *command_sql(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
471 char *str;
472 char output_buffer[STR_XXL];
473 char *sql_str;
474
475 char *res=NULL;
476
477 SQ_result_set_t *sql_result=NULL;
478 SQ_connection_t *sql_connection;
479
480 sql_connection = SQ_get_connection("",0,"","","");
481
482 if (sql_connection == NULL) {
483 printf("/* Check for errors */\n");
484 }
485
486 /* skip over the "sql" */
487 sql_str = input+3;
488 /* skip over white space */
489 while (sql_str[0] == ' ') {
490 sql_str++;
491 }
492
493 strcpy(output_buffer, "");
494
495 if (sql_connection != NULL) {
496 if (strcmp(sql_str, "status") == 0) {
497 /* Get the status of the database */
498 res = SQ_info_to_string(sql_connection);
499 }
500 else {
501 if (strcmp(sql_str, "") == 0) {
502 /* Execute the default query (from the properties file) */
503 SQ_execute_query(sql_connection, "", &sql_result);
504 }
505 else {
506 /* Execute an sql query */
507 SQ_execute_query(sql_connection, sql_str, &sql_result);
508 }
509 if (sql_result != NULL) {
510 res = SQ_result_to_string(sql_result);
511 }
512 else {
513 printf("no results\n");
514 }
515 }
516 if (res != NULL) {
517 sprintf(output_buffer, "%s", res);
518 }
519 else {
520 printf("empty results\n");
521 }
522 }
523 else {
524 printf("Failed to make connection\n");
525 }
526
527 /*
528 strcat(output_buffer, mysql_info(sql_connection));
529 */
530
531 strcat(output_buffer, "XXX Results from mysql_info(sql_connection) is meant to go here. But it's not working!");
532
533 /*
534 str = (char *)CopyString(output_buffer);
535 */
536 /* str = (char *)calloc(1, strlen(output_buffer)+1); */
537 dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);
538 strcpy(str, output_buffer);
539
540 wr_free(res);
541 SQ_free_result(sql_result);
542
543 SQ_close_connection(sql_connection);
544
545 return str;
546
547 } /* command_sql() */
548
549
550 /* process_input() */
551 /*++++++++++++++++++++++++++++++++++++++
552
553 Process the input.
554
555 sk_conn_st *condat connection data
556
557 More:
558 +html+ <PRE>
559 Author:
560 ottrey
561 +html+ </PRE>
562 ++++++++++++++++++++++++++++++++++++++*/
563 static int process_input(char *input, sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
564 int connected = 1;
565 char *input_ptr;
566 char *output;
567 int index;
568 int repeat=0;
569
570 input_ptr = input;
571
572 if (strncmp(input, "repeat", 6) == 0) {
573 /* XXX This is a really dodgy call, that hopefully converts
574 the string to the value of the first found integer. */
575 repeat = atoi(input+7);
576 input_ptr= command_repeat(input, condat);
577 }
578
579 index = find_command(input_ptr, command);
580
581 do {
582 switch (index) {
583 case -1:
584 /* Command not found */
585 output = command_help(NULL, condat);
586 break;
587
588 default:
589 output = command[index].function(input_ptr, condat);
590 }
591
592 if(output == NULL) {
593 connected = 0;
594 } else {
595 /*
596 printf("thread output=\n%s\n", output);
597 */
598 if ( CO_get_clear_screen() == 1 ) {
599 SK_cd_puts(condat, CLEAR_SCREEN);
600 }
601 SK_cd_puts(condat, output);
602 SK_cd_puts(condat, "\n");
603 SK_cd_puts(condat, CO_get_prompt());
604
605 wr_free(output);
606 }
607
608 if (repeat > 0) {
609 repeat--;
610 }
611
612 } while (repeat > 0);
613
614 return connected;
615
616 } /* process_input() */
617
618 static void log_config(const char *user, const char *status) {
/* [<][>][^][v][top][bottom][index][help] */
619 FILE *logf;
620 time_t now;
621 char timebuf[26];
622
623 time(&now);
624
625 printf(LOG_CONFIG, TH_get_id(), user, status, ctime_r(&now, timebuf));
626
627 } /* log_config() */
628
629 /* XXX Doh! These only change the server's terminal. We need some
630 tricky escape sequence to send over the socket.
631 static void echo_off(int sock) {
632 struct termio state;
633
634 ioctl(0, TIOCGETP, &state);
635 state.c_lflag &= ~ECHO;
636 ioctl(0, TIOCSETP, &state);
637 } echo_off() */
638
639 /* XXX Doh! These only change the server's terminal. We need some
640 tricky escape sequence to send over the socket.
641 static void echo_on(int sock) {
642 struct termio state;
643
644 ioctl(0, TIOCGETP, &state);
645 state.c_lflag |= ECHO;
646 ioctl(0, TIOCSETP, &state);
647 } echo_on() */
648
649 static char *authenticate_user(sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
650 char *user = NULL;
651 const char Salt[2] = "DB";
652 char input[MAX_INPUT_SIZE];
653 int read_result;
654 char *password=NULL;
655 char *user_password=NULL;
656 char user_buf[10];
657
658 SK_cd_puts(condat, LOGIN_PROMPT);
659 read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
660
661 strncpy(user_buf, input, 10);
662
663 SK_cd_puts(condat, PASSWD_PROMPT);
664 /* XXX These aren't working.
665 SK_puts(sock, ECHO_ON);
666 echo_off(sock);
667 */
668 read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
669 /* XXX These aren't working.
670 echo_on(sock);
671 SK_puts(sock, ECHO_OFF);
672 */
673
674 password = crypt(input, Salt);
675
676 user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
677
678 if (user_password != NULL) {
679 if (strcmp(password, user_password) == 0) {
680 /*user = (char *)calloc(1, strlen(user_buf)+1);*/
681 dieif( wr_malloc((void **)&user, strlen(user_buf)+1) != UT_OK);
682 strcpy(user, user_buf);
683 }
684 }
685
686 if (user == NULL) {
687 log_config(user_buf, "unsuccesful login attempt");
688 }
689
690 return user;
691
692 } /* authenticate_user() */
693
694 void PC_interact(int sock) {
/* [<][>][^][v][top][bottom][index][help] */
695 char input[MAX_INPUT_SIZE];
696 int connected = 1;
697 char *user=NULL;
698 sk_conn_st condat;
699
700 memset( &condat, 0, sizeof(condat));
701 condat.sock = sock;
702 SK_getpeerip(sock, &(condat.rIP));
703 condat.ip = SK_getpeername(sock); /* XXX *alloc involved */
704
705 /* Welcome the client */
706 SK_cd_puts(&condat, CO_get_welcome());
707
708 /* Authenticate the user */
709 if (CO_get_authenticate() == 1) {
710 user = authenticate_user(&condat);
711 }
712 else {
713 user="nobody";
714 }
715
716 if (user != NULL) {
717
718
719 /* Log admin logging on */
720 log_config(user, "logged on");
721
722
723 {
724 char timestring[26];
725 extern time_t SV_starttime;
726
727 ctime_r(&SV_starttime, timestring);
728 SK_cd_printf(&condat,
729 "System running since %sUptime in seconds: %ld \n\n",
730 timestring,
731 time(NULL) - SV_starttime);
732 }
733
734 SK_cd_puts(&condat, CO_get_prompt());
735
736 while (condat.rtc==0 && connected) {
737 char *ichr;
738 char *icopy;
739 char *chr;
740 /* Read input */
741 SK_cd_gets(&condat, input, MAX_INPUT_SIZE);
742
743 /* filter junk out: leading/trailing whitespaces */
744
745 /* 1. advance to non-whitespace */
746 for(ichr=input; *ichr != 0 && isspace(*ichr); ichr++) {
747 /* EMPTY */
748 }
749 /* 2. copy the rest (even if empty) */
750 dieif( (icopy = strdup(ichr)) == NULL);
751
752 /* 3. chop trailing spaces */
753 for( chr = icopy + strlen(icopy)-1 ;
754 chr != icopy && isspace(*chr);
755 chr--) {
756 *chr = 0;
757 }
758
759 /* set thread accounting */
760 TA_setactivity(icopy);
761 TA_increment();
762
763 connected = process_input(icopy, &condat);
764
765 TA_setactivity("");
766
767 free(icopy);
768 }
769
770 /* Log admin logging off */
771 log_config(user, "logged off");
772 }
773
774 /* Close the socket */
775 SK_close(sock);
776
777 wr_free(condat.ip);
778 } /* PC_interact() */
779