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