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