1 /*
2  * ImapProxy - a caching IMAP proxy daemon
3  * Copyright (C) 2002 Steven Van Acker
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  */
20 
21 
22 #include <string.h>
23 #include <strings.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 
32 #include <database.h>
33 #include <output.h>
34 #include <splitstring.h>
35 #include <processing_child.h>
36 #include <network.h>
37 #include <configfile.h>
38 
39 
40 extern int Globaltime;
41 
42 DB_record *DB_start = NULL;
43 DB_record *DB_end = NULL;
44 
45 /* add a record to the linked list.
46  * The record is copied.
47  * DB_start and DB_end are updated.
48  * the prev and next field in the new record are changed
49  * the message structured are presumed empty
50  */
db_add(DB_record * rec)51 int db_add(DB_record *rec)
52 {
53     DB_record *p;
54 
55     if(!(p = (DB_record *)malloc(sizeof(DB_record))))
56     {
57 	debug("db_add(): Could not malloc.\n");
58 	return -1;
59     }
60 
61     memcpy(p,rec,sizeof(DB_record));
62 
63     if(DB_end) DB_end->next = p;
64     p->prev = DB_end;
65     p->next = NULL;
66 
67     if(!DB_end) DB_start = p;
68     DB_end = p;
69 
70     return 0;
71 }
72 
73 /* this function cleans up a record
74  * it removes everything, except the parts necessary for keeping alive the connection
75  *
76  * what it doesn't remove :
77  * 	username
78  * 	password
79  * 	server socket
80  * 	status
81  * 	next and prev pointers
82  */
db_cleanup(DB_record * rec)83 int db_cleanup(DB_record *rec)
84 {
85     /* keep : 	username/password
86      * 		server socket
87      * 		status
88      * 		next and prev pointers
89      */
90 
91     /* close client socket */
92     close(rec->clientsocket);
93     rec->clientsocket = -1;
94 
95     /* remove pid */
96     rec->pid = -1;
97 
98     /* authenticate tags */
99     if(rec->clientauthtag)
100     {
101 	free(rec->clientauthtag);
102 	rec->clientauthtag = NULL;
103     }
104 
105     if(rec->proxyauthtag)
106     {
107 	free(rec->proxyauthtag);
108 	rec->proxyauthtag = NULL;
109     }
110 
111     /* remove messages */
112     db_delete_client_message(rec);
113     db_delete_server_message(rec);
114 
115     /* close pipe */
116     close(rec->ipcfd[0]);
117     close(rec->ipcfd[1]);
118 
119     rec->ipcfd[0] = -1;
120     rec->ipcfd[1] = -1;
121 
122     rec->serverlastnoop = Globaltime;
123     rec->clientidlesince = Globaltime;
124     rec->serveridlesince = Globaltime;
125 
126     rec->clientlocaladdress.s_addr = 0;
127     rec->clientlocalport = 0;
128 
129     return 0;
130 }
131 
132 /* remove a record from the linked list
133  * the record is freed
134  * all resources are freed
135  * DB_start and DB_end are updated
136  */
db_del(DB_record * rec)137 int db_del(DB_record *rec)
138 {
139     DB_record *p,*n;
140 
141     p = rec->prev;
142     n = rec->next;
143 
144     if(p) p->next = n;
145     else DB_start = n;
146     if(n) n->prev = p;
147     else DB_end = p;
148 
149 
150     db_cleanup(rec);
151 
152     /* don't leave password lying around */
153     memset(rec->password,0,DB_STRING_LENGTH);
154     close(rec->serversocket);
155     free(rec);
156 
157     return 0;
158 }
159 
160 /* initialize a record
161  */
db_init_record(DB_record * rec)162 int db_init_record(DB_record *rec)
163 {
164     memset(rec,0,sizeof(DB_record));
165 
166     db_set_server_connection_state(rec,DB_STATE_SERVER_NOT_CONNECTED);
167     db_set_client_state(rec,DB_STATE_CLIENT_NOT_AUTHENTICATED);
168     db_set_server_state(rec,DB_STATE_SERVER_NONE);
169     db_set_proxy_state(rec,DB_STATE_PROXY_NONE);
170     db_set_misc_state(rec,DB_STATE_MISC_NONE);
171     db_set_record_state(rec,DB_STATE_RECORD_NONE);
172     db_set_capability_state(rec,DB_STATE_CAPABILITY_NONE);
173 
174     rec->clientsocket = -1;
175     rec->serversocket = -1;
176     rec->ipcfd[0] = -1;
177     rec->ipcfd[1] = -1;
178     rec->pid = -1;
179 
180     /* set these to 1, so we know there is no command in progress */
181     rec->clientmessage.completed = 1;
182     rec->servermessage.completed = 1;
183 
184     /* no messages yet, so they are unchecked. */
185     rec->clientmessage.status = DB_MESSAGE_UNCHECKED;
186     rec->servermessage.status = DB_MESSAGE_UNCHECKED;
187 
188     rec->clientidlesince = Globaltime;
189     rec->serverlastnoop = Globaltime;
190     rec->serveridlesince = Globaltime;
191 
192     rec->clientlocaladdress.s_addr = 0;
193     rec->clientlocalport = 0;
194     rec->proxylocalport = 0;
195 
196     rec->reuse = 0;
197 
198     return 0;
199 }
200 
201 #define INDEX_FOR_SERVER	0
202 #define INDEX_FOR_CLIENT	1
203 
204 /* when in process mode or unchecked mode :
205  * 	this function appends a string to the current line in the message (client or server)
206  * when in passthrough mode :
207  * 	this function sends the received data to the destination, without appending it
208  *
209  * the function checks if the command is LOGOUT or not
210  * if it is LOGOUT, the message is switched to process mode, and the message is interpreted
211  * otherwise, we just send away the message
212  *
213  * ALL OF THIS IS ONLY DONE IN THE CHILD !!!
214  * when in the parent, the message is just processed. (since we only do authentication there, and don't expect big messages)
215  *
216  */
217 
db_append_to_message(DB_record * rec,char * buf,int what)218 int db_append_to_message(DB_record *rec,char *buf,int what)
219 {
220     struct message_t *currmessage = NULL;
221     int newsize = 0;
222     char *currbuf = NULL;
223     char *newbuf = NULL;
224     int outfd = -1,i = 0;
225     Split_string ss;
226 
227     /* decide which message we want to append to */
228     if(what == INDEX_FOR_SERVER)
229     {
230 	currmessage = &(rec->servermessage);
231 	outfd = rec->clientsocket;
232     }
233     else
234     {
235 	currmessage = &(rec->clientmessage);
236 	outfd = rec->serversocket;
237     }
238 
239     /* message is not complete */
240     currmessage->completed = 0;
241 
242     /* only care about the state of the message if we are in a forked child */
243     if(!forkedchild)
244 	goto db_process;
245 
246     /* what mode are we in ? */
247     switch(currmessage->status)
248     {
249 	case DB_MESSAGE_UNCHECKED:
250 
251 	    //debug("db_append_to_buffer(%d): We are in unchecked mode ! (%s)\n",what,buf);
252 
253 	    init_split_string(&ss);
254 
255 	    if(!currmessage->count)
256 	    {
257 		make_split_string_strip_crlf(buf,&ss," ");
258 	    }
259 	    else
260 	    {
261 		/* something is in the first slot of the message.
262 		 * check if it contains our command
263 		 * if it doesn't don't check the buffer !
264 		 * just let the buffer be appended to the message, and check the first line
265 		 * on the next append
266 		 */
267 		make_split_string(currmessage->lines[0],&ss," ");
268 	    }
269 
270 	    if(split_string_count_parts(&ss) > 1)
271 	    {
272 		if(!strcasecmp(split_string_get(&ss,1),"LOGOUT" ))
273 		{
274 		    debug("db_append_to_buffer(%d): LOGOUT received !!! going to process mode\n",what);
275 		    currmessage->status = DB_MESSAGE_PROCESS;
276 		}
277 		else
278 		{
279 		    currmessage->status = DB_MESSAGE_PASSTHROUGH;
280 
281 		    /* if any previous lines, send them */
282 		    /* there should only be 1 (one) line, otherwise there is a problem */
283 		    for(i = 0;i < currmessage->count;i++)
284 		    {
285 			socket_printf(outfd,"%s",currmessage->lines[i]);
286 		    }
287 
288 		    if(currmessage->count > 1)
289 		    {
290 			debug("db_append_to_buffer(%d): There is more than one previous line ! this cannot happen ?\n");
291 		    }
292 
293 		    /* send current buffer */
294 		    socket_printf(outfd,"%s",buf);
295 		    /* we're in passthrough mode, and everything sent so far, was passed on
296 		     * we can go home now
297 		     */
298 
299 		    delete_split_string(&ss);
300 		    return 0;
301 		}
302 	    }
303 	    else
304 	    {
305 		/* message is not complete so we'll check again in the next append ! */
306 	    }
307 
308 	    delete_split_string(&ss);
309 
310 	    break;
311 	case DB_MESSAGE_PASSTHROUGH:
312 	    //debug("db_append_to_buffer(%d): We are in passthrough mode !\n",what);
313 	    /* send current buffer */
314 	    socket_printf(outfd,"%s",buf);
315 	    return 0;
316 	    break;
317 	case DB_MESSAGE_PROCESS:
318 	    //debug("db_append_to_buffer(%d): We are in process mode !\n",what);
319 	    break;
320     }
321 
322 db_process:
323     if(!currmessage->count)
324     {
325 	if(db_create_new_line_in_message(rec,what) < 0)
326 	{
327 	    debug("db_append_to_buffer(): db_create_new_line_in_message() returned error !\n");
328 	    return -1;
329 	}
330     }
331 
332     currbuf = currmessage->lines[currmessage->count - 1];
333 
334     /* calculate new length */
335     newsize = strlen(buf);
336     if(currbuf) newsize += strlen(currbuf);
337     newsize++;	// \0
338 
339     /* allocate space */
340     if(!(newbuf = (char *)calloc(1,newsize)))
341     {
342 	debug("db_append_to_buffer(): Out of memory.\n");
343 	return -1;
344     }
345 
346     /* copy and append */
347     if(currbuf) strcpy(newbuf,currbuf);
348     strcat(newbuf,buf);
349 
350     /* free */
351 
352     if(currbuf) free(currbuf);
353 
354     /* assign */
355     currmessage->lines[currmessage->count - 1] = newbuf;
356 
357     return 0;
358 }
359 
360 /* create a new line in the message = allocate an extra pointer for it */
db_create_new_line_in_message(DB_record * rec,int what)361 int db_create_new_line_in_message(DB_record *rec,int what)
362 {
363     struct message_t *currmessage = NULL;
364 
365     if(what == INDEX_FOR_SERVER)
366 	currmessage = &(rec->servermessage);
367     else
368 	currmessage = &(rec->clientmessage);
369 
370     currmessage->completed = 0;
371     currmessage->count++;
372 
373     if(!(currmessage->lines = (char **)realloc(currmessage->lines, sizeof(char *) * currmessage->count)))
374     {
375 	debug("db_create_new_line_in_message(): Out of memory.\n");
376 	return -1;
377     }
378 
379     currmessage->lines[currmessage->count - 1] = NULL;
380 
381     return 0;
382 }
383 
384 /* delete a message and release the allocated space */
db_delete_message(DB_record * rec,int what)385 int db_delete_message(DB_record *rec, int what)
386 {
387     struct message_t *x;
388     int i;
389 
390     if(what == INDEX_FOR_SERVER)
391 	x = &(rec->servermessage);
392     else
393 	x = &(rec->clientmessage);
394 
395 
396     /* clear the messages, if any */
397     if(x->count != 0)
398     {
399 	for(i = 0;i < x->count; i++)
400 	    free(x->lines[i]);
401 
402 	free(x->lines);
403     }
404 
405     x->count = 0;
406     x->completed = 1;
407     x->lines = NULL;
408     x->status = DB_MESSAGE_UNCHECKED;
409 
410     return 0;
411 }
412 
db_append_to_client_message(DB_record * rec,char * buf)413 int db_append_to_client_message(DB_record *rec,char *buf)
414 {
415     return db_append_to_message(rec,buf,INDEX_FOR_CLIENT);
416 }
417 
db_append_to_server_message(DB_record * rec,char * buf)418 int db_append_to_server_message(DB_record *rec,char *buf)
419 {
420     return db_append_to_message(rec,buf,INDEX_FOR_SERVER);
421 }
422 
db_delete_client_message(DB_record * rec)423 int db_delete_client_message(DB_record *rec)
424 {
425     return db_delete_message(rec,INDEX_FOR_CLIENT);
426 }
427 
db_delete_server_message(DB_record * rec)428 int db_delete_server_message(DB_record *rec)
429 {
430     return db_delete_message(rec,INDEX_FOR_SERVER);
431 }
432 
db_create_new_line_in_client_message(DB_record * rec)433 int db_create_new_line_in_client_message(DB_record *rec)
434 {
435     return db_create_new_line_in_message(rec,INDEX_FOR_CLIENT);
436 }
437 
db_create_new_line_in_server_message(DB_record * rec)438 int db_create_new_line_in_server_message(DB_record *rec)
439 {
440     return db_create_new_line_in_message(rec,INDEX_FOR_SERVER);
441 }
442 
443 /* return the i'th line of a message
444  * or NULL if i is out of range
445  */
db_get_message(DB_record * rec,int i,int what)446 char *db_get_message(DB_record *rec, int i,int what)
447 {
448     struct message_t *currmessage = NULL;
449 
450     if(what == INDEX_FOR_SERVER)
451 	currmessage = &(rec->servermessage);
452     else
453 	currmessage = &(rec->clientmessage);
454 
455     if(i < 0 || i >= currmessage->count)
456 	return NULL;
457 
458     return currmessage->lines[i];
459 }
460 
db_get_server_message(DB_record * rec,int i)461 char *db_get_server_message(DB_record *rec,int i)
462 {
463     return db_get_message(rec,i,INDEX_FOR_SERVER);
464 }
465 
db_get_client_message(DB_record * rec,int i)466 char *db_get_client_message(DB_record *rec,int i)
467 {
468     return db_get_message(rec,i,INDEX_FOR_CLIENT);
469 }
470 
471 
472 /* return a specific field from the status field
473  * see the headers for more information
474  */
db_get_state(DB_record * p,int mask)475 int db_get_state(DB_record *p, int mask)
476 {
477     if(!(p->status & mask))
478 	debug("db_get_state(): state vs. mask mismatch ! %0.8p %0.8p\n",p->status,mask);
479 
480     return p->status & mask;
481 }
482 
483 /* set a specific field in the status field
484  */
db_set_state(DB_record * p,int s,int mask)485 void db_set_state(DB_record *p,int s,int mask)
486 {
487     if(!(mask & s))
488 	debug("db_set_state(): state vs. mask mismatch ! %0.8p %0.8p\n",s,mask);
489 
490     p->status = ((mask ^ 0xffffffff) & p->status) | s;
491 }
492 
db_get_server_connection_state(DB_record * p)493 int db_get_server_connection_state(DB_record *p)
494 {
495     return db_get_state(p,DB_STATE_SERVER_CONNECTION_MASK);
496 }
497 
db_set_server_connection_state(DB_record * p,int s)498 void db_set_server_connection_state(DB_record *p,int s)
499 {
500     db_set_state(p,s,DB_STATE_SERVER_CONNECTION_MASK);
501 }
502 
db_get_client_state(DB_record * p)503 int db_get_client_state(DB_record *p)
504 {
505     return db_get_state(p,DB_STATE_CLIENT_MASK);
506 }
507 
db_set_client_state(DB_record * p,int s)508 void db_set_client_state(DB_record *p,int s)
509 {
510     db_set_state(p,s,DB_STATE_CLIENT_MASK);
511 }
512 
db_get_server_state(DB_record * p)513 int db_get_server_state(DB_record *p)
514 {
515     return db_get_state(p,DB_STATE_SERVER_MASK);
516 }
517 
db_set_server_state(DB_record * p,int s)518 void db_set_server_state(DB_record *p,int s)
519 {
520     db_set_state(p,s,DB_STATE_SERVER_MASK);
521 }
522 
db_get_proxy_state(DB_record * p)523 int db_get_proxy_state(DB_record *p)
524 {
525     return db_get_state(p,DB_STATE_PROXY_MASK);
526 }
527 
db_set_proxy_state(DB_record * p,int s)528 void db_set_proxy_state(DB_record *p,int s)
529 {
530     db_set_state(p,s,DB_STATE_PROXY_MASK);
531 }
532 
db_get_misc_state(DB_record * p)533 int db_get_misc_state(DB_record *p)
534 {
535     return db_get_state(p,DB_STATE_MISC_MASK);
536 }
537 
db_set_misc_state(DB_record * p,int s)538 void db_set_misc_state(DB_record *p,int s)
539 {
540     db_set_state(p,s,DB_STATE_MISC_MASK);
541 }
542 
db_get_record_state(DB_record * p)543 int db_get_record_state(DB_record *p)
544 {
545     return db_get_state(p,DB_STATE_RECORD_MASK);
546 }
547 
db_set_record_state(DB_record * p,int s)548 void db_set_record_state(DB_record *p,int s)
549 {
550     db_set_state(p,s,DB_STATE_RECORD_MASK);
551 }
552 
db_get_capability_state(DB_record * p)553 int db_get_capability_state(DB_record *p)
554 {
555     return db_get_state(p,DB_STATE_CAPABILITY_MASK);
556 }
557 
db_set_capability_state(DB_record * p,int s)558 void db_set_capability_state(DB_record *p,int s)
559 {
560     db_set_state(p,s,DB_STATE_CAPABILITY_MASK);
561 }
562 
563 /* find the next free inactive record
564  * this record will be assigned to an authenticated temporary record
565  *
566  * it should :
567  * 	contain the same username
568  * 	contain the same password
569  * 	be INACTIVE
570  * 	not be in the middle of processing a message
571  * 	not be "me" (the temporary record)
572  */
db_find_record(DB_record * me,char * username,char * password)573 DB_record *db_find_record(DB_record *me,char *username,char *password)
574 {
575     DB_record *p = NULL;
576 
577     p = DB_start;
578 
579     while(p)
580     {
581 
582 	/* if username and password match and if the record is inactive, and not processing a server message,
583 	 * and if has need been reused too much, return it !*/
584 	if(p != me && db_get_record_state(p) == DB_STATE_RECORD_INACTIVE && p->servermessage.completed &&
585 		(p->reuse < config_max_reuse || config_max_reuse == 0) &&
586 		!strcmp(p->username,username) && !strcmp(p->password,password))
587 	{
588 	    return p;
589 	}
590 
591 	p = p->next;
592     }
593 
594     return NULL;
595 }
596 
597 
db_get_state_string(int state)598 char *db_get_state_string(int state)
599 {
600     int i,max;
601     static char ret[80];
602 
603     int intvalues[] = {
604 	DB_STATE_SERVER_CONNECTION_MASK,
605 	DB_STATE_SERVER_NOT_CONNECTED,
606 	DB_STATE_SERVER_CONNECTION_STARTED,
607 	DB_STATE_SERVER_CONNECTED,
608         DB_STATE_CLIENT_MASK,
609         DB_STATE_CLIENT_NOT_AUTHENTICATED,
610         DB_STATE_CLIENT_SENT_AUTHENTICATE_COMMAND,
611         DB_STATE_CLIENT_SENT_LOGIN_COMMAND,
612         DB_STATE_CLIENT_SENT_USERNAME,
613         DB_STATE_CLIENT_SENT_PASSWORD,
614         DB_STATE_CLIENT_AUTHENTICATED,
615         DB_STATE_CLIENT_SENT_LOGOUT_COMMAND,
616         DB_STATE_SERVER_MASK,
617         DB_STATE_SERVER_NONE,
618         DB_STATE_SERVER_SENT_GREETING,
619         DB_STATE_SERVER_SENT_USERNAME_REPLY,
620         DB_STATE_SERVER_SENT_PASSWORD_REPLY,
621         DB_STATE_SERVER_SENT_LOGIN_OK,
622         DB_STATE_SERVER_SENT_LOGIN_FAILED,
623         DB_STATE_PROXY_MASK,
624         DB_STATE_PROXY_NONE,
625         DB_STATE_PROXY_SENT_GREETING_TO_CLIENT,
626         DB_STATE_PROXY_SENT_USERNAME_REPLY_TO_CLIENT,
627         DB_STATE_PROXY_SENT_PASSWORD_REPLY_TO_CLIENT,
628         DB_STATE_PROXY_SENT_AUTHENTICATE_COMMAND_TO_SERVER,
629         DB_STATE_PROXY_SENT_LOGIN_COMMAND_TO_SERVER,
630         DB_STATE_PROXY_SENT_USERNAME_TO_SERVER,
631         DB_STATE_PROXY_SENT_PASSWORD_TO_SERVER,
632         DB_STATE_PROXY_SENT_LOGIN_OK_TO_CLIENT,
633         DB_STATE_PROXY_SENT_LOGIN_FAILED_TO_CLIENT,
634         DB_STATE_MISC_MASK,
635 	DB_STATE_MISC_NONE,
636         DB_STATE_MISC_REMOVE_RECORD,
637 	DB_STATE_RECORD_MASK,
638 	DB_STATE_RECORD_NONE,
639 	DB_STATE_RECORD_FORKED_CHILD
640     };
641 
642     char *values[] = {
643         "DB_STATE_SERVER_CONNECTION_MASK",
644         "DB_STATE_SERVER_NOT_CONNECTED",
645         "DB_STATE_SERVER_CONNECTION_STARTED",
646         "DB_STATE_SERVER_CONNECTED",
647         "DB_STATE_CLIENT_MASK",
648         "DB_STATE_CLIENT_NOT_AUTHENTICATED",
649         "DB_STATE_CLIENT_SENT_AUTHENTICATE_COMMAND",
650         "DB_STATE_CLIENT_SENT_LOGIN_COMMAND",
651         "DB_STATE_CLIENT_SENT_USERNAME",
652         "DB_STATE_CLIENT_SENT_PASSWORD",
653         "DB_STATE_CLIENT_AUTHENTICATED",
654         "DB_STATE_CLIENT_SENT_LOGOUT_COMMAND",
655         "DB_STATE_SERVER_MASK",
656         "DB_STATE_SERVER_NONE",
657         "DB_STATE_SERVER_SENT_GREETING",
658         "DB_STATE_SERVER_SENT_USERNAME_REPLY",
659         "DB_STATE_SERVER_SENT_PASSWORD_REPLY",
660         "DB_STATE_SERVER_SENT_LOGIN_OK",
661         "DB_STATE_SERVER_SENT_LOGIN_FAILED",
662         "DB_STATE_PROXY_MASK",
663         "DB_STATE_PROXY_NONE",
664         "DB_STATE_PROXY_SENT_GREETING_TO_CLIENT",
665         "DB_STATE_PROXY_SENT_USERNAME_REPLY_TO_CLIENT",
666         "DB_STATE_PROXY_SENT_PASSWORD_REPLY_TO_CLIENT",
667         "DB_STATE_PROXY_SENT_AUTHENTICATE_COMMAND_TO_SERVER",
668         "DB_STATE_PROXY_SENT_LOGIN_COMMAND_TO_SERVER",
669         "DB_STATE_PROXY_SENT_USERNAME_TO_SERVER",
670         "DB_STATE_PROXY_SENT_PASSWORD_TO_SERVER",
671         "DB_STATE_PROXY_SENT_LOGIN_OK_TO_CLIENT",
672         "DB_STATE_PROXY_SENT_LOGIN_FAILED_TO_CLIENT",
673         "DB_STATE_MISC_MASK",
674 	"DB_STATE_MISC_NONE",
675         "DB_STATE_MISC_REMOVE_RECORD",
676 	"DB_STATE_RECORD_MASK",
677 	"DB_STATE_RECORD_NONE",
678 	"DB_STATE_MISC_FORKED_CHILD"
679     };
680 
681     max = sizeof(intvalues) / sizeof(int);
682 
683     for(i = 0;i < max; i++)
684 	if(state == intvalues[i])
685 	    return values[i];
686 
687     snprintf(ret,sizeof(ret),"UNKNOWN_STATUS_%s%#0x",state?"":"0x",state);
688     return ret;
689 }
690 
db_print_state(DB_record * p)691 void db_print_state(DB_record *p)
692 {
693     debug("Server connection state: %s\n",db_get_state_string(db_get_server_connection_state(p)));
694     debug("Client state: %s\n",db_get_state_string(db_get_client_state(p)));
695     debug("Server state: %s\n",db_get_state_string(db_get_server_state(p)));
696     debug("Proxy state: %s\n",db_get_state_string(db_get_proxy_state(p)));
697     debug("Misc state: %s\n",db_get_state_string(db_get_misc_state(p)));
698 }
699 
db_log_stats()700 void db_log_stats()
701 {
702     DB_record *p = NULL;
703     int active = 0,inactive = 0, temporary = 0, other = 0,total = 0;
704     p = DB_start;
705 
706     while(p)
707     {
708 	switch(db_get_record_state(p))
709 	{
710 	    case DB_STATE_RECORD_INACTIVE:
711 		inactive++;
712 		break;
713 	    case DB_STATE_RECORD_ACTIVE:
714 		active++;
715 		break;
716 	    case DB_STATE_RECORD_TEMPORARY:
717 		temporary++;
718 		break;
719 	    default:
720 		other++;
721 		break;
722 	}
723 
724 	total++;
725 
726 	p = p->next;
727     }
728 
729     log(LOG_INFO,"Status: %d temporary, %d active, %d inactive, %d other, %d total.\n",temporary,active,inactive,other,total);
730 }
731 
732 
db_get_record_info(DB_record * p)733 char *db_get_record_info(DB_record *p)
734 {
735     static char buffer[64];
736 
737     snprintf(buffer,sizeof(buffer),"[%s:%d (%d)]\n",inet_ntoa(p->clientlocaladdress),p->clientlocalport,p->proxylocalport);
738 
739     return buffer;
740 }
741