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