This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbfido/ptic.c
2002-01-07 19:16:03 +00:00

761 lines
19 KiB
C

/*****************************************************************************
*
* $Id$
* Purpose ...............: Process 1 .tic file
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../lib/libs.h"
#include "../lib/structs.h"
#include "../lib/users.h"
#include "../lib/records.h"
#include "../lib/common.h"
#include "../lib/dbtic.h"
#include "../lib/clcomm.h"
#include "../lib/dbnode.h"
#include "../lib/dbdupe.h"
#include "ulock.h"
#include "mover.h"
#include "toberep.h"
#include "tic.h"
#include "utic.h"
#include "addbbs.h"
#include "magic.h"
#include "forward.h"
#include "rollover.h"
#include "ptic.h"
#include "magic.h"
#include "virscan.h"
#define UNPACK_FACTOR 300
extern int tic_bad;
extern int tic_dup;
extern int tic_out;
extern int do_quiet;
extern int check_crc;
extern int check_dupe;
/*
* Return values:
* 0 - Success
* 1 - Some error
* 2 - Orphaned tic
*/
int ProcessTic(fa_list *sbl)
{
time_t Now, Fdate;
int Age, First, Listed = FALSE;
int DownLinks = 0;
int MustRearc = FALSE;
int UnPacked = FALSE, IsArchive = FALSE;
int i, j, k, File_Id = FALSE;
char *Temp, *unarc = NULL, *cmd = NULL;
char temp1[PATH_MAX], temp2[PATH_MAX], sbe[24], TDesc[256];
unsigned long crc, crc2, Kb;
sysconnect Link;
FILE *fp;
long FwdCost = 0, FwdSize = 0;
struct utimbuf ut;
int BBS_Imp = FALSE, DidBanner = FALSE;
Now = time(NULL);
if (TIC.TicIn.PathError) {
WriteError("Our Aka is in the path");
return 1;
}
Temp = calloc(PATH_MAX, sizeof(char));
if (!do_quiet) {
colour(10, 0);
printf("Checking \b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
if (strlen(TIC.RealName) == 0) {
WriteError("File not in inbound: %s", TIC.TicIn.File);
/*
* Now check the age of the .tic file.
*/
sprintf(Temp, "%s/%s", TIC.Inbound, TIC.TicName);
Fdate = file_time(Temp);
Age = (Now - Fdate) / 84400;
Syslog('+', "Orphaned tic age %d days", Age);
if (Age > 21) {
tic_bad++;
mover(TIC.TicName);
}
free(Temp);
return 2;
}
sprintf(Temp, "%s/%s", TIC.Inbound, TIC.RealName);
crc = file_crc(Temp, CFG.slow_util && do_quiet);
TIC.FileSize = file_size(Temp);
TIC.FileDate = file_time(Temp);
if (TIC.TicIn.Size) {
if (TIC.TicIn.Size != TIC.FileSize)
WriteError("Size is %ld, expected %ld", TIC.FileSize, TIC.TicIn.Size);
}
if (TIC.Crc_Int) {
if (crc != TIC.Crc_Int) {
Syslog('!', "CRC: expected %08lX, the file is %08lX", TIC.Crc_Int, crc);
if (check_crc) {
Bad((char *)"CRC: error, %s may be damaged", TIC.RealName);
free(Temp);
return 1;
} else {
Syslog('!', "CRC: error, recalculating crc");
ReCalcCrc(Temp);
}
}
} else {
Syslog('+', "CRC: missing, calculating CRC");
ReCalcCrc(Temp);
}
/*
* Load and check the .TIC area.
*/
if (!SearchTic(TIC.TicIn.Area)) {
Bad((char *)"Unknown file area %s", TIC.TicIn.Area);
free(Temp);
return 1;
}
if ((tic.Secure) && (!TIC.TicIn.Hatch)) {
First = TRUE;
while (GetTicSystem(&Link, First)) {
First = FALSE;
if (Link.aka.zone) {
if ((Link.aka.zone == TIC.Aka.zone) &&
(Link.aka.net == TIC.Aka.net) &&
(Link.aka.node == TIC.Aka.node) &&
(Link.aka.point== TIC.Aka.point) &&
(Link.receivefrom))
Listed = TRUE;
}
}
if (!Listed) {
Bad((char *)"%s NOT connected to %s", aka2str(TIC.Aka), TIC.TicIn.Area);
free(Temp);
return 1;
}
}
if ((!SearchNode(TIC.Aka)) && (!TIC.TicIn.Hatch)) {
Bad((char *)"%s NOT known", aka2str(TIC.Aka));
free(Temp);
return 1;
}
if (!TIC.TicIn.Hatch) {
if (strcasecmp(TIC.TicIn.Pw, nodes.Fpasswd)) {
Bad((char *)"Pwd error, got %s, expected %s", TIC.TicIn.Pw, nodes.Fpasswd);
free(Temp);
return 1;
}
} else {
if (strcasecmp(TIC.TicIn.Pw, CFG.hatchpasswd)) {
Bad((char *)"Password error in local Hatch");
WriteError("WARNING: it might be a Trojan in your inbound");
free(Temp);
return 1;
}
}
if (Magic_DeleteFile()) {
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.TicName);
file_rm(temp1);
Syslog('+', "Deleted file %s", temp1);
file_rm(Temp);
free(Temp);
return 0;
}
if (Magic_MoveFile()) {
if (!SearchTic(TIC.TicIn.Area)) {
Bad((char *)"Unknown Area: %s", TIC.TicIn.Area);
free(Temp);
return 1;
}
}
strcpy(T_File.Echo, tic.Name);
strcpy(T_File.Group, tic.Group);
TIC.KeepNum = tic.KeepLatest;
Magic_Keepnum();
if (!tic.FileArea) {
Syslog('f', "Passthru area!");
strcpy(TIC.BBSpath, CFG.ticout);
strcpy(TIC.BBSdesc, tic.Comment);
} else {
sprintf(Temp, "%s/etc/fareas.data", getenv("MBSE_ROOT"));
if ((fp = fopen(Temp, "r")) == NULL) {
WriteError("Can't access fareas.data area: %ld", tic.FileArea);
free(Temp);
return 1;
}
fread(&areahdr, sizeof(areahdr), 1, fp);
if (fseek(fp, ((tic.FileArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET)) {
fclose(fp);
WriteError("Can't seek area %ld in fareas.data", tic.FileArea);
free(Temp);
return 1;
}
if (fread(&area, areahdr.recsize, 1, fp) != 1) {
fclose(fp);
WriteError("Can't read area %ld in fareas.data", tic.FileArea);
free(Temp);
return 1;
}
fclose(fp);
strcpy(TIC.BBSpath, area.Path);
strcpy(TIC.BBSdesc, area.Name);
/*
* If the File area has a special announce group, change
* the group to that name.
*/
if (strlen(area.NewGroup))
strcpy(T_File.Group, area.NewGroup);
}
strcpy(T_File.Comment, tic.Comment);
/*
* Check if the destination area really exists, it may be that
* the area is not linked to an existing BBS area.
*/
if (tic.FileArea && access(TIC.BBSpath, W_OK)) {
WriteError("$No write access to \"%s\"", TIC.BBSpath);
Bad((char *)"Dest directory not available");
free(Temp);
return 1;
}
if ((tic.DupCheck) && (check_dupe)) {
sprintf(Temp, "%s%s", TIC.TicIn.Area, TIC.TicIn.Crc);
crc2 = 0xffffffff;
crc2 = upd_crc32(Temp, crc2, strlen(Temp));
if (CheckDupe(crc2, D_FILEECHO, CFG.tic_dupes)) {
Bad((char *)"Duplicate file");
tic_dup++;
free(Temp);
return 1;
}
}
/*
* Count the actual downlinks for this area
*/
First = TRUE;
while (GetTicSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto))
DownLinks++;
}
/*
* Calculate the cost of this file
*/
T_File.Size = TIC.FileSize;
T_File.SizeKb = TIC.FileSize / 1024;
if ((fgroup.UnitCost) || (TIC.TicIn.Cost))
TIC.Charge = TRUE;
else
TIC.Charge = FALSE;
if (TIC.Charge) {
/*
* Calculate our filetransfer cost.
*/
FwdCost = fgroup.UnitCost;
FwdSize = fgroup.UnitSize;
/*
* If FwdSize <> 0 then calculate per size, else
* charge for each file.
*/
if (FwdSize)
TIC.FileCost = ((TIC.FileSize / 1024) / FwdSize) * FwdCost;
else
TIC.FileCost = FwdCost;
if (TIC.TicIn.Cost)
TIC.FileCost += TIC.TicIn.Cost;
if (fgroup.AddProm)
TIC.FileCost += (TIC.FileCost * fgroup.AddProm / 1000);
if (fgroup.DivideCost) {
/*
* If not a passthru area, we are a link too.
*/
if (DownLinks)
TIC.FileCost = TIC.FileCost / (DownLinks + 1);
}
/*
* At least charge one unit.
*/
if (!TIC.FileCost)
TIC.FileCost = 1;
Syslog('+', "The file cost will be %ld", TIC.FileCost);
}
/*
* Update the uplink's counters.
*/
Kb = TIC.FileSize / 1024;
if (SearchNode(TIC.Aka)) {
if (TIC.TicIn.Cost && nodes.Billing) {
nodes.Debet -= TIC.TicIn.Cost;
Syslog('f', "Uplink cost %ld, debet %ld", TIC.TicIn.Cost, nodes.Debet);
}
StatAdd(&nodes.FilesRcvd, 1L);
StatAdd(&nodes.F_KbRcvd, Kb);
UpdateNode();
SearchNode(TIC.Aka);
}
/*
* Update the fileecho and group counters.
*/
StatAdd(&fgroup.Files, 1L);
StatAdd(&fgroup.KBytes, Kb);
fgroup.LastDate = time(NULL);
StatAdd(&tic.Files, 1L);
StatAdd(&tic.KBytes, Kb);
tic.LastAction = time(NULL);
UpdateTic();
if (!do_quiet) {
printf("Unpacking \b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
/*
* Check if this is an archive, and if so, which compression method
* is used for this file.
*/
if (strlen(tic.Convert) || tic.VirScan || tic.FileId || tic.ConvertAll || strlen(tic.Banner)) {
if ((unarc = unpacker(TIC.RealName)) == NULL)
Syslog('+', "Unknown archive format %s", TIC.RealName);
else {
IsArchive = TRUE;
if ((strlen(tic.Convert) && (strcmp(unarc, tic.Convert) == 0)) || (tic.ConvertAll))
MustRearc = TRUE;
}
}
/*
* Copy the file if there are downlinks and we send the
* original file, but want to rearc it for ourself, or if
* it's a passthru area.
*/
if (((tic.SendOrg) && (MustRearc || strlen(tic.Banner))) || (!tic.FileArea)) {
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.RealName);
sprintf(temp2, "%s/%s", CFG.ticout, TIC.RealName);
if (file_cp(temp1, temp2) == 0) {
TIC.SendOrg = TRUE;
} else {
WriteError("$Copy %s to %s failed", temp1, temp2);
}
}
if ((tic.VirScan || MustRearc) && IsArchive) {
/*
* Check if there is a temp directory for the archive
* conversion.
*/
sprintf(temp2, "%s/tmp/arc", getenv("MBSE_ROOT"));
if ((access(temp2, R_OK)) != 0) {
if (mkdir(temp2, 0777)) {
WriteError("$Can't create %s", temp2);
free(Temp);
return 1;
}
}
/*
* Check for stale FILE_ID.DIZ files
*/
sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT"));
if (!unlink(temp1))
Syslog('+', "Removed stale %s", temp1);
sprintf(temp1, "%s/tmp/arc/file_id.diz", getenv("MBSE_ROOT"));
if (!unlink(temp1))
Syslog('+', "Removed stale %s", temp1);
sprintf(temp1, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT"));
if (!unlink(temp1))
Syslog('+', "Removed stale %s", temp1);
sprintf(temp1, "%s/tmp/file_id.diz", getenv("MBSE_ROOT"));
if (!unlink(temp1))
Syslog('+', "Removed stale %s", temp1);
if (!checkspace(temp2, TIC.RealName, UNPACK_FACTOR)) {
Bad((char *)"Not enough free diskspace left");
free(Temp);
return 1;
}
if (chdir(temp2) != 0) {
WriteError("$Can't change to %s", temp2);
free(Temp);
return 1;
}
if (!getarchiver(unarc)) {
chdir(TIC.Inbound);
free(Temp);
return 1;
}
cmd = xstrcpy(archiver.funarc);
if ((cmd == NULL) || (cmd == "")) {
Syslog('!', "No unarc command available");
} else {
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.RealName);
if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) {
UnPacked = TRUE;
} else {
chdir(TIC.Inbound);
Bad((char *)"Archive maybe corrupt");
free(Temp);
DeleteVirusWork();
return 1;
}
free(cmd);
}
}
if (tic.VirScan && !UnPacked) {
/*
* Copy file to tempdir and run scanner over the file
* whatever that is. This should catch single files
* with worms or other macro viri
*/
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.RealName);
sprintf(temp2, "%s/tmp/arc/%s", getenv("MBSE_ROOT"), TIC.RealName);
if (file_cp(temp1, temp2)) {
WriteError("Can't copy %s to %s", temp1, temp2);
free(Temp);
return 1;
} else {
Syslog('f', "file_cp(%s, %s) ok", temp1, temp2);
}
sprintf(temp2, "%s/tmp/arc", getenv("MBSE_ROOT"));
if (chdir(temp2) != 0) {
WriteError("$Can't change to %s", temp2);
free(Temp);
return 1;
}
}
if (tic.VirScan) {
if (!do_quiet) {
printf("Virscan \b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
if (VirScan()) {
DeleteVirusWork();
chdir(TIC.Inbound);
Bad((char *)"Possible virus found!");
free(Temp);
return 1;
}
if (!do_quiet) {
printf("Checking \b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
}
if (tic.FileId && tic.FileArea && IsArchive) {
if (UnPacked) {
sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT"));
sprintf(temp2, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT"));
if (file_cp(temp1, temp2) == 0) {
File_Id = TRUE;
} else {
sprintf(temp1, "%s/tmp/arc/file_id.diz", getenv("MBSE_ROOT"));
if (file_cp(temp1, temp2) == 0) {
File_Id = TRUE;
}
}
} else {
if (!getarchiver(unarc)) {
chdir(TIC.Inbound);
} else {
cmd = xstrcpy(archiver.iunarc);
if (cmd == NULL) {
WriteError("No unarc command available");
} else {
sprintf(temp1, "%s/tmp", getenv("MBSE_ROOT"));
chdir(temp1);
sprintf(temp1, "%s/%s FILE_ID.DIZ", TIC.Inbound, TIC.RealName);
if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null",
(char *)"/dev/null", (char *)"/dev/null") == 0) {
File_Id = TRUE;
} else {
sprintf(temp1, "%s/%s file_id.diz", TIC.Inbound, TIC.RealName);
if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null",
(char *)"/dev/null", (char *)"/dev/null") == 0) {
File_Id = TRUE;
}
}
free(cmd);
}
} /* if getarchiver */
} /* if not unpacked */
} /* if need FILE_ID.DIZ and not passthru */
/*
* Create internal file description, priority is FILE_ID.DIZ,
* 2nd LDesc, and finally the standard description.
*/
if (!Get_File_Id()) {
if (TIC.TicIn.TotLDesc > 2) {
for (i = 0; i < TIC.TicIn.TotLDesc; i++) {
strcpy(temp1, TIC.TicIn.LDesc[i]);
temp1[48] = '\0';
strcpy(TIC.File_Id[i], temp1);
}
TIC.File_Id_Ct = TIC.TicIn.TotLDesc;
} else {
/*
* Format the description line (max 255 chars)
* in parts of 48 characters.
*/
if (strlen(TIC.TicIn.Desc) <= 48) {
strcpy(TIC.File_Id[0], TIC.TicIn.Desc);
TIC.File_Id_Ct++;
} else {
memset(&TDesc, 0, sizeof(TDesc));
strcpy(TDesc, TIC.TicIn.Desc);
while (strlen(TDesc) > 48) {
j = 48;
while (TDesc[j] != ' ')
j--;
strncat(TIC.File_Id[TIC.File_Id_Ct], TDesc, j);
TIC.File_Id_Ct++;
k = strlen(TDesc);
j++; /* Correct space */
for (i = 0; i <= k; i++, j++)
TDesc[i] = TDesc[j];
}
strcpy(TIC.File_Id[TIC.File_Id_Ct], TDesc);
TIC.File_Id_Ct++;
}
}
} /* not get FILE_ID.DIZ */
if ((MustRearc) && (UnPacked) && (tic.FileArea)) {
if (Rearc(tic.Convert)) {
if (strlen(tic.Banner)) {
Syslog('f', "Must replace banner 1");
}
/*
* Get new filesize for import and announce
*/
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.NewName);
TIC.FileSize = file_size(temp1);
T_File.Size = TIC.FileSize;
T_File.SizeKb = TIC.FileSize / 1024;
/*
* Calculate the CRC if we must send the new
* archived file.
*/
if (!TIC.SendOrg) {
ReCalcCrc(temp1);
}
} else {
WriteError("Rearc failed");
} /* if Rearc() */
} else {
/*
* If the file is not unpacked, change the banner
* direct if this is needed.
*/
if ((strlen(tic.Banner)) && IsArchive) {
cmd = xstrcpy(archiver.barc);
if ((cmd == NULL) || (!strlen(cmd))) {
Syslog('!', "No banner command for %s", archiver.name);
} else {
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.RealName);
sprintf(Temp, "%s/etc/%s", getenv("MBSE_ROOT"), tic.Banner);
if (execute(cmd, temp1, (char *)NULL, Temp, (char *)"/dev/null", (char *)"/dev/null")) {
WriteError("$Changing the banner failed");
} else {
Syslog('+', "New banner %s", tic.Banner);
TIC.FileSize = file_size(temp1);
T_File.Size = TIC.FileSize;
T_File.SizeKb = TIC.FileSize / 1024;
ReCalcCrc(temp1);
DidBanner = TRUE;
}
}
}
} /* if MustRearc and Unpacked and not Passthtru */
DeleteVirusWork();
chdir(TIC.Inbound);
/*
* If the file is converted, we set the date of the original
* received file as the file creation date.
*/
if (MustRearc || DidBanner) {
if ((!tic.NoTouch) && (tic.FileArea)) {
ut.actime = mktime(localtime(&TIC.FileDate));
ut.modtime = mktime(localtime(&TIC.FileDate));
sprintf(Temp, "%s/%s", TIC.Inbound, TIC.NewName);
utime(Temp, &ut);
}
}
if (tic.FileArea) {
Syslog('+', "Import: %s Area: %s", TIC.NewName, TIC.TicIn.Area);
BBS_Imp = Add_BBS();
if (!BBS_Imp) {
Bad((char *)"File Import Error");
free(Temp);
return 1;
}
}
chdir(TIC.Inbound);
if (tic.FileArea) {
if (strlen(TIC.TicIn.Magic))
UpDateAlias(TIC.TicIn.Magic);
else
Magic_UpDateAlias();
for (i = 0; i <= TIC.File_Id_Ct; i++)
strcpy(T_File.LDesc[i], TIC.File_Id[i]);
T_File.TotLdesc = TIC.File_Id_Ct;
T_File.Announce = tic.Announce;
strcpy(T_File.Name, TIC.NewName);
T_File.Fdate = TIC.FileDate;
T_File.Cost = TIC.TicIn.Cost;
Add_ToBeRep();
}
if (TIC.SendOrg && !tic.FileArea) {
/*
* If it's a passthru area we don't need the
* file in the inbound anymore so it can be
* deleted.
*/
sprintf(temp1, "%s/%s", TIC.Inbound, TIC.RealName);
if (file_rm(temp1) == 0)
Syslog('f', "Deleted %s", temp1);
}
if (DownLinks) {
First = TRUE;
/*
* Add all our system aka's to the seenby lines in the same zone
*/
for (i = 0; i < 40; i++) {
if (CFG.akavalid[i] && (tic.Aka.zone == CFG.aka[i].zone) &&
!((tic.Aka.net == CFG.aka[i].net) && (tic.Aka.node == CFG.aka[i].node))) {
sprintf(sbe, "%u:%u/%u", CFG.aka[i].zone, CFG.aka[i].net, CFG.aka[i].node);
fill_list(&sbl, sbe, NULL);
}
}
/*
* Add downlinks to seenby lines
*/
while (GetTicSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.aka.point)) {
if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) &&
(TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) {
sprintf(sbe, "%u:%u/%u", Link.aka.zone, Link.aka.net, Link.aka.node);
fill_list(&sbl, sbe, NULL);
}
}
}
uniq_list(&sbl);
sort_list(&sbl);
/*
* Now start forwarding files
*/
First = TRUE;
while (GetTicSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) {
if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) &&
(TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) {
tic_out++;
ForwardFile(Link.aka, sbl);
}
}
}
}
Magic_ExecCommand();
Magic_CopyFile();
Magic_UnpackFile();
Magic_AdoptFile();
sprintf(Temp, "%s/%s", TIC.Inbound, TIC.TicName);
unlink(Temp);
free(Temp);
return 0;
}