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() */