1 /*
2 * binkleyforce -- unix FTN mailer project
3 *
4 * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * $Id: prot_yoohoo.c,v 1.1.1.1 2004/09/09 09:52:39 kstepanenkov Exp $
12 */
13
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18 #include "session.h"
19 #include "prot_yoohoo.h"
20
21 typedef enum {
22 YS_Init,
23 YS_SendHello,
24 YS_WaitResp,
25 YS_Done,
26 YS_Error
27 } YooHoo_SendState;
28
29 typedef enum {
30 YR_Init,
31 YR_SendENQ,
32 YR_WaitHeader,
33 YR_TossJunk,
34 YR_RecvHello,
35 YR_SendNAK,
36 YR_SendACK,
37 YR_Done,
38 YR_Error
39 } YooHoo_RecvState;
40
yoohoo_putword(char * buf,int val)41 static char *yoohoo_putword(char *buf, int val)
42 {
43 buf[0] = ( ((unsigned int) val) ) & 0xff;
44 buf[1] = ( ((unsigned int) val) >> 8 ) & 0xff;
45
46 return buf + 2;
47 }
48
yoohoo_getword(const char * buf)49 static int yoohoo_getword(const char *buf)
50 {
51 return ( (unsigned int) ((unsigned char) buf[0]) )
52 | ( (unsigned int) ((unsigned char) buf[1]) << 8 );
53 }
54
55 /*****************************************************************************
56 * Make ``hello'' packet from the yoohoo sysinfo structure and put
57 * it to the buffer
58 *
59 * Arguments:
60 * buffer pointer to the destination buffer (must be at least
61 * 128 bytes)
62 * hello structure with the YooHoo system information
63 *
64 * Return value:
65 * None
66 */
yoohoo_put_hello(char * buffer,s_yoohoo_sysinfo * hello)67 static void yoohoo_put_hello(char *buffer, s_yoohoo_sysinfo *hello)
68 {
69 char *p, *q;
70
71 ASSERT(buffer && hello);
72
73 memset(buffer, '\0', YOOHOO_HELLOLEN);
74
75 p = buffer;
76 p = yoohoo_putword(p, 0x6f);
77 p = yoohoo_putword(p, 0x01); /* Hello version */
78 p = yoohoo_putword(p, hello->product_code); /* Product code */
79 p = yoohoo_putword(p, hello->version_maj); /* Major version */
80 p = yoohoo_putword(p, hello->version_min); /* Minor version */
81
82 strnxcpy(p, hello->system, 60); /* Node name */
83
84 /*
85 * Add domain after the end of 'Node name'
86 * TODO: check it for buffer overflows %-I
87 */
88 if( hello->anum > 0 && hello->addrs[0].addr.domain
89 && *hello->addrs[0].addr.domain )
90 {
91 char *q;
92 if( strlen(hello->system) + strlen(hello->addrs[0].addr.domain) > 57 )
93 {
94 if( strlen(hello->addrs[0].addr.domain) < 60 )
95 q = p + (60 - strlen(hello->addrs[0].addr.domain));
96 else
97 q = p;
98
99 *q++ = '\0';
100 }
101 else
102 {
103 q = p + strlen(hello->system) + 1;
104 }
105 strnxcpy(q, hello->addrs[0].addr.domain, 60-(q-p));
106 }
107 p += 60;
108
109 strnxcpy(p, hello->sysop, 20); /* SysOp name */
110 p += 20;
111
112 if( hello->anum > 0 )
113 {
114 p = yoohoo_putword(p, hello->addrs[0].addr.zone);
115 p = yoohoo_putword(p, hello->addrs[0].addr.net);
116 p = yoohoo_putword(p, hello->addrs[0].addr.node);
117 p = yoohoo_putword(p, hello->addrs[0].addr.point);
118 }
119 else
120 p += 8;
121
122 strncpy(p, hello->passwd, 8); /* Session password */
123 p += 8;
124 p += 8; /* Reserved 8 bytes */
125 p = yoohoo_putword(p, hello->capabilities); /* Capabilities */
126 p += 12; /* Reserved 12 bytes */
127
128 #ifdef DEBUG
129 DEB((D_HSHAKE, "yoohoo_put_hello: HELLO dump: \"%s\"",
130 q = string_printable_buffer(buffer, 128)));
131 if( q ) free(q);
132 #endif
133
134 ASSERT((p - buffer) == YOOHOO_HELLOLEN);
135 }
136
137 /*****************************************************************************
138 * Extract session information from the ``hello'' packet
139 *
140 * Arguments:
141 * hello pointer to the destination structure with the session
142 * information
143 * buffer source buffer with ``hello'' packet
144 *
145 * Return value:
146 * None
147 */
yoohoo_get_hello(s_yoohoo_sysinfo * hello,const char * buffer)148 static int yoohoo_get_hello(s_yoohoo_sysinfo *hello, const char *buffer)
149 {
150 s_faddr addr;
151
152 ASSERT(buffer && hello);
153
154 #ifdef DEBUG
155 {
156 char *q = string_printable_buffer(buffer, YOOHOO_HELLOLEN);
157 DEB((D_HSHAKE, "yoohoo_get_hello: HELLO dump: \"%s\"", q));
158 if( q ) free(q);
159 }
160 #endif
161
162 memset(hello, '\0', sizeof(s_yoohoo_sysinfo));
163
164 if( yoohoo_getword(buffer+2) != 0x01 )
165 bf_log("YooHoo hello version is %d!", yoohoo_getword(buffer+2));
166
167 hello->product_code = yoohoo_getword(buffer+4);
168 hello->version_maj = yoohoo_getword(buffer+6);
169 hello->version_min = yoohoo_getword(buffer+8);
170 strnxcpy(hello->system, buffer+10, MIN(sizeof(hello->system),60+1));
171 strnxcpy(hello->sysop, buffer+70, MIN(sizeof(hello->sysop),20+1));
172
173 /*
174 * Extract address
175 */
176 memset(&addr, '\0', sizeof(s_faddr));
177 addr.zone = yoohoo_getword(buffer+90);
178 addr.net = yoohoo_getword(buffer+92);
179 addr.node = yoohoo_getword(buffer+94);
180 addr.point = yoohoo_getword(buffer+96);
181 session_addrs_add(&hello->addrs, &hello->anum, addr);
182
183 strnxcpy(hello->passwd, buffer+98, MIN(sizeof(hello->passwd),8+1));
184 /* Reserved 8 bytes */
185 hello->capabilities = yoohoo_getword(buffer+114);
186 /* Reserved 12 bytes */
187
188 return 0;
189 }
190
yoohoo_send_hello(s_yoohoo_sysinfo * local_data)191 int yoohoo_send_hello(s_yoohoo_sysinfo *local_data)
192 {
193 char hello_buffer[YOOHOO_HELLOLEN];
194 unsigned short hello_crc = 0;
195 YooHoo_SendState state = YS_Init;
196 time_t wait_timer;
197 int tries = 0;
198 int rc;
199
200 ASSERT(local_data);
201
202 while(1)
203 {
204 switch(state) {
205 case YS_Init:
206 tries = 0;
207 yoohoo_put_hello(hello_buffer, local_data);
208 hello_crc = getcrc16xmodem(hello_buffer, YOOHOO_HELLOLEN);
209 state = YS_SendHello;
210 break;
211
212 case YS_SendHello:
213 if( ++tries > 10 )
214 {
215 bf_log("too many tries sending hello");
216 state = YS_Error;
217 break;
218 }
219 else if( tries > 1 )
220 bf_log("yoohoo hello send - retry %d", tries);
221
222 if( PUTCHAR(0x1f) < 0
223 || WRITE_TIMEOUT(hello_buffer, sizeof(hello_buffer)) < 0
224 || PUTCHAR(((unsigned int) hello_crc >> 8) & 0xff) < 0
225 || PUTCHAR(((unsigned int) hello_crc ) & 0xff) < 0 )
226 {
227 state = YS_Error;
228 break;
229 }
230
231 timer_set(&wait_timer, 40);
232 state = YS_WaitResp;
233 break;
234
235 case YS_WaitResp:
236 if( timer_expired(wait_timer) )
237 {
238 bf_log("time out waiting for response");
239 state = YS_Error;
240 break;
241 }
242
243 if( (rc = GETCHAR(1)) < 0 )
244 {
245 if( rc != TTY_TIMEOUT )
246 {
247 state = YS_Error;
248 break;
249 }
250 }
251 else if( rc == XON || rc == XOFF )
252 {
253 /* Do nothing. Drop them down */
254 }
255 else if( rc == '?' || rc == ENQ )
256 {
257 if( rc == '?' )
258 bf_log("remote failed to receive our HELLO packet");
259 state = YS_SendHello;
260 }
261 else if( rc == ACK )
262 {
263 state = YS_Done;
264 }
265 break;
266
267 case YS_Done:
268 return 0;
269
270 case YS_Error:
271 return -1;
272 }
273 }
274
275 return -1; /* UNREACHABLE */
276 }
277
yoohoo_recv_hello(s_yoohoo_sysinfo * remote_data)278 int yoohoo_recv_hello(s_yoohoo_sysinfo *remote_data)
279 {
280 char hello_buffer[YOOHOO_HELLOLEN];
281 int crc_local = 0;
282 int crc_remote = 0;
283 YooHoo_RecvState state = YR_Init;
284 time_t wait_timer;
285 time_t junk_timer;
286 int hello_pos;
287 int tries = 0;
288 int rc;
289
290 ASSERT(remote_data);
291
292 while(1)
293 {
294 switch(state) {
295 case YR_Init:
296 tries = 0;
297 memset(hello_buffer, '\0', sizeof(hello_buffer));
298 state = YR_SendENQ;
299 break;
300
301 case YR_SendENQ:
302 if( ++tries > 3 )
303 {
304 bf_log("too many tries receiving hello");
305 state = YR_Error;
306 break;
307 }
308 else if( tries > 1 )
309 bf_log("yoohoo hello recv - retry %d", tries);
310
311 if( PUTCHAR(ENQ) < 0 )
312 {
313 state = YR_Error;
314 break;
315 }
316
317 timer_set(&wait_timer, 120);
318 state = YR_WaitHeader;
319 break;
320
321 case YR_WaitHeader:
322 if( timer_expired(wait_timer) )
323 {
324 bf_log("time out waiting for response");
325 state = YR_Error;
326 break;
327 }
328
329 if( (rc = GETCHAR(1)) < 0 )
330 {
331 if( rc != TTY_TIMEOUT )
332 {
333 state = YR_Error;
334 break;
335 }
336 }
337 else if( rc == XON || rc == XOFF )
338 {
339 /* Do nothing. Drop them down */
340 }
341 else if( rc == 0x1f )
342 {
343 state = YR_RecvHello;
344 }
345 else
346 {
347 timer_set(&junk_timer, 10);
348 state = YR_TossJunk;
349 }
350 break;
351
352 case YR_TossJunk:
353 if( timer_expired(junk_timer) )
354 {
355 state = YR_SendENQ;
356 break;
357 }
358
359 if( (rc = GETCHAR(1)) < 0 )
360 {
361 if( rc != TTY_TIMEOUT )
362 {
363 state = YR_Error;
364 break;
365 }
366 }
367 else if( rc == XON || rc == XOFF )
368 {
369 /* Do nothing. Drop them down */
370 }
371 else if( rc == 0x1f )
372 {
373 state = YR_RecvHello;
374 }
375 break;
376
377 case YR_RecvHello:
378 hello_pos = 0;
379 while( (rc = GETCHAR(30)) >= 0 )
380 {
381 if( hello_pos < 128 )
382 {
383 hello_buffer[hello_pos++] = rc;
384 }
385 else if( hello_pos == 128 )
386 {
387 crc_remote = ((unsigned int) ((unsigned char) rc) << 8);
388 ++hello_pos;
389 }
390 else if( hello_pos == 129 )
391 {
392 crc_remote |= (unsigned int) ((unsigned char) rc);
393 break;
394 }
395 else
396 break;
397 }
398
399 if( hello_pos != 129 )
400 {
401 state = YR_Error;
402 break;
403 }
404
405 /*
406 * Check CRC-16
407 */
408 crc_local = getcrc16xmodem(hello_buffer, sizeof(hello_buffer));
409 if( crc_local != crc_remote )
410 {
411 bf_log("got hello packet with incorrect checksum");
412 state = YR_SendNAK;
413 break;
414 }
415
416 if( yoohoo_get_hello(remote_data, hello_buffer) )
417 {
418 bf_log("got invalid hello packet");
419 state = YR_SendNAK;
420 }
421 else
422 state = YR_SendACK;
423 break;
424
425 case YR_SendNAK:
426 if( PUTCHAR('?') < 0 )
427 state = YR_Error;
428 else
429 state = YR_WaitHeader;
430 break;
431
432 case YR_SendACK:
433 if( PUTCHAR(ACK) < 0 )
434 state = YR_Error;
435 else
436 state = YR_Done;
437 break;
438
439 case YR_Done:
440 return 0;
441
442 case YR_Error:
443 return -1;
444 }
445 }
446
447 return -1; /* UNREACHABLE */
448 }
449
yoohoo_set_sysinfo(s_yoohoo_sysinfo * local_data,int hrc,e_protocol protocol)450 void yoohoo_set_sysinfo(s_yoohoo_sysinfo *local_data, int hrc,
451 e_protocol protocol)
452 {
453 s_cval_entry *addr_ptr;
454 s_faddr *primary = NULL;
455
456 const long options = conf_options(cf_options);
457 const char *p_system = conf_string(cf_system_name);
458 const char *p_sysop = conf_string(cf_sysop_name);
459
460 memset(local_data, '\0', sizeof(s_yoohoo_sysinfo));
461
462 /* Set best primary address */
463 primary = session_get_bestaka(state.node.addr);
464
465 /*
466 * Set our local address
467 */
468 if( primary )
469 session_addrs_add(&local_data->addrs, &local_data->anum, *primary);
470 else if( (addr_ptr = conf_first(cf_address)) )
471 session_addrs_add(&local_data->addrs, &local_data->anum, addr_ptr->d.falist.addr);
472
473 if( !local_data->anum )
474 bf_log("warning: no addresses will be presented to remote");
475
476 /*
477 * Set session password
478 */
479 if( state.caller )
480 {
481 session_get_password(state.node.addr,
482 local_data->passwd, sizeof(local_data->passwd));
483 }
484 else if( hrc == HRC_OK )
485 {
486 /* Satisfy remote with their password */
487 const char *p = state.handshake->remote_password(state.handshake);
488 if( p )
489 strnxcpy(local_data->passwd, p, sizeof(local_data->passwd));
490 }
491
492 if( !state.caller )
493 {
494 if( state.reqstat != REQS_ALLOW )
495 local_data->capabilities |= YOOHOO_WZ_FREQ;
496 }
497
498 /* compatibility codes */
499 if( state.caller )
500 {
501 if( (options & OPTIONS_NO_ZMODEM) != OPTIONS_NO_ZMODEM )
502 local_data->capabilities |= YOOHOO_ZMODEM;
503 if( (options & OPTIONS_NO_ZEDZAP) != OPTIONS_NO_ZEDZAP )
504 local_data->capabilities |= YOOHOO_ZEDZAP;
505 if( (options & OPTIONS_NO_JANUS) != OPTIONS_NO_JANUS )
506 local_data->capabilities |= YOOHOO_JANUS;
507 if( (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA )
508 local_data->capabilities |= YOOHOO_HYDRA;
509 }
510 else
511 {
512 switch(protocol) {
513 case PROT_ZMODEM: local_data->capabilities |= YOOHOO_ZMODEM; break;
514 case PROT_ZEDZAP: local_data->capabilities |= YOOHOO_ZEDZAP; break;
515 case PROT_JANUS: local_data->capabilities |= YOOHOO_JANUS; break;
516 case PROT_HYDRA: local_data->capabilities |= YOOHOO_HYDRA; break;
517 default: break;
518 }
519 }
520
521 local_data->product_code = BF_PRODCODE;
522
523 if( hrc == HRC_BAD_PASSWD )
524 {
525 local_data->version_maj = 99;
526 local_data->version_min = 99; /* TODO */
527 }
528 else
529 {
530 local_data->version_maj = 0;
531 local_data->version_min = 1;
532 }
533
534 strnxcpy(local_data->sysop, p_sysop ? p_sysop : "Unknown", sizeof(local_data->sysop));
535
536 switch(hrc) {
537 case HRC_BAD_PASSWD:
538 strnxcpy(local_data->system, "Bad password", sizeof(local_data->system));
539 break;
540 case HRC_LOW_SPEED:
541 strnxcpy(local_data->system, "Connect speed too low", sizeof(local_data->system));
542 break;
543 case HRC_BUSY:
544 strnxcpy(local_data->system, "All AKAs are busy", sizeof(local_data->system));
545 break;
546 default:
547 strnxcpy(local_data->system, p_system ? p_system : "Unknown", sizeof(local_data->system));
548 }
549 }
550
551 /*****************************************************************************
552 * Write system information to the log
553 *
554 * Arguments:
555 * yoohoo structure with the system information
556 *
557 * Return value:
558 * None
559 */
yoohoo_log_sysinfo(s_yoohoo_sysinfo * yoohoo)560 void yoohoo_log_sysinfo(s_yoohoo_sysinfo *yoohoo)
561 {
562 int i;
563 char abuf[BF_MAXADDRSTR+1];
564
565 if( yoohoo->anum )
566 for( i = 0; i < yoohoo->anum; i++ )
567 {
568 bf_log(" Address : %s", ftn_addrstr(abuf, yoohoo->addrs[i].addr));
569 }
570 else
571 bf_log(" Address : <none>");
572
573 if( yoohoo->system[0] )
574 bf_log(" System : %s", string_printable(yoohoo->system));
575
576 #ifdef BFORCE_LOG_PASSWD
577 if( yoohoo->passwd[0] )
578 bf_log(" Password : %s", string_printable(yoohoo->passwd));
579 #endif
580
581 if( yoohoo->sysop[0] )
582 bf_log(" SysOp : %s", string_printable(yoohoo->sysop));
583
584 if( yoohoo->product_code || yoohoo->version_maj || yoohoo->version_min )
585 {
586 bf_log(" Mailer : %s [%02x] %d.%d",
587 "?", yoohoo->product_code,
588 yoohoo->version_maj, yoohoo->version_min);
589 }
590 }
591
592