1 /*****************************************************************************
2 * AreaFix for HTICK (FTN Ticker / Request Processor)
3 *****************************************************************************
4 * Copyright (C) 2004
5 *
6 * val khokhlov (Fido: 2:550/180), Kiev, Ukraine
7 *
8 * Based on original HTICK code by:
9 *
10 * Max Levenkov
11 *
12 * Fido: 2:5000/117
13 * Internet: sackett@mail.ru
14 *
15 * Novosibirsk, West Siberia, Russia
16 *
17 * This file is part of HTICK, which is based on HPT by Matthias Tichy,
18 * 2:2432/605.14 2:2433/1245, mtt@tichy.de
19 *
20 * HTICK is free software; you can redistribute it and/or modify it
21 * under the terms of the GNU General Public License as published by the
22 * Free Software Foundation; either version 2, or (at your option) any
23 * later version.
24 *
25 * HTICK is distributed in the hope that it will be useful, but
26 * WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with HTICK; see the file COPYING. If not, write to the Free
32 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
33 *****************************************************************************
34 * $Id$
35 *****************************************************************************/
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44
45 /* compiler.h */
46 #include <huskylib/compiler.h>
47
48 #ifdef HAS_UNISTD_H
49 # include <unistd.h>
50 #endif
51
52 /* fidoconf */
53 #include <fidoconf/fidoconf.h>
54 #include <fidoconf/common.h>
55 #include <huskylib/xstr.h>
56 #include <fidoconf/afixcmd.h>
57 #include <fidoconf/arealist.h>
58 #include <fidoconf/areatree.h>
59
60 /* areafix */
61 #include <areafix/areafix.h>
62 #include <areafix/afglobal.h>
63 #include <areafix/callback.h>
64 #include <areafix/query.h>
65
66 /* htick */
67 #include <fcommon.h>
68 #include <global.h>
69 #include <toss.h>
70 #include <htickafix.h>
71 #include <hatch.h>
72 #include <scan.h>
73 #include <add_desc.h>
74 extern char *versionStr;
75
76 #define AREA_ACCESS_OK 0
77 #define AREA_ACCESS_NOGROUP 1
78 #define AREA_ACCESS_NOLEVEL 2
79 #define AREA_ACCESS_NOEXPORT 3
80 #define AREA_ACCESS_NOIMPORT 3
81 #define AREA_ACCESS_NOTLINKED 4
82
checkAccessAndOptGrps(s_area * echo,s_link * link,int imp_exp)83 int checkAccessAndOptGrps( s_area * echo, s_link * link, int imp_exp )
84 {
85 if( echo->group )
86 {
87 /* check group access */
88 if( !grpInArray( echo->group, config->PublicGroup, config->numPublicGroup ) &&
89 !grpInArray( echo->group, link->AccessGrp, link->numAccessGrp ) )
90 return AREA_ACCESS_NOGROUP;
91 /* check import/export restriction */
92 if( imp_exp == 0 &&
93 ( link->numOptGrp == 0 || grpInArray( echo->group, link->optGrp, link->numOptGrp ) ) )
94 return AREA_ACCESS_NOEXPORT;
95 }
96 else
97 {
98 /* No access group restriction is applied for areas without group
99 * (virtually no-group is always part of PublicGroup) */
100
101 /* check import/export restriction */
102 /* No import/export restriction is applied for areas without group
103 * if OptGrp isn't empty (in contrast to PublicGroup,
104 * virtually optGrp doesn't contain no-group) */
105 if( imp_exp == 0 && link->numOptGrp == 0 )
106 return AREA_ACCESS_NOEXPORT;
107 }
108 return AREA_ACCESS_OK;
109 }
110
e_readCheck(s_fidoconfig * config,s_area * echo,s_link * link)111 int e_readCheck( s_fidoconfig * config, s_area * echo, s_link * link )
112 {
113 unsigned i, rc = AREA_ACCESS_OK;
114 unsigned Pause = echo->areaType;
115
116 for( i = 0; i < echo->downlinkCount && link != echo->downlinks[i]->link; i++ );
117 /* Link is not subscribed => no export ever */
118 if( i == echo->downlinkCount )
119 return AREA_ACCESS_NOTLINKED;
120
121 /* pause */
122 if( ( ( link->Pause & Pause ) == Pause ) && echo->noPause == 0 )
123 return 3;
124
125 /* check access based on group access and optGrp+export */
126 rc = checkAccessAndOptGrps( echo, link, link->aexport );
127 if( rc != AREA_ACCESS_OK )
128 return rc;
129
130 /* check access level */
131 if( echo->levelread > link->level )
132 return AREA_ACCESS_NOLEVEL;
133
134 /* check for 'access export' for arealink set up by WriteOnly keyword */
135 if( echo->downlinks[i]->aexport == 0 )
136 return AREA_ACCESS_NOEXPORT;
137
138 return rc;
139 }
140
e_writeCheck(s_fidoconfig * config,s_area * echo,s_link * link)141 int e_writeCheck( s_fidoconfig * config, s_area * echo, s_link * link )
142 {
143 unsigned int i = 0, rc = AREA_ACCESS_OK;
144
145 if( echo->downlinkCount == 0 && isOurAka( config, link->hisAka ) )
146 {
147 /* always OK for nolinks (need for hpucode's tics) */
148 /* FIXME: Is it really safe and only way? */
149 return 0;
150 }
151
152 for( i = 0; i < echo->downlinkCount && link != echo->downlinks[i]->link; i++ );
153 /* Link is not subscribed => refuse to import */
154 /* OurAka is a special case for access check of ourselves */
155 if( i == echo->downlinkCount && !isOurAka( config, link->hisAka ) )
156 return AREA_ACCESS_NOTLINKED;
157
158 /* check access based on group access and optGrp+import */
159 rc = checkAccessAndOptGrps( echo, link, link->import );
160 if( rc != AREA_ACCESS_OK )
161 return rc;
162
163 /* check access level */
164 if( echo->levelwrite > link->level )
165 return AREA_ACCESS_NOLEVEL;
166
167 /* check for 'access import' for arealink set up by ReadOnly keyword */
168 if( i < echo->downlinkCount && echo->downlinks[i]->import == 0 )
169 return AREA_ACCESS_NOIMPORT;
170
171 return rc;
172 }
173
174
resend(s_link * link,s_message * msg,char * cmd)175 char *resend( s_link * link, s_message * msg, char *cmd )
176 {
177 unsigned int rc, i;
178 char *line;
179 char *report = NULL, *token = NULL, *filename = NULL, *filearea = NULL;
180 s_area *area = NULL;
181
182 line = cmd;
183 line = stripLeadingChars( line, " \t" );
184 token = strtok( line, " \t\0" );
185 if( token == NULL )
186 {
187 xscatprintf( &report, "Error in line! Format: %%Resend <file> <filearea>\r" );
188 return report;
189 }
190 filename = sstrdup( token );
191 token = stripLeadingChars( strtok( NULL, "\0" ), " " );
192 if( token == NULL )
193 {
194 nfree( filename );
195 xscatprintf( &report, "Error in line! Format: %%Resend <file> <filearea>\r" );
196 return report;
197 }
198 filearea = sstrdup( token );
199 area = getFileArea( filearea );
200 if( area != NULL )
201 {
202 rc = 1;
203 for( i = 0; i < area->downlinkCount; i++ )
204 if( addrComp( msg->origAddr, area->downlinks[i]->link->hisAka ) == 0 )
205 rc = 0;
206 if( rc == 1 && area->manual == 1 )
207 rc = 5;
208 else
209 rc = send( filename, filearea, aka2str( link->hisAka ) );
210 switch ( rc )
211 {
212 case 0:
213 xscatprintf( &report, "Send %s from %s for %s\r",
214 filename, filearea, aka2str( link->hisAka ) );
215 break;
216 case 1:
217 xscatprintf( &report, "Error: Passthrough filearea %s!\r", filearea );
218 w_log( '8', "FileFix %%Resend: Passthrough filearea %s", filearea );
219 break;
220 case 2:
221 xscatprintf( &report, "Error: Filearea %s not found!\r", filearea );
222 w_log( '8', "FileFix %%Resend: Filearea %s not found", filearea );
223 break;
224 case 3:
225 xscatprintf( &report, "Error: File %s not found!\r", filename );
226 w_log( '8', "FileFix %%Resend: File %s not found", filename );
227 break;
228 case 5:
229 xscatprintf( &report, "Error: You don't have access for filearea %s!\r", filearea );
230 w_log( '8', "FileFix %%Resend: Link don't have access for filearea %s", filearea );
231 break;
232 }
233 }
234 else
235 {
236 xscatprintf( &report, "Error: filearea %s not found!\r", filearea );
237 w_log( '8', "FileFix %%Resend: Filearea %s not found", filearea );
238 }
239
240 nfree( filearea );
241 nfree( filename );
242 return report;
243 }
244
245
filefix_tellcmd(char * cmd)246 int filefix_tellcmd( char *cmd )
247 {
248 char *line = NULL;
249
250 if( strncasecmp( cmd, "* Origin:", 9 ) == 0 )
251 return NOTHING;
252 line = strpbrk( cmd, " \t" );
253 if( line && *cmd != '%' )
254 *line = 0;
255
256 line = cmd;
257
258 switch ( line[0] )
259 {
260 case '%':
261 line++;
262 if( *line == 0 )
263 return FFERROR;
264 if( stricmp( line, "list" ) == 0 )
265 return LIST;
266 if( stricmp( line, "help" ) == 0 )
267 return HELP;
268 if( stricmp( line, "unlinked" ) == 0 )
269 return UNLINKED;
270 if( stricmp( line, "linked" ) == 0 )
271 return QUERY;
272 if( stricmp( line, "avail" ) == 0 )
273 return AVAIL;
274 if( stricmp( line, "query" ) == 0 )
275 return QUERY;
276 if( stricmp( line, "pause" ) == 0 )
277 return PAUSE;
278 if( stricmp( line, "resume" ) == 0 )
279 return RESUME;
280 if( stricmp( line, "info" ) == 0 )
281 return INFO;
282 if( strncasecmp( line, "resend", 6 ) == 0 )
283 if( line[6] != 0 )
284 return RESEND;
285 return FFERROR;
286 case '\001':
287 return NOTHING;
288 case '\000':
289 return NOTHING;
290 case '-':
291 return DEL;
292 case '+':
293 line++;
294 if( line[0] == '\000' )
295 return FFERROR;
296 default:
297 return ADD;
298 }
299
300 return 0;
301 }
302
filefix_processcmd(s_link * link,s_message * msg,char * line,int cmd)303 char *filefix_processcmd( s_link * link, s_message * msg, char *line, int cmd )
304 {
305
306 char *report = NULL;
307
308 switch ( cmd )
309 {
310
311 case NOTHING:
312 return NULL;
313
314 case LIST:
315 report = list( lt_all, link, line );
316 RetFix = LIST;
317 break;
318 case HELP:
319 report = help( link );
320 RetFix = HELP;
321 break;
322 case ADD:
323 report = subscribe( link, line );
324 RetFix = ADD;
325 break;
326 case DEL:
327 report = unsubscribe( link, line );
328 RetFix = DEL;
329 break;
330 case UNLINKED:
331 report = list( lt_unlinked, link, line );
332 RetFix = UNLINKED;
333 break;
334 case QUERY:
335 report = list( lt_linked, link, line );
336 RetFix = QUERY;
337 break;
338 case AVAIL:
339 report = available( link, line );
340 RetFix = AVAIL;
341 break;
342 case PAUSE:
343 report = pause_link( link );
344 RetFix = PAUSE;
345 break;
346 case RESUME:
347 report = resume_link( link );
348 RetFix = RESUME;
349 break;
350 /* case INFO: report = info_link(msg, link);
351 RetFix=INFO;
352 break;*/
353 case RESEND:
354 report = resend( link, msg, line + 7 );
355 RetFix = RESEND;
356 break;
357 case FFERROR:
358 report = errorRQ( line );
359 RetFix = FFERROR;
360 break;
361 default:
362 return NULL;
363 }
364
365 return report;
366 }
367
368
369 /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
370
371
processFileFix(s_message * msg)372 int processFileFix( s_message * msg )
373 {
374 int security = 1, notforme = 0;
375 s_link *link = NULL;
376 s_link *tmplink = NULL;
377 char *textBuff = NULL, *report = NULL, *preport = NULL, *token = NULL;
378
379 /* find link */
380 link = getLinkFromAddr( config, msg->origAddr );
381
382 if( link )
383 {
384 w_log( LL_AREAFIX, "FileFix: request from %s", aka2str( link->hisAka ) );
385 }
386 else
387 {
388 w_log( LL_ERR, "FileFix: No such link in config: %s!", aka2str( msg->origAddr ) );
389 }
390
391 /* this is for me? */
392 if( link != NULL )
393 notforme = addrComp( msg->destAddr, *link->ourAka );
394
395 /* ignore msg for other link (maybe this is transit...) */
396 if( notforme )
397 {
398 w_log( LL_AREAFIX,
399 "Destination address (%s) of the message belongs to set of our addresses but differs from ourAka setting for link",
400 aka2str( msg->destAddr ) );
401 return 2;
402 }
403
404
405 /* security check: link, filefix enabled & password. */
406 if( link != NULL )
407 {
408 if( link->filefix.on )
409 {
410 if( link->filefix.pwd )
411 {
412 if( stricmp( link->filefix.pwd, msg->subjectLine ) == 0 )
413 security = 0;
414 else
415 security = 3;
416 }
417 else
418 security = 0;
419 }
420 else
421 security = 2;
422 }
423 else
424 security = 1;
425
426 remove_kludges( msg );
427
428 if( !security )
429 {
430 char *tmp;
431
432 textBuff = tmp = sstrdup( msg->text );
433 token = strseparate( &textBuff, "\n\r" );
434 while( token != NULL )
435 {
436 preport =
437 filefix_processcmd( link, msg, stripLeadingChars( token, " \t" ),
438 filefix_tellcmd( token ) );
439 if( preport != NULL )
440 {
441 switch ( RetFix )
442 {
443 case LIST:
444 RetMsg( msg, link, preport, "Filefix reply: list request" );
445 break;
446 case HELP:
447 RetMsg( msg, link, preport, "Filefix reply: help request" );
448 break;
449 case ADD:
450 case DEL:
451 /*if (report == NULL) report = textHead(); */
452 report = areaStatus( report, preport );
453 break;
454 case UNLINKED:
455 RetMsg( msg, link, preport, "Filefix reply: unlinked request" );
456 break;
457 case QUERY:
458 RetMsg( msg, link, preport, "Filefix reply: linked request" );
459 break;
460 case AVAIL:
461 RetMsg( msg, link, preport, "Filefix reply: avail request" );
462 break;
463 case PAUSE:
464 case RESUME:
465 RetMsg( msg, link, preport, "Filefix reply: node change request" );
466 break;
467 case INFO:
468 RetMsg( msg, link, preport, "Filefix reply: link information" );
469 break;
470 case RESEND:
471 RetMsg( msg, link, preport, "Filefix reply: resend request" );
472 break;
473 case FFERROR:
474 if( report == NULL )
475 report = textHead( );
476 report = areaStatus( report, preport );
477 break;
478 default:
479 break;
480 }
481
482 }
483 token = strseparate( &textBuff, "\n\r" );
484 }
485 nfree( tmp );
486
487 }
488 else
489 {
490
491 if( link == NULL )
492 {
493 tmplink = ( s_link * ) scalloc( 1, sizeof( s_link ) );
494 tmplink->ourAka = &( msg->destAddr );
495 tmplink->hisAka.zone = msg->origAddr.zone;
496 tmplink->hisAka.net = msg->origAddr.net;
497 tmplink->hisAka.node = msg->origAddr.node;
498 tmplink->hisAka.point = msg->origAddr.point;
499 link = tmplink;
500 }
501 /* security problem */
502
503 switch ( security )
504 {
505 case 1:
506 report = sstrdup( " \r your system is unknown\r" );
507 break;
508 case 2:
509 report = sstrdup( " \r filefix is turned off\r" );
510 break;
511 case 3:
512 report = sstrdup( " \r password error\r" );
513 break;
514 default:
515 report = sstrdup( " \r unknown error. mail to sysop.\r" );
516 break;
517 }
518
519
520 RetMsg( msg, link, report, "security violation" );
521 /* free(report); */
522
523 w_log( '8', "FileFix: security violation from %s", aka2str( link->hisAka ) );
524
525 free( tmplink );
526
527 return 0;
528 }
529
530
531 if( report != NULL )
532 {
533 if( af_robot->queryReports )
534 {
535 preport = list( lt_linked, link, NULL );
536 xstrcat( &report, preport );
537 nfree( preport );
538 }
539 RetMsg( msg, link, report, "Filefix reply: node change request" );
540 }
541
542 w_log( '8', "FileFix: successfully done for %s", aka2str( link->hisAka ) );
543 /* send msg to the links (forward requests to areafix) */
544 sendAreafixMessages( );
545 return 1;
546 }
547
ffix(hs_addr addr,char * cmd)548 void ffix( hs_addr addr, char *cmd )
549 {
550 s_link *link = NULL;
551 s_message *tmpmsg = NULL;
552
553 if( cmd )
554 {
555 link = getLinkFromAddr( config, addr );
556 if( link )
557 {
558 tmpmsg = makeMessage( &addr, link->ourAka, link->name,
559 link->filefix.name ? link->filefix.name : "Filefix",
560 link->filefix.pwd ? link->filefix.pwd : "", 1, af_robot->reportsAttr );
561 tmpmsg->text = strdup( cmd );
562 processFileFix( tmpmsg );
563 tmpmsg->text = NULL;
564 freeMsgBuffers( tmpmsg );
565 }
566 else
567 w_log( LL_ERR, "FileFix: no such link in config: %s!", aka2str( addr ) );
568 }
569 else
570 scan( );
571 }
572
573
574 /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
575
afSendMsg(s_message * tmpmsg)576 int afSendMsg( s_message * tmpmsg )
577 {
578 writeNetmail( tmpmsg, config->robotsArea );
579 return 1;
580 }
581
afWriteMsgToSysop(s_message * msg)582 int afWriteMsgToSysop( s_message * msg )
583 {
584 if( config->ReportTo )
585 writeMsgToSysop( msg, config->ReportTo, config->origin ? config->origin : config->name );
586 return 1;
587 }
588
afReportAutoCreate(char * c_area,char * descr,hs_addr pktOrigAddr,ps_addr forwardAddr)589 void afReportAutoCreate( char *c_area, char *descr, hs_addr pktOrigAddr, ps_addr forwardAddr )
590 {
591 s_area *area;
592 s_message *msg;
593 FILE *echotosslog;
594
595 unused( descr );
596 unused( forwardAddr );
597
598 /* report about new filearea */
599 if( config->ReportTo && !cmAnnNewFileecho && ( area = getFileArea( c_area ) ) != NULL )
600 {
601 if( getNetMailArea( config, config->ReportTo ) != NULL )
602 {
603 msg = makeMessage( area->useAka,
604 area->useAka,
605 af_robot->name,
606 config->sysop, "Created new fileareas", 1, af_robot->reportsAttr );
607 msg->text = createKludges( config, NULL, area->useAka, area->useAka, af_versionStr );
608 }
609 else
610 {
611 msg = makeMessage( area->useAka,
612 area->useAka,
613 af_robot->name, "All", "Created new fileareas", 0, af_robot->reportsAttr );
614 msg->text =
615 createKludges( config, config->ReportTo, area->useAka, area->useAka, af_versionStr );
616 } /* endif */
617 if( af_robot->reportsFlags )
618 xstrscat( &( msg->text ), "\001FLAGS ", af_robot->reportsFlags, "\r", NULL );
619 xstrscat( &msg->text, "\r\rNew filearea: ",
620 area->areaName, "\r\rDescription : ",
621 area->description ? area->description : "", "\r", NULL );
622 writeMsgToSysop( msg, config->ReportTo, NULL );
623 freeMsgBuffers( msg );
624 nfree( msg );
625 if( config->echotosslog != NULL )
626 {
627 echotosslog = fopen( config->echotosslog, "a" );
628 fprintf( echotosslog, "%s\n", config->ReportTo );
629 fclose( echotosslog );
630 }
631 }
632
633 if( cmAnnNewFileecho )
634 announceNewFileecho( announcenewfileecho, c_area, aka2str( pktOrigAddr ) );
635 }
636
getLinkRobot(s_link * link)637 s_link_robot *getLinkRobot( s_link * link )
638 {
639 return &( link->filefix );
640 }
641
init_htickafix(void)642 int init_htickafix( void )
643 {
644 /* vars */
645 af_config = config;
646 af_cfgFile = cfgFile;
647 af_app = &theApp;
648 af_versionStr = versionStr;
649 af_quiet = quiet;
650 af_silent_mode = 0; /*silent_mode; */
651 af_report_changes = 0; /*report_changes; */
652 af_send_notify = cmNotifyLink;
653 af_pause = FILEAREA;
654 /* callbacks and hooks */
655 call_getArea = &getFileArea;
656 call_sendMsg = &afSendMsg;
657 call_writeMsgToSysop = &afWriteMsgToSysop;
658 call_getLinkRobot = &getLinkRobot;
659 hook_onAutoCreate = &afReportAutoCreate;
660 robot = getRobot( config, "filefix", 0 ); /* !!! val: change this later !!! */
661 return init_areafix( "filefix" );
662 }
663