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