1 | /*************************************** 2 | $Revision: 1.10 $ 3 | 4 | Query command module (qc). This is what the whois query gets stored as in 5 | memory. 6 | 7 | Status: NOT REVUED, NOT TESTED 8 | 9 | ******************/ /****************** 10 | Filename : query_command.c 11 | Author : ottrey@ripe.net 12 | OSs Tested : Solaris 13 | To Do : Write some kind of options parser (to check for valid 14 | combinations of options.) 15 | Comments : 16 | ******************/ /****************** 17 | Copyright (c) 1999 RIPE NCC 18 | 19 | All Rights Reserved 20 | 21 | Permission to use, copy, modify, and distribute this software and its 22 | documentation for any purpose and without fee is hereby granted, 23 | provided that the above copyright notice appear in all copies and that 24 | both that copyright notice and this permission notice appear in 25 | supporting documentation, and that the name of the author not be 26 | used in advertising or publicity pertaining to distribution of the 27 | software without specific, written prior permission. 28 | 29 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 30 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 31 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 32 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 33 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 34 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 35 | ***************************************/ 36 | #include <stdlib.h> 37 | #include <stdio.h> 38 | 39 | #include "query_command.h" 40 | #include "objects.h" 41 | #include "constants.h" 42 | #include "which_keytypes.h" 43 | 44 | #define MAX_OPT_ARG_C 20 45 | 46 | /*+ String sizes +*/ 47 | #define STR_S 63 48 | #define STR_M 255 49 | #define STR_L 1023 50 | #define STR_XL 4095 51 | #define STR_XXL 16383 52 | 53 | /* XXX These probably wont get used. I'm using a switch statement instead. -ottrey 5/7/99 */ 54 | /* 55 | mask_t Inv_attr_mask; 56 | mask_t Object_mask; 57 | */ 58 | 59 | 60 | /* QC_bitmap_to_string() */ 61 | /*++++++++++++++++++++++++++++++++++++++ 62 | Convert the bitmap of attributes used in this query_command to a string. 63 | 64 | mask_t bitmap The bitmap of attribute to be converted. 65 | 66 | More: 67 | +html+ <PRE> 68 | Authors: 69 | ottrey 70 | +html+ </PRE><DL COMPACT> 71 | +html+ <DT>Online References: 72 | +html+ <DD><UL> 73 | +html+ </UL></DL> 74 | 75 | ++++++++++++++++++++++++++++++++++++++*/ 76 | char *QC_bitmap_to_string(mask_t bitmap) { 77 | 78 | return MA_to_string(bitmap, AT_get_attributes(), DUP_TOKENS, 0); 79 | 80 | } /* QC_bitmap_to_string() */ 81 | 82 | /* my_getopt() */ 83 | /*++++++++++++++++++++++++++++++++++++++ 84 | A thread safe version of getopt, used to get the options from the whois 85 | query. 86 | 87 | int opt_argc The number of query arguments. 88 | 89 | char **opt_argv The query arguments. 90 | 91 | char *optstring The string containing valid options. 92 | 93 | int *my_optind_ptr A pointer to the index into the options of the option 94 | returned. 95 | 96 | char **my_optarg_ptr A pointer to the arguments to be returned. 97 | 98 | More: 99 | +html+ <PRE> 100 | Authors: 101 | ottrey 102 | +html+ </PRE><DL COMPACT> 103 | +html+ <DT>Online References: 104 | +html+ <DD><UL> 105 | +html+ <LI>man getopt 106 | +html+ </UL></DL> 107 | 108 | ++++++++++++++++++++++++++++++++++++++*/ 109 | static int my_getopt(int opt_argc, char **opt_argv, char *optstring, int *my_optind_ptr, char **my_optarg_ptr) { 110 | int c='?'; 111 | int i, j; 112 | int no_options; 113 | int optind = *my_optind_ptr; 114 | char option[3]; 115 | int option_matched=0; 116 | 117 | /* Get the number of options in the option string */ 118 | for(i=0, no_options=0; i < strlen(optstring) ; i++) { 119 | if (optstring[i] != ':') { 120 | no_options++; 121 | } 122 | } 123 | 124 | /* Iterate through all the option until it matches the current opt_argv */ 125 | /* Ie. opt_argv[optind] */ 126 | for (i=0, j=0; i <= no_options; i++, j++) { 127 | /* Construct one option from the optstring */ 128 | option[0] = '-'; 129 | if (optstring[j] == ':') { 130 | j++; 131 | } 132 | option[1] = optstring[j]; 133 | if ( optstring[j+1] == ':' ) { 134 | option[2] = ':'; 135 | } 136 | else { 137 | option[2] = '\0'; 138 | } 139 | option[3] = '\0'; 140 | 141 | if (optind < opt_argc) { 142 | if (strlen(opt_argv[optind]) > 0) { 143 | /* 144 | printf("opt_argv[%d] == option <==> %s == %s\n", optind, opt_argv[optind], option); 145 | */ 146 | if (strncmp(opt_argv[optind], option, 2) == 0) { 147 | /* Does the option have arguments. */ 148 | if (option[2] == ':') { 149 | /* If the option has arguments */ 150 | if (strlen(opt_argv[optind]) > 2) { 151 | /* If the arguments are in this token */ 152 | *my_optarg_ptr = (opt_argv[optind])+2; 153 | } 154 | else { 155 | /* If the arguments are in the next token */ 156 | *my_optarg_ptr = opt_argv[optind+1]; 157 | optind++; 158 | } 159 | } 160 | else { 161 | /* There are no arguments to this token */ 162 | *my_optarg_ptr = NULL; 163 | } 164 | /* Option matched - break out of the search */ 165 | option_matched = 1; 166 | break; 167 | } 168 | } 169 | } 170 | } /* for() */ 171 | 172 | if ( option_matched == 1 ) { 173 | /* This option was matched, return it. */ 174 | c = option[1]; 175 | 176 | /* Move to the next opt_argv */ 177 | optind++; 178 | *my_optind_ptr = optind; 179 | } 180 | else { 181 | /* Discontinue search */ 182 | c = EOF; 183 | } 184 | 185 | return c; 186 | 187 | } /* my_getopt() */ 188 | 189 | /* QC_query_command_to_string() */ 190 | /*++++++++++++++++++++++++++++++++++++++ 191 | Convert the query_command to a string. 192 | 193 | Query_command *query_command The query_command to be converted. 194 | 195 | More: 196 | +html+ <PRE> 197 | Authors: 198 | ottrey 199 | +html+ </PRE><DL COMPACT> 200 | +html+ <DT>Online References: 201 | +html+ <DD><UL> 202 | +html+ </UL></DL> 203 | 204 | ++++++++++++++++++++++++++++++++++++++*/ 205 | char *QC_query_command_to_string(Query_command *query_command) { 206 | char *result; 207 | char result_buf[STR_XL]; 208 | char *str1; 209 | char *str2; 210 | char *str3; 211 | char *str4; 212 | 213 | str1 = QC_bitmap_to_string(query_command->inv_attrs_bitmap); 214 | str2 = QC_bitmap_to_string(query_command->object_type_bitmap); 215 | str3 = WK_to_string(query_command->keytypes_bitmap); 216 | str4 = AT_sources_list_to_string(query_command->sources_list); 217 | sprintf(result_buf, "Query_command : recursive=%d, inv_attrs=%s, k=%d, object_type=%s, sources=%s, (a=%d,g=%d,l=%d,m=%d,t=%d,v=%d,F=%d,L=%d,M=%d,R=%d,S=%d,V=%d), possible keytypes=%s, keys=[%s]\n", 218 | query_command->recursive, 219 | str1, 220 | query_command->k, 221 | str2, 222 | str4, 223 | query_command->a, 224 | query_command->g, 225 | query_command->l, 226 | query_command->m, 227 | query_command->t, 228 | query_command->v, 229 | query_command->F, 230 | query_command->L, 231 | query_command->M, 232 | query_command->R, 233 | query_command->S, 234 | query_command->V, 235 | str3, 236 | query_command->keys); 237 | free(str1); 238 | free(str2); 239 | free(str3); 240 | free(str4); 241 | 242 | result = (char *)calloc(1, strlen(result_buf)+1); 243 | strcpy(result, result_buf); 244 | 245 | return result; 246 | 247 | } /* QC_query_command_to_string() */ 248 | 249 | /* log_command() */ 250 | /*++++++++++++++++++++++++++++++++++++++ 251 | Log the command. 252 | This is more to do with Tracing. And should/will get merged with a tracing 253 | module (when it is finalized.) 254 | 255 | char *query_str 256 | 257 | Query_command *query_command 258 | 259 | More: 260 | +html+ <PRE> 261 | Authors: 262 | ottrey 263 | +html+ </PRE><DL COMPACT> 264 | +html+ <DT>Online References: 265 | +html+ <DD><UL> 266 | +html+ </UL></DL> 267 | 268 | ++++++++++++++++++++++++++++++++++++++*/ 269 | static void log_command(char *query_str, Query_command *query_command) { 270 | FILE *logf; 271 | char *str; 272 | 273 | if (CO_get_comnd_logging() == 1) { 274 | str = QC_query_command_to_string(query_command); 275 | if (strcmp(CO_get_comnd_logfile(), "stdout") == 0) { 276 | printf("query=[%s]\n%s", query_str, str); 277 | } 278 | else { 279 | logf = fopen(CO_get_comnd_logfile(), "a"); 280 | fprintf(logf, "query=[%s]\n%s", query_str, str); 281 | fclose(logf); 282 | } 283 | free(str); 284 | } 285 | 286 | } /* log_command() */ 287 | 288 | /* QC_free() */ 289 | /*++++++++++++++++++++++++++++++++++++++ 290 | Free the query_command. 291 | 292 | Query_command *qc query_command to be freed. 293 | 294 | XXX I'm not sure the bitmaps will get freed. 295 | qc->inv_attrs_bitmap 296 | qc->object_type_bitmap 297 | qc->keytypes_bitmap 298 | 299 | More: 300 | +html+ <PRE> 301 | Authors: 302 | ottrey 303 | +html+ </PRE><DL COMPACT> 304 | +html+ <DT>Online References: 305 | +html+ <DD><UL> 306 | +html+ </UL></DL> 307 | 308 | ++++++++++++++++++++++++++++++++++++++*/ 309 | void QC_free(Query_command *qc) { 310 | if (qc != NULL) { 311 | if (qc->keys != NULL) { 312 | free(qc->keys); 313 | } 314 | 315 | g_list_free(qc->sources_list); 316 | 317 | free(qc); 318 | } 319 | } /* QC_free() */ 320 | 321 | /* QC_new() */ 322 | /*++++++++++++++++++++++++++++++++++++++ 323 | Create a new query_command. 324 | 325 | char *query_str The garden variety whois query string. 326 | 327 | int sock The client socket. 328 | 329 | Pre-condition: OB_init() must be called before this. 330 | Ie the objects have to be created first. 331 | 332 | XXX sock shouldn't be passed here. But it needs to in order to report errors to the client. 333 | Doh!.... this needs some looking into. 334 | 335 | More: 336 | +html+ <PRE> 337 | Authors: 338 | ottrey 339 | +html+ </PRE><DL COMPACT> 340 | +html+ <DT>Online References: 341 | +html+ <DD><UL> 342 | +html+ </UL></DL> 343 | 344 | ++++++++++++++++++++++++++++++++++++++*/ 345 | Query_command *QC_new(char *query_str, int sock) { 346 | char *my_optarg; 347 | int my_optind; 348 | int c; 349 | int errflg = 0; 350 | char *inv_attrs_str = NULL; 351 | char *object_types_str = NULL; 352 | char *sources_str = NULL; 353 | int opt_argc; 354 | char *opt_argv[MAX_OPT_ARG_C]; 355 | char *value; 356 | char *tmp_query_str; 357 | char tmp_query_str_buf[STR_L]; 358 | int key_length; 359 | int i; 360 | 361 | Query_command *query_command; 362 | 363 | int index; 364 | int type; 365 | int attr; 366 | int offset; 367 | 368 | char *str; 369 | char str_buf[STR_XL]; 370 | 371 | query_command = (Query_command *)calloc(1, sizeof(Query_command)+1); 372 | query_command->a = 0; 373 | query_command->g = 0; 374 | query_command->inv_attrs_bitmap = MA_new(MA_END); 375 | query_command->k = 0; 376 | query_command->recursive = 1; 377 | query_command->l = 0; 378 | query_command->m = 0; 379 | /* The 0th source is initialized by default. */ 380 | query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(0)); 381 | query_command->t = 0; 382 | query_command->v = 0; 383 | query_command->F = 0; 384 | query_command->L = 0; 385 | query_command->M = 0; 386 | query_command->R = 0; 387 | query_command->S = 0; 388 | query_command->object_type_bitmap = MA_new(OBJECT_MASK); 389 | query_command->V = 0; 390 | /* 391 | query_command->keytypes_bitmap = MA_new(MA_END); 392 | */ 393 | query_command->keys = NULL; 394 | 395 | my_optind=1; 396 | 397 | /* This is so Marek can't crash me :-) */ 398 | /* Side Effect - query keys are subsequently cut short to STR_L size. */ 399 | /* 400 | tmp_query_str = (char *)calloc(1, strlen(query_str)); 401 | strcpy(tmp_query_str, query_str, STR_L); 402 | */ 403 | strncpy(tmp_query_str_buf, query_str, STR_L-1); 404 | tmp_query_str_buf[STR_L-1] = '\0'; 405 | 406 | opt_argv[0] = NULL; 407 | opt_argv[1] = (char *)strtok(tmp_query_str_buf, " "); 408 | opt_argc = 2; 409 | while ( (opt_argv[opt_argc] = (char *)strtok(NULL, " ")) != NULL ) { 410 | opt_argc++; 411 | /* I really would like to put this statement in the while clause, but 412 | I don't think we can be sure which order it will execute the two 413 | parts in. - So I'll leave it here. */ 414 | if ( opt_argc >= MAX_OPT_ARG_C ) break; 415 | } 416 | opt_argv[opt_argc] = NULL; 417 | 418 | 419 | while ((c = my_getopt(opt_argc, opt_argv, "agi:klrms:t:v:FLMRST:V", &my_optind, &my_optarg)) != EOF) { 420 | switch (c) { 421 | case 'a': 422 | /* The 0th source is initialized already by default. - so don't add it again. */ 423 | /* Add the rest of the sources to the list. */ 424 | for (i=1; AT_get_source(i) != NULL; i++) { 425 | query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(i)); 426 | } 427 | break; 428 | 429 | case 'g': 430 | query_command->g=1; 431 | break; 432 | 433 | case 'i': 434 | if (my_optarg != NULL) { 435 | inv_attrs_str = my_optarg; 436 | while (*inv_attrs_str) { 437 | index = getsubopt(&inv_attrs_str, AT_get_attributes(), &value); 438 | if (index == -1) { 439 | attr = -1; 440 | strcpy(str_buf, ""); 441 | sprintf(str_buf, "Unkown attribute encountered.\n"); 442 | SK_puts(sock, str_buf); 443 | errflg++; 444 | } 445 | else { 446 | attr = index/DUP_TOKENS; 447 | if ( MA_isset(OB_get_inv_attr_mask(), attr) == 1 ) { 448 | /* Add the attr to the bitmap. */ 449 | MA_set(&(query_command->inv_attrs_bitmap), attr, 1); 450 | } 451 | else { 452 | strcpy(str_buf, ""); 453 | sprintf(str_buf, "\"%s\" does not belong to inv_attr.\n", (AT_get_attributes())[index]); 454 | SK_puts(sock, str_buf); 455 | errflg++; 456 | } 457 | } 458 | } /* while () */ 459 | } /* if () */ 460 | break; 461 | 462 | case 'k': 463 | query_command->k = 1; 464 | break; 465 | 466 | case 'r': 467 | query_command->recursive = 0; 468 | break; 469 | 470 | case 'l': 471 | query_command->l=1; 472 | break; 473 | 474 | case 'm': 475 | query_command->m=1; 476 | break; 477 | 478 | case 's': 479 | if (my_optarg != NULL) { 480 | sources_str = my_optarg; 481 | /* The 0th source is initialized already by default. - so remove it first. */ 482 | query_command->sources_list = g_list_remove(query_command->sources_list, (void *)AT_get_source(0)); 483 | while (*sources_str) { 484 | index = getsubopt(&sources_str, AT_get_sources(), &value); 485 | if (index == -1) { 486 | strcpy(str_buf, ""); 487 | sprintf(str_buf, "Unkown source encountered.\nNot one of: %s\n", AT_sources_to_string()); 488 | SK_puts(sock, str_buf); 489 | errflg++; 490 | } 491 | else { 492 | query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(index)); 493 | } 494 | } /* while () */ 495 | } /* if () */ 496 | /* 497 | query_command->s=1; 498 | */ 499 | break; 500 | 501 | case 't': 502 | if (my_optarg != NULL) { 503 | object_types_str = my_optarg; 504 | while (*object_types_str) { 505 | index = getsubopt(&object_types_str, AT_get_attributes(), &value); 506 | if (index == -1) { 507 | strcpy(str_buf, ""); 508 | sprintf(str_buf, "Unkown object encountered.\n"); 509 | SK_puts(sock, str_buf); 510 | errflg++; 511 | } 512 | else { 513 | type = index/DUP_TOKENS; 514 | query_command->t=type; 515 | } 516 | } 517 | } 518 | break; 519 | 520 | case 'v': 521 | if (my_optarg != NULL) { 522 | object_types_str = my_optarg; 523 | if (*object_types_str) { 524 | index = getsubopt(&object_types_str, AT_get_attributes(), &value); 525 | if (index == -1) { 526 | strcpy(str_buf, ""); 527 | sprintf(str_buf, "Unkown object encountered.\n"); 528 | SK_puts(sock, str_buf); 529 | errflg++; 530 | } 531 | else { 532 | type = index/DUP_TOKENS; 533 | query_command->v=type; 534 | } 535 | } 536 | } 537 | break; 538 | 539 | case 'F': 540 | query_command->F=1; 541 | break; 542 | 543 | case 'L': 544 | query_command->L=1; 545 | break; 546 | 547 | case 'M': 548 | query_command->M=1; 549 | break; 550 | 551 | case 'R': 552 | query_command->R=1; 553 | break; 554 | 555 | case 'S': 556 | query_command->S=1; 557 | break; 558 | 559 | case 'T': 560 | /* XXX This is a bit tricky. 561 | The bits are initialized to be all set. 562 | Then each encountered bit is unset. 563 | Finally the result is "not'ed by using XOR with the original. */ 564 | if (my_optarg != NULL) { 565 | mask_t tmp = MA_new(OBJECT_MASK); 566 | mask_t original = MA_new(OBJECT_MASK); 567 | object_types_str = my_optarg; 568 | while (*object_types_str) { 569 | index = getsubopt(&object_types_str, AT_get_attributes(), &value); 570 | if (index == -1) { 571 | strcpy(str_buf, ""); 572 | sprintf(str_buf, "Unkown attribute encountered.\n"); 573 | SK_puts(sock, str_buf); 574 | errflg++; 575 | } 576 | else { 577 | type = index/DUP_TOKENS; 578 | if ( MA_isset(OB_get_object_mask(), type) == 1 ) { 579 | /* Add the type to the bitmap. */ 580 | MA_set(&tmp, type, 0); 581 | } 582 | else { 583 | strcpy(str_buf, ""); 584 | sprintf(str_buf, "\"%s\" does not belong to object_type.\n", (AT_get_attributes())[index]); 585 | SK_puts(sock, str_buf); 586 | errflg++; 587 | } 588 | } 589 | } 590 | query_command->object_type_bitmap = MA_xor(original, tmp); 591 | MA_free(&original); 592 | MA_free(&tmp); 593 | } 594 | break; 595 | 596 | case 'V': 597 | query_command->V=1; 598 | break; 599 | 600 | case '?': 601 | errflg++; 602 | break; 603 | 604 | default: 605 | errflg++; 606 | } 607 | } 608 | 609 | /* XXX Report the error. This could be improved. */ 610 | if (opt_argv[my_optind] != NULL) { 611 | if ( (errflg) || (strncmp(opt_argv[my_optind], "-", 1) == 0) ) { 612 | strncpy(str_buf, USAGE, STR_XL-1); 613 | SK_puts(sock, str_buf); 614 | } 615 | } 616 | else { 617 | if (errflg) { 618 | strncpy(str_buf, USAGE, STR_XL-1); 619 | SK_puts(sock, str_buf); 620 | } 621 | } 622 | 623 | 624 | /* Work out the length of space needed */ 625 | key_length = 0; 626 | for (i=my_optind ; i < opt_argc; i++) { 627 | /* length for the string + 1 for the '\0'+ 1 for the ' ' + 1 for good luck. */ 628 | if (opt_argv[i] != NULL) { 629 | key_length += strlen(opt_argv[i])+3; 630 | } 631 | } 632 | 633 | query_command->keys = (char *)calloc(1, key_length+1); 634 | strcpy(query_command->keys, ""); 635 | if (errflg == 0) { 636 | for (i=my_optind; i < opt_argc; i++) { 637 | strcat(query_command->keys, opt_argv[i]); 638 | if ( (i + 1) < opt_argc) { 639 | strcat(query_command->keys, " "); 640 | } 641 | } 642 | } /* XXX - Be careful about where this brace goes. */ 643 | 644 | /* Now we don't need this anymore */ 645 | /* 646 | free(tmp_query_str); 647 | */ 648 | 649 | /* Now convert the key to uppercase. */ 650 | for (i=0; i <= key_length; i++) { 651 | query_command->keys[i] = toupper(query_command->keys[i]); 652 | } 653 | 654 | /* Now make the keytypes_bitmap. */ 655 | query_command->keytypes_bitmap = WK_new(query_command->keys); 656 | 657 | if ( CO_get_comnd_logging() == 1 ) { 658 | log_command(query_str, query_command); 659 | } 660 | 661 | return query_command; 662 | 663 | } /* QC_new() */ 664 | 665 | /* QC_environ_update() */ 666 | /*++++++++++++++++++++++++++++++++++++++ 667 | Update the query environment. 668 | Return the new environment? 669 | This will include things like setting recursion, and the sources, and other 670 | options deemed to be of an environmental type. 671 | XXX This hasn't been implemented yet. Haven't quite decided what to do here 672 | yet. 673 | (I personally don't like functions that change two things at once, so that 674 | may also be looked into aswell.) 675 | 676 | Query_command *qc The query command to be updated. 677 | 678 | Query_command *qe The current environment. 679 | 680 | More: 681 | +html+ <PRE> 682 | Authors: 683 | ottrey 684 | +html+ </PRE><DL COMPACT> 685 | +html+ <DT>Online References: 686 | +html+ <DD><UL> 687 | +html+ </UL></DL> 688 | 689 | ++++++++++++++++++++++++++++++++++++++*/ 690 | Query_command *QC_environ_update(Query_command *qc, Query_command *qe) { 691 | Query_command *query_command; 692 | 693 | query_command = (Query_command *)calloc(1, sizeof(Query_command)+1); 694 | 695 | query_command->recursive = 1; 696 | 697 | return query_command; 698 | 699 | } /* QC_environ_update() */