1 /* daemon.c -- Server daemon
2 * Created: Fri Feb 28 18:17:56 1997 by faith@dict.org
3 * Copyright 1997, 1998, 1999, 2000, 2002 Rickard E. Faith (faith@dict.org)
4 * Copyright 2002-2008 Aleksey Cheusov (vle@gmx.net)
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 1, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "dictd.h"
22 #include "index.h"
23 #include "data.h"
24 #include "md5.h"
25 #include "regex.h"
26 #include "dictdplugin.h"
27 #include "strategy.h"
28 #include "plugin.h"
29
30 #include <ctype.h>
31 #include <setjmp.h>
32
33 int stdin2stdout_mode = 0; /* copy stdin to stdout ( dict_dictd function ) */
34
35 static int _dict_defines, _dict_matches;
36 static int daemonS_in = 0;
37 static int daemonS_out = 1;
38 static const char *daemonHostname = NULL;
39 static const char *daemonIP = NULL;
40 static int daemonPort = -1;
41 static char daemonStamp[256] = "";
42 static jmp_buf env;
43
44 static int daemonMime;
45
46 static void daemon_define( const char *cmdline, int argc, const char **argv );
47 static void daemon_match( const char *cmdline, int argc, const char **argv );
48 static void daemon_show_db( const char *cmdline, int argc, const char **argv );
49 static void daemon_show_strat( const char *cmdline, int argc, const char **argv );
50 void daemon_show_info( const char *cmdline, int argc, const char **argv );
51 static void daemon_show_server( const char *cmdline, int argc, const char **argv );
52 static void daemon_show( const char *cmdline, int argc, const char **argv );
53 static void daemon_option_mime( const char *cmdline, int argc, const char **argv );
54 static void daemon_option( const char *cmdline, int argc, const char **argv );
55 static void daemon_client( const char *cmdline, int argc, const char **argv );
56 static void daemon_auth( const char *cmdline, int argc, const char **argv );
57 static void daemon_status( const char *cmdline, int argc, const char **argv );
58 static void daemon_help( const char *cmdline, int argc, const char **argv );
59 static void daemon_quit( const char *cmdline, int argc, const char **argv );
60
61 typedef void (*command_t)( const char *cmdline, int argc, const char **argv );
62
63 #define MAXARGCS 3
64 static struct {
65 int argc;
66 const char *name[MAXARGCS];
67 command_t f;
68 } commandInfo[] = {
69 { 1, {"define"}, daemon_define },
70 { 1, {"d"}, daemon_define },
71 { 1, {"match"}, daemon_match },
72 { 1, {"m"}, daemon_match },
73 { 2, {"show", "db"}, daemon_show_db },
74 { 2, {"show", "databases"}, daemon_show_db },
75 { 2, {"show", "strat"}, daemon_show_strat },
76 { 2, {"show", "strategies"}, daemon_show_strat },
77 { 2, {"show", "info"}, daemon_show_info },
78 { 2, {"show", "server"}, daemon_show_server },
79 { 1, {"show"}, daemon_show },
80 { 2, {"option", "mime"}, daemon_option_mime },
81 { 1, {"option"}, daemon_option },
82 { 1, {"client"}, daemon_client },
83 { 1, {"auth"}, daemon_auth },
84 { 1, {"status"}, daemon_status },
85 { 1, {"s"}, daemon_status },
86 { 1, {"help"}, daemon_help },
87 { 1, {"h"}, daemon_help },
88 { 1, {"quit"}, daemon_quit },
89 { 1, {"q"}, daemon_quit },
90 };
91 #define COMMANDS (sizeof(commandInfo)/sizeof(commandInfo[0]))
92
lookup_command(int argc,const char ** argv)93 static command_t lookup_command( int argc, const char **argv )
94 {
95 size_t i;
96 int j;
97 int err;
98
99 for (i = 0; i < COMMANDS; i++) {
100 if (argc >= commandInfo[i].argc) {
101 for (err = 0, j = 0; j < commandInfo[i].argc; j++) {
102 if (strcasecmp(argv[j], commandInfo[i].name[j])) {
103 err = 1;
104 break;
105 }
106 }
107 if (!err) return commandInfo[i].f;
108 }
109 }
110 return NULL;
111 }
112
daemon_compute_mask(int bits)113 static unsigned long daemon_compute_mask(int bits)
114 {
115 unsigned long mask = 0xffffffff;
116
117 if (bits < 1) return 0;
118 if (bits < 32) mask -= (1 << (32-bits)) - 1;
119 return mask;
120 }
121
daemon_log(int type,const char * format,...)122 static void daemon_log( int type, const char *format, ... )
123 {
124 va_list ap;
125 char buf[8*1024];
126 char *buf2;
127 size_t len;
128 char *s, *d;
129 int c;
130 char marker = '?';
131
132 switch (type) {
133 case DICT_LOG_TERM:
134 if (!flg_test(LOG_STATS)) return; marker = 'I'; break;
135 case DICT_LOG_TRACE:
136 if (!flg_test(LOG_SERVER)) return; marker = 'I'; break;
137 case DICT_LOG_CLIENT:
138 if (!flg_test(LOG_CLIENT)) return; marker = 'C'; break;
139 case DICT_LOG_CONNECT:
140 if (!flg_test(LOG_CONNECT)) return; marker = 'K'; break;
141 case DICT_LOG_DEFINE:
142 if (!flg_test(LOG_FOUND)) return; marker = 'D'; break;
143 case DICT_LOG_MATCH:
144 if (!flg_test(LOG_FOUND)) return; marker = 'M'; break;
145 case DICT_LOG_NOMATCH:
146 if (!flg_test(LOG_NOTFOUND)) return; marker = 'N'; break;
147 case DICT_LOG_COMMAND:
148 if (!flg_test(LOG_COMMAND)) return; marker = 'T'; break;
149 case DICT_LOG_AUTH:
150 if (!flg_test(LOG_AUTH)) return; marker = 'A'; break;
151 }
152
153 if (dbg_test(DBG_PORT))
154 snprintf(
155 buf, sizeof (buf)/2,
156 ":%c: %s:%d ", marker, daemonHostname, daemonPort );
157 else if (flg_test(LOG_HOST))
158 snprintf(
159 buf, sizeof (buf)/2,
160 ":%c: %s ", marker, daemonHostname );
161 else
162 snprintf(
163 buf, sizeof (buf)/2,
164 ":%c: ", marker );
165
166 len = strlen( buf );
167
168 va_start( ap, format );
169 vsnprintf( buf+len, sizeof (buf)/2-len, format, ap );
170 va_end( ap );
171 len = strlen( buf );
172
173 if (len >= sizeof (buf)/2) {
174 log_info( ":E: buffer overflow (%d)\n", len );
175 buf[2048] = '\0';
176 len = strlen(buf);
177 }
178
179 buf2 = alloca( 3*(len+3) );
180
181 for (s = buf, d = buf2; *s; s++) {
182 c = (unsigned char)*s;
183 if (c == '\t') *d++ = ' ';
184 else if (c == '\n') *d++ = c;
185 else {
186 if (c < 32) { *d++ = '^'; *d++ = c + 64; }
187 else if (c == 127) { *d++ = '^'; *d++ = '?'; }
188 else *d++ = c;
189 }
190 }
191 *d = '\0';
192 log_info( "%s", buf2 );
193
194 if (d != buf2) d[-1] = '\0'; /* kill newline */
195 dict_setproctitle( "dictd %s", buf2 );
196 }
197
daemon_check_mask(const char * spec,const char * ip)198 static int daemon_check_mask(const char *spec, const char *ip)
199 {
200 char *tmp = alloca(strlen(spec) + 1);
201 char *pt;
202 char tstring[64], mstring[64];
203 struct in_addr target, mask;
204 int bits;
205 unsigned long bitmask;
206
207 strcpy(tmp, spec);
208 if (!(pt = strchr(tmp, '/'))) {
209 log_info( ":E: No / in %s, denying access to %s\n", spec, ip);
210 return DICT_DENY;
211 }
212 *pt++ = '\0';
213 if (!*pt) {
214 log_info( ":E: No bit count after / in %s, denying access to %s\n",
215 spec, ip);
216 return DICT_DENY;
217 }
218
219 inet_aton(ip, &target);
220 inet_aton(tmp, &mask);
221 bits = strtol(pt, NULL, 10);
222 strcpy(tstring, inet_ntoa(target));
223 strcpy(mstring, inet_ntoa(mask));
224 if (bits < 0 || bits > 32) {
225 log_info( ":E: Bit count (%d) out of range, denying access to %s\n",
226 bits, ip);
227 return DICT_DENY;
228 }
229
230 bitmask = daemon_compute_mask(bits);
231 if ((ntohl(target.s_addr) & bitmask) == (ntohl(mask.s_addr) & bitmask)) {
232 PRINTF(DBG_AUTH, ("%s matches %s/%d\n", tstring, mstring, bits));
233 return DICT_MATCH;
234 }
235 PRINTF(DBG_AUTH, ("%s does NOT match %s/%d\n", tstring, mstring, bits));
236 return DICT_NOMATCH;
237 }
238
daemon_check_range(const char * spec,const char * ip)239 static int daemon_check_range(const char *spec, const char *ip)
240 {
241 char *tmp = alloca(strlen(spec) + 1);
242 char *pt;
243 char tstring[64], minstring[64], maxstring[64];
244 struct in_addr target, min, max;
245
246 strcpy(tmp, spec);
247 if (!(pt = strchr(tmp, ':'))) {
248 log_info( ":E: No : in range %s, denying access to %s\n", spec, ip);
249 return DICT_DENY;
250 }
251 *pt++ = '\0';
252 if (strchr(pt, ':')) {
253 log_info( ":E: More than one : in range %s, denying access to %s\n",
254 spec, ip);
255 return DICT_DENY;
256 }
257 if (!*pt) {
258 log_info( ":E: Misformed range %s, denying access to %s\n", spec, ip);
259 return DICT_DENY;
260 }
261
262 inet_aton(ip, &target);
263 inet_aton(tmp, &min);
264 inet_aton(pt, &max);
265 strcpy(tstring, inet_ntoa(target));
266 strcpy(minstring, inet_ntoa(min));
267 strcpy(maxstring, inet_ntoa(max));
268 if (ntohl(target.s_addr) >= ntohl(min.s_addr)
269 && ntohl(target.s_addr) <= ntohl(max.s_addr)) {
270 PRINTF(DBG_AUTH,("%s in range from %s to %s\n",
271 tstring, minstring, maxstring));
272 return DICT_MATCH;
273 }
274 PRINTF(DBG_AUTH,("%s NOT in range from %s to %s\n",
275 tstring, minstring, maxstring));
276 return DICT_NOMATCH;
277 }
278
daemon_check_wildcard(const char * spec,const char * ip)279 static int daemon_check_wildcard(const char *spec, const char *ip)
280 {
281 char regbuf[256];
282 char erbuf[100];
283 int err;
284 const char *s;
285 char *d;
286 regex_t re;
287
288 for (d = regbuf, s = spec; s && *s; ++s) {
289 switch (*s) {
290 case '*': *d++ = '.'; *d++ = '*'; break;
291 case '.': *d++ = '\\'; *d++ = '.'; break;
292 case '?': *d++ = '.'; break;
293 default: *d++ = *s; break;
294 }
295 }
296 *d = '\0';
297 if ((err = regcomp(&re, regbuf, REG_ICASE|REG_NOSUB))) {
298 regerror(err, &re, erbuf, sizeof(erbuf));
299 log_info( ":E: regcomp(%s): %s\n", regbuf, erbuf );
300 return DICT_DENY; /* Err on the side of safety */
301 }
302 if (!regexec(&re, daemonHostname, 0, NULL, 0)
303 || !regexec(&re, daemonIP, 0, NULL, 0)) {
304 PRINTF(DBG_AUTH,
305 ("Match %s with %s/%s\n", spec, daemonHostname, daemonIP));
306 regfree(&re);
307 return DICT_MATCH;
308 }
309 regfree(&re);
310 PRINTF(DBG_AUTH,
311 ("No match (%s with %s/%s)\n", spec, daemonHostname, daemonIP));
312 return DICT_NOMATCH;
313 }
314
daemon_check_list(const char * user,lst_List acl)315 static int daemon_check_list( const char *user, lst_List acl )
316 {
317 lst_Position p;
318 dictAccess *a;
319 int retcode;
320
321 if (!acl)
322 return DICT_ALLOW;
323
324 for (p = lst_init_position(acl); p; p = lst_next_position(p)) {
325 a = lst_get_position(p);
326 switch (a->type) {
327 case DICT_DENY:
328 case DICT_ALLOW:
329 case DICT_AUTHONLY:
330 if (strchr(a->spec, '/'))
331 retcode = daemon_check_mask(a->spec, daemonIP);
332 else if (strchr(a->spec, ':'))
333 retcode = daemon_check_range(a->spec, daemonIP);
334 else
335 retcode = daemon_check_wildcard(a->spec, daemonIP);
336 switch (retcode) {
337 case DICT_DENY:
338 return DICT_DENY;
339 case DICT_MATCH:
340 if (a->type == DICT_DENY) {
341 daemon_log( DICT_LOG_AUTH, "spec %s denies %s/%s\n",
342 a->spec, daemonHostname, daemonIP);
343 }
344 return a->type;
345 }
346 break;
347 case DICT_USER:
348 if (user && !strcmp(user,a->spec)) return DICT_ALLOW;
349 case DICT_GROUP: /* Groups are not yet implemented. */
350 break;
351 }
352 }
353 return DICT_DENY;
354 }
355
daemon_check_auth(const char * user)356 static int daemon_check_auth( const char *user )
357 {
358 lst_Position p;
359 lst_List dbl = DictConfig->dbl;
360 dictDatabase *db;
361
362 switch (daemon_check_list( user, DictConfig->acl )) {
363 default:
364 case DICT_DENY:
365 return 1;
366 case DICT_AUTHONLY:
367 if (!user) return 0;
368 case DICT_ALLOW:
369 for (p = lst_init_position(dbl); p; p = lst_next_position(p)) {
370 db = lst_get_position(p);
371 switch (daemon_check_list(user, db->acl)) {
372 case DICT_ALLOW: db->available = 1; continue;
373 default: db->available = 0; continue;
374 }
375 }
376 break;
377 }
378 return 0;
379 }
380
daemon_terminate(int sig,const char * name)381 void daemon_terminate( int sig, const char *name )
382 {
383 alarm(0);
384 tim_stop( "t" );
385 close(daemonS_in);
386 close(daemonS_out);
387 if (name) {
388 daemon_log( DICT_LOG_TERM,
389 "%s: d/m/c = %d/%d/%d; %sr %su %ss\n",
390 name,
391 _dict_defines,
392 _dict_matches,
393 _dict_comparisons,
394 dict_format_time( tim_get_real( "t" ) ),
395 dict_format_time( tim_get_user( "t" ) ),
396 dict_format_time( tim_get_system( "t" ) ) );
397 } else {
398 daemon_log( DICT_LOG_TERM,
399 "signal %d: d/m/c = %d/%d/%d; %sr %su %ss\n",
400 sig,
401 _dict_defines,
402 _dict_matches,
403 _dict_comparisons,
404 dict_format_time( tim_get_real( "t" ) ),
405 dict_format_time( tim_get_user( "t" ) ),
406 dict_format_time( tim_get_system( "t" ) ) );
407 }
408
409 log_close();
410 longjmp(env,1);
411 if (sig) exit(sig+128);
412
413 exit(0);
414 }
415
416
daemon_write(const char * buf,int len)417 static void daemon_write( const char *buf, int len )
418 {
419 int left = len;
420 int count;
421
422 while (left) {
423 if ((count = write(daemonS_out, buf, left)) != left) {
424 if (count <= 0) {
425 if (errno == EPIPE) {
426 daemon_terminate( 0, "pipe" );
427 }
428 log_info( ":E: writing %d of %d bytes:"
429 " retval = %d, errno = %d (%s)\n",
430 left, len, count, errno, strerror(errno) );
431 daemon_terminate( 0, __func__ );
432 }
433 }
434 left -= count;
435 }
436 }
437
daemon_crlf(char * d,const char * s,int dot)438 static void daemon_crlf( char *d, const char *s, int dot )
439 {
440 int first = 1;
441
442 while (*s) {
443 if (*s == '\n') {
444 *d++ = '\r';
445 *d++ = '\n';
446 first = 1;
447 ++s;
448 } else {
449 if (dot && first && *s == '.' && s[1] == '\n')
450 *d++ = '.'; /* double first dot on line */
451 first = 0;
452 *d++ = *s++;
453 }
454 }
455 if (dot) { /* add final . */
456 if (!first){
457 *d++ = '\r';
458 *d++ = '\n';
459 }
460 *d++ = '.';
461 *d++ = '\r';
462 *d++ = '\n';
463 }
464 *d = '\0';
465 }
466
daemon_printf(const char * format,...)467 static void daemon_printf( const char *format, ... )
468 {
469 va_list ap;
470 char buf[BUFFERSIZE];
471 char *pt;
472 int len;
473
474 va_start( ap, format );
475 vsnprintf( buf, sizeof (buf), format, ap );
476 va_end( ap );
477 if ((len = strlen( buf )) >= BUFFERSIZE) {
478 log_info( ":E: buffer overflow: %d\n", len );
479 daemon_terminate( 0, __func__ );
480 }
481
482 pt = alloca(2*len + 10); /* +10 for the case when buf == "\n"*/
483 daemon_crlf(pt, buf, 0);
484 daemon_write(pt, strlen(pt));
485 }
486
daemon_mime(void)487 static void daemon_mime( void )
488 {
489 if (daemonMime) daemon_write( "\r\n", 2 );
490 }
491
daemon_mime_definition(const dictDatabase * db)492 static void daemon_mime_definition (const dictDatabase *db)
493 {
494 if (daemonMime){
495 if (db -> mime_header){
496 daemon_printf ("%s", db -> mime_header);
497 }
498
499 daemon_write ("\r\n", 2);
500 }
501 }
502
daemon_text(const char * text,int dot)503 static void daemon_text( const char *text, int dot )
504 {
505 char *pt = alloca( 2*strlen(text) + 10 );
506
507 daemon_crlf(pt, text, dot);
508 daemon_write(pt, strlen(pt));
509 }
510
daemon_read(char * buf,int count)511 static int daemon_read( char *buf, int count )
512 {
513 return net_read( daemonS_in, buf, count );
514 }
515
daemon_ok(int code,const char * string,const char * timer)516 static void daemon_ok( int code, const char *string, const char *timer )
517 {
518 static int lastDefines = 0;
519 static int lastMatches = 0;
520 static int lastComparisons = 0;
521
522 if (code == CODE_STATUS) {
523 lastDefines = 0;
524 lastMatches = 0;
525 lastComparisons = 0;
526 }
527
528 if (!timer) {
529 daemon_printf("%d %s\n", code, string);
530 } else {
531 tim_stop( timer );
532 daemon_printf("%d %s [d/m/c = %d/%d/%d; %sr %su %ss]\n",
533 code,
534 string,
535 _dict_defines - lastDefines,
536 _dict_matches - lastMatches,
537 _dict_comparisons - lastComparisons,
538 dict_format_time( tim_get_real( timer ) ),
539 dict_format_time( tim_get_user( timer ) ),
540 dict_format_time( tim_get_system( timer ) ) );
541 }
542
543 lastDefines = _dict_defines;
544 lastMatches = _dict_matches;
545 lastComparisons = _dict_comparisons;
546 }
547
daemon_count_defs(lst_List list)548 static int daemon_count_defs( lst_List list )
549 {
550 lst_Position p;
551 dictWord *dw;
552 unsigned long previousStart = 0;
553 unsigned long previousEnd = 0;
554 const char *previousDef = NULL;
555 int count = 0;
556
557 LST_ITERATE(list,p,dw) {
558 if (
559 previousStart == dw->start &&
560 previousEnd == dw->end &&
561 previousDef == dw->def)
562 {
563 continue;
564 }
565
566 previousStart = dw->start;
567 previousEnd = dw->end;
568 previousDef = dw->def;
569
570 ++count;
571 }
572 return count;
573 }
574
daemon_dump_defs(lst_List list)575 static void daemon_dump_defs( lst_List list )
576 {
577 lst_Position p;
578 char *buf;
579 dictWord *dw;
580 const dictDatabase *db = NULL;
581 const dictDatabase *db_visible = NULL;
582 unsigned long previousStart = 0;
583 unsigned long previousEnd = 0;
584 const char * previousDef = NULL;
585 int count;
586
587 LST_ITERATE(list,p,dw) {
588 db = dw->database;
589
590 if (
591 previousStart == dw->start &&
592 previousEnd == dw->end &&
593 previousDef == dw->def)
594 {
595 continue;
596 }
597
598 previousStart = dw->start;
599 previousEnd = dw->end;
600 previousDef = dw->def;
601
602 buf = dict_data_obtain ( db, dw );
603
604 if (dw -> database_visible){
605 db_visible = dw -> database_visible;
606 }else{
607 db_visible = db;
608 }
609
610 daemon_printf (
611 "%d \"%s\" %s \"%s\"\n",
612 CODE_DEFINITION_FOLLOWS,
613 dw->word,
614 db_visible -> invisible ? "*" : db_visible -> databaseName,
615 db_visible -> invisible ? "" : db_visible -> databaseShort);
616
617 daemon_mime_definition (db);
618
619 if (db->filter){
620 count = strlen(buf);
621 daemon_log( DICT_LOG_AUTH, "filtering with: %s\ncount: %d\n",
622 db->filter, count );
623
624 dict_data_filter(buf, &count, strlen (buf), db->filter);
625 buf[count] = '\0';
626 }
627
628 daemon_text(buf, 1);
629 xfree( buf );
630 }
631 }
632
daemon_count_matches(lst_List list)633 static int daemon_count_matches( lst_List list )
634 {
635 lst_Position p;
636 dictWord *dw;
637 const char *prevword = NULL;
638 const dictDatabase *prevdb = NULL;
639 int count = 0;
640
641 LST_ITERATE(list,p,dw) {
642 if (prevdb == dw->database && prevword && !strcmp(prevword,dw->word))
643 continue;
644
645 prevword = dw->word;
646 prevdb = dw->database;
647
648 ++count;
649 }
650 return count;
651 }
652
daemon_dump_matches(lst_List list)653 static void daemon_dump_matches( lst_List list )
654 {
655 lst_Position p;
656 dictWord *dw;
657 const char *prevword = NULL;
658 const dictDatabase *prevdb = NULL;
659 const dictDatabase *db = NULL;
660
661 daemon_mime();
662 LST_ITERATE(list,p,dw) {
663 db = dw -> database;
664
665 if (prevdb == dw->database && prevword && !strcmp(prevword,dw->word))
666 continue;
667
668 prevword = dw->word;
669 prevdb = dw->database;
670
671 if (dw -> database_visible){
672 db = dw -> database_visible;
673 }
674
675 daemon_printf (
676 "%s \"%s\"\n",
677 db -> invisible ? "*" : db -> databaseName,
678 dw -> word );
679 }
680 daemon_printf( ".\n" );
681 }
682
daemon_banner(void)683 static void daemon_banner( void )
684 {
685 time_t t;
686
687 time(&t);
688
689 snprintf( daemonStamp, sizeof (daemonStamp), "<%d.%d.%lu@%s>",
690 _dict_forks,
691 (int) getpid(),
692 (long unsigned)t,
693 net_hostname() );
694 daemon_printf( "%d %s %s <auth.mime> %s\n",
695 CODE_HELLO,
696 net_hostname(),
697 dict_get_banner(0),
698 daemonStamp );
699 }
700
daemon_define(const char * cmdline,int argc,const char ** argv)701 static void daemon_define( const char *cmdline, int argc, const char **argv )
702 {
703 lst_List list = lst_create();
704 int matches = 0;
705 const char *word;
706 const char *databaseName;
707 int extension = (argv[0][0] == 'd' && argv[0][1] == '\0');
708 int db_found = 0;
709
710 if (extension) {
711 switch (argc) {
712 case 2: databaseName = "*"; word = argv[1]; break;
713 case 3: databaseName = argv[1]; word = argv[2]; break;
714 default:
715 daemon_printf( "%d syntax error, illegal parameters\n",
716 CODE_ILLEGAL_PARAM );
717 return;
718 }
719 } else if (argc == 3) {
720 databaseName = argv[1];
721 word = argv[2];
722 } else {
723 daemon_printf( "%d syntax error, illegal parameters\n",
724 CODE_ILLEGAL_PARAM );
725 return;
726 }
727
728 matches = abs(dict_search_databases (
729 list, NULL,
730 databaseName, word, DICT_STRAT_EXACT,
731 &db_found));
732
733 if (db_found && matches > 0) {
734 int actual_matches = daemon_count_defs( list );
735
736 _dict_defines += actual_matches;
737 daemon_log( DICT_LOG_DEFINE,
738 "%s \"%s\" %d\n", databaseName, word, actual_matches);
739 daemon_printf( "%d %d definitions retrieved\n",
740 CODE_DEFINITIONS_FOUND,
741 actual_matches );
742 daemon_dump_defs( list );
743 daemon_ok( CODE_OK, "ok", "c" );
744 #ifdef USE_PLUGIN
745 call_dictdb_free (DictConfig->dbl);
746 #endif
747 dict_destroy_list( list );
748 return;
749 }
750
751 if (!db_found) {
752 #ifdef USE_PLUGIN
753 call_dictdb_free (DictConfig->dbl);
754 #endif
755 dict_destroy_list( list );
756 daemon_printf( "%d invalid database, use SHOW DB for list\n",
757 CODE_INVALID_DB );
758 return;
759 }
760
761 #ifdef USE_PLUGIN
762 call_dictdb_free (DictConfig->dbl);
763 #endif
764 dict_destroy_list( list );
765 daemon_log( DICT_LOG_NOMATCH,
766 "%s exact \"%s\"\n", databaseName, word );
767 daemon_ok( CODE_NO_MATCH, "no match", "c" );
768 }
769
daemon_match(const char * cmdline,int argc,const char ** argv)770 static void daemon_match( const char *cmdline, int argc, const char **argv )
771 {
772 lst_List list = lst_create();
773 int matches = 0;
774 const char *word;
775 const char *databaseName;
776 const char *strategy;
777 int strategyNumber;
778 int extension = (argv[0][0] == 'm' && argv[0][1] == '\0');
779 int db_found = 0;
780
781 if (extension) {
782 switch (argc) {
783 case 2:databaseName = "*"; strategy = "."; word = argv[1]; break;
784 case 3:databaseName = "*"; strategy = argv[1]; word = argv[2]; break;
785 case 4:databaseName = argv[1]; strategy = argv[2]; word = argv[3]; break;
786 default:
787 daemon_printf( "%d syntax error, illegal parameters\n",
788 CODE_ILLEGAL_PARAM );
789 return;
790 }
791 } else if (argc == 4) {
792 databaseName = argv[1];
793 strategy = argv[2];
794 word = argv[3];
795 } else {
796 daemon_printf( "%d syntax error, illegal parameters\n",
797 CODE_ILLEGAL_PARAM );
798 return;
799 }
800
801 if ((strategyNumber = lookup_strategy(strategy)) < 0) {
802 daemon_printf( "%d invalid strategy, use SHOW STRAT for a list\n",
803 CODE_INVALID_STRATEGY );
804 return;
805 }
806
807 matches = abs(dict_search_databases (
808 list, NULL,
809 databaseName, word, strategyNumber | DICT_MATCH_MASK,
810 &db_found));
811
812 if (db_found && matches > 0) {
813 int actual_matches = daemon_count_matches( list );
814
815 _dict_matches += actual_matches;
816 daemon_log( DICT_LOG_MATCH,
817 "%s %s \"%s\" %d\n",
818 databaseName, strategy, word, actual_matches);
819 daemon_printf( "%d %d matches found\n",
820 CODE_MATCHES_FOUND, actual_matches );
821 daemon_dump_matches( list );
822 daemon_ok( CODE_OK, "ok", "c" );
823 #ifdef USE_PLUGIN
824 call_dictdb_free (DictConfig->dbl);
825 #endif
826 dict_destroy_list( list );
827 return;
828 }
829
830 if (!db_found) {
831 #ifdef USE_PLUGIN
832 call_dictdb_free (DictConfig->dbl);
833 #endif
834 dict_destroy_list( list );
835 daemon_printf( "%d invalid database, use SHOW DB for list\n",
836 CODE_INVALID_DB );
837 return;
838 }
839
840 #ifdef USE_PLUGIN
841 call_dictdb_free (DictConfig->dbl);
842 #endif
843 dict_destroy_list( list );
844 daemon_log( DICT_LOG_NOMATCH,
845 "%s %s \"%s\"\n", databaseName, strategy, word );
846 daemon_ok( CODE_NO_MATCH, "no match", "c" );
847 }
848
first_database_pos(void)849 static lst_Position first_database_pos (void)
850 {
851 return lst_init_position (DictConfig->dbl);
852 }
853
next_database(lst_Position * databasePosition,const char * name)854 static dictDatabase *next_database (
855 lst_Position *databasePosition,
856 const char *name)
857 {
858 dictDatabase *db = NULL;
859
860 assert (databasePosition);
861
862 if (!name)
863 return NULL;
864
865 if (*name == '*' || *name == '!') {
866 if (*databasePosition) {
867 do {
868 db = lst_get_position( *databasePosition );
869
870 *databasePosition = lst_next_position( *databasePosition );
871 } while ( db && (!db->available || db->invisible));
872 }
873 return db;
874 } else {
875 while (*databasePosition) {
876 db = lst_get_position( *databasePosition );
877 *databasePosition = lst_next_position( *databasePosition );
878
879 if (db){
880 if (
881 !db -> invisible && db->available &&
882 !strcmp(db -> databaseName,name))
883 {
884 return db;
885 }
886 }else{
887 return NULL;
888 }
889 }
890
891 return NULL;
892 }
893 }
894
count_databases(void)895 static int count_databases( void )
896 {
897 int count = 0;
898 const dictDatabase *db;
899
900 lst_Position databasePosition = first_database_pos ();
901
902 while (NULL != (db = next_database (&databasePosition, "*"))){
903 assert (!db -> invisible);
904
905 if (!db -> exit_db)
906 ++count;
907 }
908
909 return count;
910 }
911
destroy_word_list(lst_List l)912 static void destroy_word_list (lst_List l)
913 {
914 char *word;
915
916 while (lst_length (l)){
917 word = lst_pop (l);
918 if (word)
919 xfree (word);
920 }
921 lst_destroy (l);
922 }
923
924 /*
925 Search for all words in word_list in the database db
926 */
dict_search_words(lst_List * l,lst_List word_list,const dictDatabase * db,int strategy,int * error,int * result,const dictPluginData ** extra_result,int * extra_result_size)927 static int dict_search_words (
928 lst_List *l,
929 lst_List word_list,
930 const dictDatabase *db,
931 int strategy,
932 int *error, int *result,
933 const dictPluginData **extra_result, int *extra_result_size)
934 {
935 lst_Position word_list_pos;
936 int mc = 0;
937 int matches_count = 0;
938 const char *word;
939
940 word_list_pos = lst_init_position (word_list);
941 while (word_list_pos){
942 word = lst_get_position (word_list_pos);
943
944 if (word){
945 matches_count = dict_search (
946 l, word, db, strategy,
947 daemonMime,
948 result, extra_result, extra_result_size);
949
950 if (*result == DICT_PLUGIN_RESULT_PREPROCESS){
951 assert (matches_count > 0);
952
953 xfree (lst_get_position (word_list_pos));
954 lst_set_position (word_list_pos, NULL);
955 }
956
957 if (matches_count < 0){
958 *error = 1;
959 matches_count = abs (matches_count);
960 mc += matches_count;
961 break;
962 }
963
964 mc += matches_count;
965 }
966
967 word_list_pos = lst_next_position (word_list_pos);
968 }
969
970 return mc;
971 }
972
dict_search_databases(lst_List * l,lst_Position databasePosition,const char * databaseName,const char * word,int strategy,int * db_found)973 int dict_search_databases (
974 lst_List *l,
975 lst_Position databasePosition, /* NULL for global database list */
976 const char *databaseName, const char *word, int strategy,
977 int *db_found)
978 {
979 int matches = -1;
980 int matches_count = 0;
981 int error = 0;
982
983
984 const dictDatabase *db;
985 dictWord *dw;
986 char *p;
987
988 lst_List preprocessed_words;
989 int i;
990
991 int result;
992 const dictPluginData *extra_result;
993 int extra_result_size;
994
995 *db_found = 0;
996
997 if (!databasePosition)
998 databasePosition = first_database_pos ();
999
1000 preprocessed_words = lst_create ();
1001 lst_append (preprocessed_words, xstrdup(word));
1002
1003 while (!error && (db = next_database (&databasePosition, databaseName))) {
1004 if (db -> exit_db)
1005 /* dictionary_exit */
1006 break;
1007
1008 *db_found = 1;
1009
1010 result = DICT_PLUGIN_RESULT_NOTFOUND;
1011
1012 matches_count = dict_search_words (
1013 l,
1014 preprocessed_words, db, strategy,
1015 &error,
1016 &result, &extra_result, &extra_result_size);
1017
1018 if (matches < 0)
1019 matches = 0;
1020
1021 if (result == DICT_PLUGIN_RESULT_PREPROCESS){
1022 for (i=0; i < matches_count; ++i){
1023 dw = lst_pop (l);
1024 switch (dw -> def_size){
1025 case -1:
1026 p = xstrdup (dw -> word);
1027 lst_append (preprocessed_words, p);
1028 break;
1029 case 0:
1030 break;
1031 default:
1032 p = xmalloc (1 + dw -> def_size);
1033 memcpy (p, dw -> def, dw -> def_size);
1034 p [dw -> def_size] = 0;
1035
1036 lst_append (preprocessed_words, p);
1037 }
1038
1039 dict_destroy_datum (dw);
1040 }
1041 }else{
1042 matches += matches_count;
1043
1044 if (result == DICT_PLUGIN_RESULT_EXIT)
1045 break;
1046
1047 if (*databaseName == '*')
1048 continue;
1049 else if (!matches && *databaseName == '!')
1050 continue;
1051
1052 break;
1053 }
1054 }
1055
1056 destroy_word_list (preprocessed_words);
1057
1058 return error ? -matches : matches;
1059 }
1060
daemon_show_db(const char * cmdline,int argc,const char ** argv)1061 static void daemon_show_db( const char *cmdline, int argc, const char **argv )
1062 {
1063 int count;
1064 const dictDatabase *db;
1065
1066 lst_Position databasePosition;
1067
1068 if (argc != 2) {
1069 daemon_printf( "%d syntax error, illegal parameters\n",
1070 CODE_ILLEGAL_PARAM );
1071 return;
1072 }
1073
1074 if (!(count = count_databases())) {
1075 daemon_printf( "%d no databases present\n", CODE_NO_DATABASES );
1076 } else {
1077 daemon_printf( "%d %d databases present\n",
1078 CODE_DATABASE_LIST, count );
1079
1080 databasePosition = first_database_pos ();
1081
1082 daemon_mime();
1083 while ((db = next_database(&databasePosition, "*"))) {
1084 assert (!db->invisible);
1085
1086 if (db -> exit_db)
1087 continue;
1088
1089 daemon_printf(
1090 "%s \"%s\"\n",
1091 db->databaseName, db->databaseShort );
1092 }
1093 daemon_printf( ".\n" );
1094 daemon_ok( CODE_OK, "ok", NULL );
1095 }
1096 }
1097
daemon_show_strat(const char * cmdline,int argc,const char ** argv)1098 static void daemon_show_strat( const char *cmdline, int argc, const char **argv )
1099 {
1100 int i;
1101
1102 int strat_count = get_strategy_count ();
1103 dictStrategy const * const * strats = get_strategies ();
1104
1105 if (argc != 2) {
1106 daemon_printf( "%d syntax error, illegal parameters\n",
1107 CODE_ILLEGAL_PARAM );
1108 return;
1109 }
1110
1111 if (strat_count){
1112 daemon_printf( "%d %d strategies present\n",
1113 CODE_STRATEGY_LIST, strat_count );
1114 daemon_mime();
1115
1116 for (i = 0; i < strat_count; i++) {
1117 daemon_printf( "%s \"%s\"\n",
1118 strats [i] -> name, strats [i] -> description );
1119 }
1120
1121 daemon_printf( ".\n" );
1122 daemon_ok( CODE_OK, "ok", NULL );
1123 }else{
1124 daemon_printf( "%d no strategies available\n", CODE_NO_STRATEGIES );
1125 }
1126 }
1127
daemon_show_info(const char * cmdline,int argc,const char ** argv)1128 void daemon_show_info(
1129 const char *cmdline,
1130 int argc, const char **argv )
1131 {
1132 char *buf=NULL;
1133 dictWord *dw;
1134 const dictDatabase *db;
1135 lst_List list;
1136 const char *info_entry_name = DICT_INFO_ENTRY_NAME;
1137
1138 lst_Position databasePosition = first_database_pos ();
1139
1140 if (argc != 3) {
1141 daemon_printf( "%d syntax error, illegal parameters\n",
1142 CODE_ILLEGAL_PARAM );
1143 return;
1144 }
1145
1146 if ((argv[2][0] == '*' || argv[2][0] == '!') && argv[2][1] == '\0') {
1147 daemon_printf( "%d invalid database, use SHOW DB for list\n",
1148 CODE_INVALID_DB );
1149 return;
1150 }
1151
1152 list = lst_create();
1153 while ((db = next_database(&databasePosition, argv[2]))) {
1154 if (db -> databaseInfo && db -> databaseInfo [0] != '@'){
1155 daemon_printf( "%d information for %s\n",
1156 CODE_DATABASE_INFO, argv[2] );
1157 daemon_mime();
1158 daemon_text(db -> databaseInfo, 1);
1159 daemon_ok( CODE_OK, "ok", NULL );
1160 return;
1161 }
1162
1163 if (db -> databaseInfo && db -> databaseInfo [0] == '@')
1164 info_entry_name = db -> databaseInfo + 1;
1165
1166 if (dict_search (
1167 list,
1168 info_entry_name,
1169 db, DICT_STRAT_EXACT, 0,
1170 NULL, NULL, NULL))
1171 {
1172 int i=1;
1173 int list_size = lst_length (list);
1174
1175 daemon_printf( "%d information for %s\n",
1176 CODE_DATABASE_INFO, argv[2] );
1177 daemon_mime();
1178
1179 if (db -> virtual_db){
1180 daemon_printf ("The virtual dictionary `%s' includes the following:\n\n",
1181 db -> databaseName);
1182 }
1183
1184 for (i=1; i <= list_size; ++i){
1185 dw = lst_nth_get( list, i );
1186
1187 daemon_printf ("============ %s ============\n",
1188 dw -> database -> databaseName);
1189
1190 buf = dict_data_obtain( dw -> database, dw );
1191
1192 #ifdef USE_PLUGIN
1193 call_dictdb_free (DictConfig->dbl);
1194 #endif
1195
1196 if (buf)
1197 daemon_text (buf, 0);
1198 }
1199
1200 daemon_text ("\n", 1);
1201 daemon_ok( CODE_OK, "ok", NULL );
1202
1203 dict_destroy_list (list);
1204
1205 return;
1206 } else {
1207 #ifdef USE_PLUGIN
1208 call_dictdb_free (DictConfig->dbl);
1209 #endif
1210
1211 dict_destroy_list( list );
1212 daemon_printf( "%d information for %s\n",
1213 CODE_DATABASE_INFO, argv[2] );
1214 daemon_mime();
1215 daemon_text( "No information available\n" , 1);
1216 daemon_ok( CODE_OK, "ok", NULL );
1217 return;
1218 }
1219 }
1220
1221 dict_destroy_list( list );
1222 daemon_printf( "%d invalid database, use SHOW DB for list\n",
1223 CODE_INVALID_DB );
1224 }
1225
daemon_get_max_dbname_length()1226 static int daemon_get_max_dbname_length ()
1227 {
1228 size_t max_len = 0;
1229 size_t curr_len = 0;
1230
1231 const dictDatabase *db;
1232
1233 lst_Position databasePosition = first_database_pos ();
1234
1235 while (NULL != (db = next_database (&databasePosition, "*"))){
1236 assert (!db -> invisible);
1237
1238 if (db -> databaseName){
1239 curr_len = strlen (db -> databaseName);
1240
1241 if (curr_len > max_len){
1242 max_len = curr_len;
1243 }
1244 }
1245 }
1246
1247 return (int) max_len;
1248 }
1249
daemon_show_server(const char * cmdline,int argc,const char ** argv)1250 static void daemon_show_server (
1251 const char *cmdline,
1252 int argc, const char **argv)
1253 {
1254 FILE *str;
1255 char buffer[1024];
1256 const dictDatabase *db;
1257 double uptime;
1258
1259 int headwords;
1260
1261 int index_size;
1262 char index_size_uom;
1263
1264 int data_size;
1265 char data_size_uom;
1266 int data_length;
1267 char data_length_uom;
1268
1269 int max_dbname_len;
1270
1271 lst_Position databasePosition = first_database_pos ();
1272
1273 daemon_printf( "%d server information\n", CODE_SERVER_INFO );
1274 daemon_mime();
1275
1276 /* banner: dictd and OS */
1277 if (!site_info_no_banner){
1278 daemon_printf( "%s\n", dict_get_banner(0) );
1279 }
1280
1281 /* uptime and forks */
1282 if (!site_info_no_uptime && !inetd){
1283 tim_stop("dictd");
1284 uptime = tim_get_real("dictd");
1285
1286 daemon_printf (
1287 "On %s: up %s, %d fork%s (%0.1f/hour)\n",
1288 net_hostname(),
1289 dict_format_time( uptime ),
1290 _dict_forks,
1291 _dict_forks > 1 ? "s" : "",
1292 (_dict_forks/uptime)*3600.0 );
1293
1294 daemon_printf ("\n");
1295 }
1296
1297 if (!site_info_no_dblist && count_databases()) {
1298 daemon_printf( "Database Headwords Index Data Uncompressed\n" );
1299
1300 databasePosition = first_database_pos ();
1301
1302 while (db = next_database (&databasePosition, "*"),
1303 db != NULL)
1304 {
1305 headwords = (db->index ? db->index->headwords : 0);
1306
1307 index_size = 0;
1308 index_size_uom = 'k';
1309
1310 data_size = 0;
1311 data_size_uom = 'k';
1312 data_length = 0;
1313 data_length_uom= 'k';
1314
1315 max_dbname_len = 0;
1316
1317 assert (!db -> invisible);
1318
1319 if (db->index){
1320 index_size = db->index->size/1024 > 10240 ?
1321 db->index->size/1024/1024 : db->index->size/1024;
1322 index_size_uom = db->index->size/1024 > 10240 ? 'M' : 'k';
1323 }
1324
1325 if (db->data){
1326 data_size = db->data->size/1024 > 10240 ?
1327 db->data->size/1024/1024 : db->data->size/1024;
1328 data_size_uom = db->data->size/1024 > 10240 ? 'M' : 'k';
1329
1330 data_length = db->data->length/1024 > 10240 ?
1331 db->data->length/1024/1024 : db->data->length/1024;
1332 data_length_uom = db->data->length/1024 > 10240 ? 'M' : 'k';
1333 }
1334
1335 max_dbname_len = daemon_get_max_dbname_length ();
1336
1337 daemon_printf(
1338 "%-*.*s %10i %10i %cB %10i %cB %10i %cB\n",
1339 max_dbname_len,
1340 max_dbname_len,
1341
1342 db->databaseName,
1343 headwords,
1344
1345 index_size,
1346 index_size_uom,
1347
1348 data_size,
1349 data_size_uom,
1350
1351 data_length,
1352 data_length_uom);
1353 }
1354
1355 daemon_printf ("\n");
1356 }
1357
1358 if (site_info && (str = fopen( site_info, "r" ))) {
1359 while ((fgets( buffer, 1000, str ))) daemon_printf( "%s", buffer );
1360 fclose( str );
1361 }
1362 daemon_printf( ".\n" );
1363 daemon_ok( CODE_OK, "ok", NULL );
1364 }
1365
daemon_show(const char * cmdline,int argc,const char ** argv)1366 static void daemon_show( const char *cmdline, int argc, const char **argv )
1367 {
1368 daemon_printf( "%d syntax error, illegal parameters\n",
1369 CODE_ILLEGAL_PARAM );
1370 }
1371
daemon_option_mime(const char * cmdline,int argc,const char ** argv)1372 static void daemon_option_mime( const char *cmdline, int argc, const char **argv )
1373 {
1374 ++daemonMime;
1375 daemon_ok( CODE_OK, "ok - using MIME headers", NULL );
1376 }
1377
daemon_option(const char * cmdline,int argc,const char ** argv)1378 static void daemon_option( const char *cmdline, int argc, const char **argv )
1379 {
1380 daemon_printf( "%d syntax error, illegal parameters\n",
1381 CODE_ILLEGAL_PARAM );
1382 }
1383
daemon_client(const char * cmdline,int argc,const char ** argv)1384 static void daemon_client( const char *cmdline, int argc, const char **argv )
1385 {
1386 const char *pt = strchr( cmdline, ' ' );
1387
1388 if (pt)
1389 daemon_log( DICT_LOG_CLIENT, "%.200s\n", pt + 1 );
1390 else
1391 daemon_log( DICT_LOG_CLIENT, "%.200s\n", cmdline );
1392 daemon_ok( CODE_OK, "ok", NULL );
1393 }
1394
daemon_auth(const char * cmdline,int argc,const char ** argv)1395 static void daemon_auth( const char *cmdline, int argc, const char **argv )
1396 {
1397 char *buf;
1398 hsh_HashTable h = DictConfig->usl;
1399 const char *secret;
1400 struct MD5Context ctx;
1401 unsigned char digest[16];
1402 char hex[33];
1403 int i;
1404 int buf_size;
1405
1406 if (argc != 3)
1407 daemon_printf( "%d syntax error, illegal parameters\n",
1408 CODE_ILLEGAL_PARAM );
1409 if (!h || !(secret = hsh_retrieve(h, argv[1]))) {
1410 daemon_log( DICT_LOG_AUTH, "%s@%s/%s denied: invalid username\n",
1411 argv[1], daemonHostname, daemonIP );
1412 daemon_printf( "%d auth denied\n", CODE_AUTH_DENIED );
1413 return;
1414 }
1415
1416 buf_size = strlen(daemonStamp) + strlen(secret) + 10;
1417 buf = alloca(buf_size);
1418 snprintf( buf, buf_size, "%s%s", daemonStamp, secret );
1419
1420 MD5Init(&ctx);
1421 MD5Update(&ctx, (const unsigned char *) buf, strlen(buf));
1422 MD5Final(digest, &ctx);
1423
1424 for (i = 0; i < 16; i++)
1425 snprintf( hex+2*i, 3, "%02x", digest[i] );
1426
1427 hex[32] = '\0';
1428
1429 PRINTF(DBG_AUTH,("Got %s expected %s\n", argv[2], hex ));
1430
1431 if (strcmp(hex,argv[2])) {
1432 daemon_log( DICT_LOG_AUTH, "%s@%s/%s denied: hash mismatch\n",
1433 argv[1], daemonHostname, daemonIP );
1434 daemon_printf( "%d auth denied\n", CODE_AUTH_DENIED );
1435 } else {
1436 daemon_printf( "%d authenticated\n", CODE_AUTH_OK );
1437 daemon_check_auth( argv[1] );
1438 }
1439 }
1440
daemon_status(const char * cmdline,int argc,const char ** argv)1441 static void daemon_status( const char *cmdline, int argc, const char **argv )
1442 {
1443 daemon_ok( CODE_STATUS, "status", "t" );
1444 }
1445
daemon_help(const char * cmdline,int argc,const char ** argv)1446 static void daemon_help( const char *cmdline, int argc, const char **argv )
1447 {
1448 daemon_printf( "%d help text follows\n", CODE_HELP );
1449 daemon_mime();
1450 daemon_text(
1451 "DEFINE database word -- look up word in database\n"
1452 "MATCH database strategy word -- match word in database using strategy\n"
1453 "SHOW DB -- list all accessible databases\n"
1454 "SHOW DATABASES -- list all accessible databases\n"
1455 "SHOW STRAT -- list available matching strategies\n"
1456 "SHOW STRATEGIES -- list available matching strategies\n"
1457 "SHOW INFO database -- provide information about the database\n"
1458 "SHOW SERVER -- provide site-specific information\n"
1459 "OPTION MIME -- use MIME headers\n"
1460 "CLIENT info -- identify client to server\n"
1461 "AUTH user string -- provide authentication information\n"
1462 "STATUS -- display timing information\n"
1463 "HELP -- display this help information\n"
1464 "QUIT -- terminate connection\n\n"
1465 "The following commands are unofficial server extensions for debugging\n"
1466 "only. You may find them useful if you are using telnet as a client.\n"
1467 "If you are writing a client, you MUST NOT use these commands, since\n"
1468 "they won't be supported on any other server!\n\n"
1469 "D word -- DEFINE * word\n"
1470 "D database word -- DEFINE database word\n"
1471 "M word -- MATCH * . word\n"
1472 "M strategy word -- MATCH * strategy word\n"
1473 "M database strategy word -- MATCH database strategy word\n"
1474 "S -- STATUS\n"
1475 "H -- HELP\n"
1476 "Q -- QUIT\n"
1477 , 1);
1478 daemon_ok( CODE_OK, "ok", NULL );
1479 }
1480
daemon_quit(const char * cmdline,int argc,const char ** argv)1481 static void daemon_quit( const char *cmdline, int argc, const char **argv )
1482 {
1483 daemon_ok( CODE_GOODBYE, "bye", "t" );
1484 daemon_terminate( 0, "quit" );
1485 }
1486
1487 /* The whole sub should be moved here, but I want to keep the diff small. */
1488 int _handleconn (int error);
1489
dict_inetd(int error)1490 int dict_inetd (int error)
1491 {
1492 if (setjmp(env)) return 0;
1493
1494 daemonPort = -1;
1495 daemonIP = "inetd";
1496
1497 daemonHostname = daemonIP;
1498
1499 daemonS_in = 0;
1500 daemonS_out = 1;
1501
1502 return _handleconn (error);
1503 }
1504
dict_daemon(int s,struct sockaddr_storage * csin,int error)1505 int dict_daemon( int s, struct sockaddr_storage *csin, int error )
1506 {
1507 struct hostent *h;
1508 int err = 0;
1509 socklen_t csin_len;
1510 static char hostname[NI_MAXHOST], service[NI_MAXSERV];
1511
1512 if (setjmp(env)) return 0;
1513
1514 // We calculate csin_len for NetBSD-9.0 and Solaris-10/11 where
1515 // getnameinfo(*,sizeof(sockaddr_storage),*,*,*,*,*) does not work.
1516 if (((struct sockaddr *)csin)->sa_family == AF_INET)
1517 csin_len = sizeof(struct sockaddr_in);
1518 else
1519 csin_len = sizeof(struct sockaddr_in6);
1520
1521 //
1522 err = getnameinfo ((const struct sockaddr *)csin, csin_len,
1523 hostname, NI_MAXHOST, service, NI_MAXSERV,
1524 NI_NUMERICSERV);
1525 if (err){
1526 log_error(__func__, ":E: getnameinfo(3) failed: %s\n", gai_strerror(err));
1527 exit(1);
1528 }
1529
1530 daemonPort = strtol (service, NULL, 10);
1531 daemonIP = str_find (inet_ntopW ((struct sockaddr *)csin));
1532 daemonHostname = str_find (hostname);
1533 daemonS_in = daemonS_out = s;
1534
1535 return _handleconn(error);
1536 }
1537
_handleconn(int error)1538 int _handleconn (int error) {
1539 int query_count = 0;
1540 char buf[4096];
1541 int count;
1542 arg_List cmdline;
1543 int argc;
1544 char **argv;
1545 void (*command)(const char *, int, const char **);
1546
1547 _dict_defines = 0;
1548 _dict_matches = 0;
1549 _dict_comparisons = 0;
1550
1551 tim_start( "t" );
1552 daemon_log( DICT_LOG_TRACE, "connected\n" );
1553 daemon_log( DICT_LOG_CONNECT, "%s/%s connected on port %d\n",
1554 daemonHostname, daemonIP, daemonPort );
1555 dict_setproctitle( "dictd: %s connected", daemonHostname );
1556
1557 if (error) {
1558 daemon_printf( "%d server temporarily unavailable\n",
1559 CODE_TEMPORARILY_UNAVAILABLE );
1560 daemon_terminate( 0, "temporarily unavailable" );
1561 }
1562
1563 if (daemon_check_auth( NULL )) {
1564 daemon_log( DICT_LOG_AUTH, "%s/%s denied: ip/hostname rules\n",
1565 daemonHostname, daemonIP );
1566 daemon_printf( "%d access denied\n", CODE_ACCESS_DENIED );
1567 daemon_terminate( 0, "access denied" );
1568 }
1569
1570 daemon_banner();
1571
1572 if (!_dict_daemon_limit_time)
1573 alarm (client_delay);
1574
1575 while (count = daemon_read( buf, 4000 ), count >= 0) {
1576 ++query_count;
1577
1578 if (_dict_daemon_limit_queries &&
1579 query_count >= _dict_daemon_limit_queries)
1580 {
1581 daemon_terminate (0, "query limit");
1582 }
1583
1584 if (stdin2stdout_mode){
1585 daemon_printf( "# %s\n", buf );
1586 }
1587
1588 if (!_dict_daemon_limit_time)
1589 alarm(0);
1590
1591 tim_start( "c" );
1592 if (!count) {
1593 #if 0
1594 daemon_ok( CODE_OK, "ok", "c" );
1595 #endif
1596 continue;
1597 }
1598
1599 daemon_log( DICT_LOG_COMMAND, "%.80s\n", buf );
1600 cmdline = arg_argify(buf,0);
1601 arg_get_vector( cmdline, &argc, &argv );
1602 if ((command = lookup_command (argc, (const char **) argv))) {
1603 command(buf, argc, (const char **) argv);
1604 } else {
1605 daemon_printf( "%d unknown command\n", CODE_SYNTAX_ERROR );
1606 }
1607 arg_destroy(cmdline);
1608
1609 if (!_dict_daemon_limit_time)
1610 alarm (client_delay);
1611 }
1612 #if 0
1613 printf( "%d %d\n", count, errno );
1614 #endif
1615 daemon_terminate( 0, "close" );
1616 return 0;
1617 }
1618