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