This is zendhand.c in view mode; [Download] [Up]
static char rcsid[] = "$Id: zendhand.c,v 1.13 1993/02/21 13:07:09 gerben Exp $";
/*
Zend --- a mail transport program for large files and directories
Copyright (C) 1992 Gerben C. Th. Wierda
This program 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 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Gerben Wierda
Goudriaanstraat 1
1222 SG Hilversum
The Netherlands
gerben@rna.indiv.nluug.nl
*/
/*
*
* zendhand.c -- Message handlers.
*
*/
#include "zend.h"
#define ZEND_ADDRESS NULL /* Represents address of other-side zend. */
/* Support routines: */
/* Open a mail stream and write some standard stuff to it. */
static FILE *
#if _ANSI_DEFUN_
mail_open( const char *mailAddress)
#else
mail_open( mailAddress)
char *mailAddress;
#endif
{
char mailCommand[PATHBUFSIZ];
FILE *mailStream;
char *q;
if (mailAddress == ZEND_ADDRESS) /* Special case for zend addresses. */
{
if (strcmp( get_global_string( global, SYSTEMNAMEPROMPT),
get_global_string( remoteglobal, SYSTEMNAMEPROMPT)) == 0)
{
mailAddress = "zend";
}
else
{
sprintf( mailCommand, get_global_boolean( global, UUCPMODEPROMPT) ?
"%s!zend" : "zend@%s",
get_global_string( remoteglobal, SYSTEMNAMEPROMPT));
mailAddress = mailCommand;
}
}
set_global( global, MAILTOPROMPT, mailAddress);
sprintf( mailCommand, "%s %s", MAILPROG, q = quote_for_sh( mailAddress));
free( q);
#if DEBUG
zerr( "%s\n", mailCommand);
#endif
if ((mailStream = popen_as_user( mailCommand, "w")) == NIL)
{
zerr( "Unable to start mail\n");
}
else
{
#if DEBUG
zerr( "mail succesfully started.\n");
#endif
#if BINMAIL
writeglobtostream( global, MAILTOPROMPT, mailStream);
#endif
}
return mailStream;
}
#define mail_close pclose
/* Return mail address of ``local'' user. */
static const char *
#if _ANSI_DEFUN_
local_user_address( void)
#else
local_user_address()
#endif
{
return get_global_string( global,
strcmp( get_global_string( global, ROLEPROMPT),
ROLE_SENDER) == 0 ?
SENDINGUSERPROMPT : RECEIVINGUSERPROMPT);
}
/* Return mail address of ``remote'' user. */
static const char *
#if _ANSI_DEFUN_
remote_user_address( void)
#else
remote_user_address()
#endif
{
static char *address;
const char *remoteUser;
const char *remoteSystem;
if (address)
{
free(address);
address = NIL;
}
remoteUser = get_global_string( global,
strcmp( get_global_string( global,
ROLEPROMPT),
ROLE_SENDER) == 0 ?
RECEIVINGUSERPROMPT : SENDINGUSERPROMPT);
remoteSystem = get_global_string( remoteglobal, SYSTEMNAMEPROMPT);
if (strcmp( get_global_string( global, SYSTEMNAMEPROMPT), remoteSystem) == 0)
{
return remoteUser;
}
address = safecalloc( strlen(remoteUser) + strlen(remoteSystem) + 1 + 1,
sizeof( char));
sprintf( address, "%s@%s", remoteUser, remoteSystem);
return address;
}
/* Notify a user of an error (and log it). */
static void
#if _ANSI_DEFUN_
mail_report_error( const char *reason)
#else
mail_report_error( reason)
char *reason;
#endif
{
FILE *mailStream;
zerr( "%s\n", reason);
if ((mailStream = mail_open( local_user_address())) == NIL)
{
return;
}
fprintf( mailStream, "Subject: ZEND FAILED %s %s %s (%s)\n\n",
get_global_string( global, FILEPROMPT),
strcmp( get_global_string( global, ROLEPROMPT), ROLE_SENDER) == 0 ?
"->" : "<-", remote_user_address(), reason);
/* The subject line says it all... */
mail_close( mailStream);
}
/* Mail an error report to the other side.
Also report failure back to the sending user (if we are the sender). */
extern void
#if _ANSI_DEFUN_
mail_err( const char *format, ...)
#else
mail_err( format, va_alist)
char *format;
va_dcl
#endif
{
char buf[PATHBUFSIZ];
va_list argpt;
va_begin( argpt, format);
vsprintf( buf, format, argpt);
va_end( argpt);
set_global( global, REASONPROMPT, buf);
set_global( global, ACTIONPROMPT, ACTION_ERR);
mail_message();
if (strcmp( get_global_string( global, ROLEPROMPT), ROLE_SENDER) == 0)
{
mail_report_error( buf);
}
}
#if _ANSI_DEFUN_
extern void handle_ayt( void)
#else
extern void handle_ayt()
#endif
{
Ulong jobId;
StringPointer
receivingUser = get_global_string( remoteglobal, RECEIVINGUSERPROMPT),
sendingSystem = get_global_string( remoteglobal, SYSTEMNAMEPROMPT),
list;
/*
* See if the file is acceptable. If so, create a jobID, else send an ERR
* message saying either file too big or user unknown.
*/
set_global( global, ROLEPROMPT, ROLE_RECEIVER);
set_global( global, SENDINGJOBIDPROMPT,
get_global_ulong( remoteglobal, SENDINGJOBIDPROMPT));
#if DEBUG
zerr( "Handling %s\n", ACTION_AYT);
#endif
if (strcmp( get_global_string( global, ZENDIDPROMPT),
get_global_string( remoteglobal, ZENDIDPROMPT)) != 0)
{
mail_err( "I do not accept protocol (%s).",
get_global_string( global, ZENDIDPROMPT));
return;
}
else if (get_global_ulong( global, RECEIVETRUESIZEPROMPT) <
get_global_ulong( remoteglobal, ZENDTRUESIZEPROMPT))
{
mail_err( "Max real transfer size (%lu) exceeded.",
get_global_ulong( global, RECEIVETRUESIZEPROMPT));
return;
}
else if (get_global_ulong( global, RECEIVESIZEPROMPT) <
get_global_ulong( remoteglobal, ZENDSIZEPROMPT))
{
mail_err( "Max mail traffic transfer size (%lu) exceeded.",
get_global_ulong( global, RECEIVESIZEPROMPT));
return;
}
else if (getpwnam( receivingUser) == NIL)
{
mail_err( "Unknown user (%s)", receivingUser);
return;
}
else if (((list = get_global_string( global, ALLOWUSERSPROMPT)) &&
list[0] &&
!str_listed( receivingUser, list)) ||
str_listed( receivingUser,
get_global_string( global, EXCLUDEUSERSPROMPT)))
{
mail_err( "User access denied");
return;
}
else if (((list = get_global_string( global, ALLOWSYSTEMSPROMPT)) &&
list[0] &&
!str_listed( sendingSystem, list)) ||
str_listed( sendingSystem,
get_global_string( global, EXCLUDESYSTEMSPROMPT)))
{
mail_err( "System access denied");
return;
}
else
{
if ((jobId = new_job()) == RESERVEDID)
{
return;
}
set_global( global, ACTIONPROMPT, ACTION_UAR);
set_global( global, RECEIVINGJOBIDPROMPT, jobId);
set_global( global, DIRPROMPT,
get_global_string( global, SPOOLDIRPROMPT) ?
get_global_string( global, SPOOLDIRPROMPT) : "~/Zend");
set_global( global, FILEPROMPT,
get_global_string( remoteglobal, FILEPROMPT));
set_global( global, TYPEPROMPT,
get_global_string( remoteglobal, TYPEPROMPT));
set_global( global, SENDINGUSERPROMPT,
get_global_string( remoteglobal, SENDINGUSERPROMPT));
set_global( global, RECEIVINGUSERPROMPT, receivingUser);
set_global( global, COMPRESSEDPROMPT,
get_global_boolean( remoteglobal, COMPRESSEDPROMPT));
/*
* Store sending system's name in jobfile for timeout.
*/
set_global( global, SENDINGSYSTEMPROMPT, sendingSystem);
/*
* Determine maximum of job- and packet timeouts.
*/
if (get_global_ushort( global, PACKETTIMEOUTPROMPT) <
get_global_ushort( remoteglobal, PACKETTIMEOUTPROMPT))
{
set_global( global, PACKETTIMEOUTPROMPT,
get_global_ushort( remoteglobal, PACKETTIMEOUTPROMPT));
}
if (get_global_ushort( global, JOBTIMEOUTPROMPT) <
get_global_ushort( remoteglobal, JOBTIMEOUTPROMPT))
{
set_global( global, JOBTIMEOUTPROMPT,
get_global_ushort( remoteglobal, JOBTIMEOUTPROMPT));
}
set_global( global, TIMESTAMPPROMPT, (Ulong) timestamp);
#if DEBUG
zerr( "Writing jobfile...\n");
#endif
write_globs_to_jobfile( global, jobId);
zlog( "ACCEPT");
#if DEBUG
zerr( "Sending UAR...\n");
#endif
mail_message();
}
}
#if _ANSI_DEFUN_
extern void handle_uar( void)
#else
extern void handle_uar()
#endif
{
char buf[PATHBUFSIZ];
char buf2[PATHBUFSIZ];
FILE *tmpStream;
FILE *chunkStream= NIL;
Ushort lineno = 0,
chunkno = 0,
nrofchunks = 0,
chunksize = get_global_ushort( remoteglobal, LINESPROMPT);
Ulong jobId = get_global_ulong( remoteglobal, SENDINGJOBIDPROMPT);
umask( ~S_IRUSR);
#if DEBUG
zerr( "Handling %s\n", ACTION_UAR);
#endif
if (chunksize < 100)
{
#if 0
mail_err( "Chunk size too small (<100) %u", (unsigned int)chunksize);
return;
#else /* silently set to minimum */
chunksize = 100;
#endif
}
if (read_jobfile_to_globs( global, jobId) != 0)
{
mail_err( "UAR: Never heard of local job %lu", jobId);
return;
}
/*
* Set job timeout to maximum of send and receive.
*/
if (get_global_ushort( global, JOBTIMEOUTPROMPT) <
get_global_ushort( remoteglobal, JOBTIMEOUTPROMPT))
{
set_global( global, JOBTIMEOUTPROMPT,
get_global_ushort( remoteglobal, JOBTIMEOUTPROMPT));
}
/*
* Make the chunks
*/
sprintf( buf, "cd %s/D.%lu && %s < ../F.%lu ../F.%lu",
HOMEDIR, jobId, UUENCODEPROG, jobId,
get_global_ulong( remoteglobal, RECEIVINGJOBIDPROMPT));
if ((tmpStream = popen_as_zend( buf, "r")) == NIL)
{
mail_err( "Unable to make chunks. Job discarded.");
kill_job( jobId);
return;
}
while (fgets( buf, PATHBUFSIZ, tmpStream) != NIL)
{
if (lineno == chunksize)
{
if (fclose( chunkStream) != 0)
{
mail_err( "Unable to make chunks. Job discarded.");
kill_job( jobId);
return;
}
lineno = 0;
}
if (lineno == 0)
{
sprintf( buf2, "%s/D.%lu/%05u", HOMEDIR, jobId,
(unsigned int)++nrofchunks);
if ((chunkStream = fopen( buf2, "w")) == NIL)
{
mail_err( "Unable to make chunks. Job discarded.");
kill_job( jobId);
return;
}
}
fputs( buf, chunkStream);
lineno++;
}
if (fclose( chunkStream) != 0 || pclose( tmpStream) != 0)
{
mail_err( "Unable to make chunks. Job discarded.");
kill_job( jobId);
return;
}
set_global( global, ACTIONPROMPT, ACTION_CNK);
set_global( global, NROFCHUNKSPROMPT, (unsigned int)nrofchunks);
set_global( global, RECEIVINGJOBIDPROMPT,
get_global_ulong( remoteglobal, RECEIVINGJOBIDPROMPT));
set_global( global, TIMESTAMPPROMPT, timestamp);
/*
* We have made all chunks. Mail them off.
*/
write_globs_to_jobfile( global, jobId);
for (chunkno = 1; chunkno <= nrofchunks; chunkno++)
{
set_global( global, CHUNKNRPROMPT, (unsigned int)chunkno);
mail_chunk();
}
zlog( "ZENT (%u chunk%s)", (unsigned int)nrofchunks,
(nrofchunks == 1) ? "" : "s");
/*
* remove our copy
*/
sprintf( buf, "%s/F.%lu", HOMEDIR, jobId);
#if DEBUG
zerr( "Unlinking %s\n", buf);
#endif
unlink( buf);
}
#if _ANSI_DEFUN_
extern void handle_cnk( void)
#else
extern void handle_cnk()
#endif
{
char buf[PATHBUFSIZ];
char buf2[PATHBUFSIZ];
FILE *tmpStream, *mailStream;
Ushort try;
struct passwd *pwStruct = NIL;
char *targetdir;
char *targetfile;
int deliver = -1, nameclash = FALSE;
char *assembledfile = NIL;
Boolean compressed;
Ulong jobId = get_global_ulong( remoteglobal, RECEIVINGJOBIDPROMPT);
struct stat statBuf;
Boolean filenameCorrupted = FALSE,
tarCorrupted = FALSE;
mode_t oldumask = umask( ~S_IRUSR);
#if DEBUG
zerr( "Handling %s\n", ACTION_CNK);
#endif
if (read_jobfile_to_globs( global, jobId) != 0)
{
mail_err( "CNK: Never heard of local job %lu", jobId);
return;
}
sprintf( buf2, "%s/D.%lu/%05u.XXXXXX", HOMEDIR, jobId,
(unsigned int)get_global_ushort( remoteglobal, CHUNKNRPROMPT));
if (mktemp( buf2) == NIL)
{
zerr( "Unable to create temp chunk name %s\n", buf2);
return;
}
if ((tmpStream = fopen( buf2, "w")) == NIL)
{
zerr( "Unable to create chunk %s\n", buf);
return;
}
/*
* stdin is on the first line of the chunk.
*/
while (fgets( buf, PATHBUFSIZ, stdin))
{
if (strncmp( buf, ZENDDELIMITER, strlen( ZENDDELIMITER)) == 0)
{
break;
}
fputs( buf, tmpStream);
}
fclose( tmpStream);
set_global( global, ACTIONPROMPT, ACTION_ACK);
set_global( global, CHUNKNRPROMPT,
(unsigned int)get_global_ushort( remoteglobal, CHUNKNRPROMPT));
set_global( global, NROFCHUNKSPROMPT,
(unsigned int)get_global_ushort( remoteglobal, NROFCHUNKSPROMPT));
set_global( global, TIMESTAMPPROMPT, timestamp);
write_globs_to_jobfile( global, jobId);
mail_message();
zlog( "CHUNK (%d of %d)",
(unsigned)get_global_ushort( global, CHUNKNRPROMPT),
(unsigned)get_global_ushort( global, NROFCHUNKSPROMPT));
/*
* Find out if all chunks are there:
*/
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId,
(unsigned int)get_global_ushort( remoteglobal, CHUNKNRPROMPT));
if (one_at_a_time( jobId, FILE_DELIVER) != 0)
{
zerr( "Unable to lock rename chunk %s to %s\n", buf2, buf);
return;
}
if (rename( buf2, buf) != 0)
{
zerr( "Unable to rename chunk %s to %s\n", buf2, buf);
end_one_at_a_time( jobId, FILE_DELIVER);
return;
}
for (try=1; try<=get_global_ushort( global, NROFCHUNKSPROMPT); try++)
{
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId,
(unsigned int)try);
#if 0
if (access( buf, F_OK) != 0)
#endif /* NO!!! access checks access rights of REAL user!!! */
if (stat( buf, &statBuf) != 0 && errno == ENOENT)
{
/* incomplete */
end_one_at_a_time( jobId, FILE_DELIVER);
return;
}
}
end_one_at_a_time( jobId, FILE_DELIVER);
/*
* We have all chunks and have sent all ACK's. Reassemble the file and place
* it in the users home directory.
*/
#if DEBUG
zerr( "I think all chunks received now\n");
#endif
targetdir = get_global_string( global, DIRPROMPT);
targetfile = get_global_string( global, FILEPROMPT);
compressed = get_global_boolean( global, COMPRESSEDPROMPT);
/* Catch attempts to corrupt filename. */
if (basename( targetfile) != targetfile)
{
filenameCorrupted = TRUE;
zlog( "BURGLAR ALARM! (corrupted filename)");
targetfile = basename( targetfile);
}
/*
* First get the users home directory and other info:
*/
pwStruct = getpwnam( get_global_string( global, RECEIVINGUSERPROMPT));
if (pwStruct == NIL)
{
zerr( "No delivery. Cannot get password info for user %s\n",
get_global_string( global, RECEIVINGUSERPROMPT));
deliver = -1;
#if DEBUG
zerr( "Unable to get password info\n");
#endif
}
else
{
/*
* Reassemble and deliver
*/
sprintf( buf, "cd %s/D.%lu && %s * | %s", HOMEDIR, jobId,
CATPROG, UUDECODEPROG);
if (system_as_zend( buf) != 0)
{
/*
* failed reassembly
*/
deliver = -1;
#if DEBUG
zerr( "Reassembly failed\n");
#endif
}
else
{
sprintf( buf, "%s/F.%lu", HOMEDIR, jobId);
assembledfile = strcpy( safecalloc( strlen( buf) + 1, sizeof( char)), buf);
/*
* Some uuencodes give default permission 0 when fed stdin, DEC
* Ultrix 4.2 for instance.
*/
if (chmod( assembledfile, S_IRUSR) != 0)
{
#if DEBUG
zerr( "Chmod assembledfile failed\n");
#endif
deliver = -1;
}
umask( oldumask);
targetdir = buf2;
if (get_global_string( global, SPOOLDIRPROMPT) != NIL)
{
/* Make sure spooldir exists.
{NOTE: if zend is setuid non-root this will fail in general,
so make sure spooldir is created at installation.} */
mkdir( get_global_string( global, SPOOLDIRPROMPT),
(S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH));
sprintf( targetdir, "%s/%s",
get_global_string( global, SPOOLDIRPROMPT),
get_global_string( global, RECEIVINGUSERPROMPT));
}
else
{
/* {NOTE: this only works if zend is seetuid root!} */
sprintf( targetdir, "%s/Zend", pwStruct->pw_dir);
}
if (mkdir( targetdir, S_IRWXU) == 0)
{
if (chown( targetdir, pwStruct->pw_uid, pwStruct->pw_gid) != 0)
{
/* Make sure the intended user can access the directory,
even if chown fails. (e.g., if zend is running
setuid non-root on _POSIX_CHOWN_RESTRICTED. systems.)
{{Is this a security hole????}}
*/
chmod( targetdir, (S_IRWXU|S_IRWXG|S_IRWXO));
}
}
if (!((stat( targetdir, &statBuf) == 0) &&
(S_ISDIR( statBuf.st_mode)) &&
(S_IWUSR & statBuf.st_mode)))
{
sprintf( targetdir, "/tmp");
}
/*
* If name clash, make temporary subdir:
*/
sprintf( buf, "%s/%s", targetdir, targetfile);
if (stat( buf, &statBuf) == 0)
{
#if DEBUG
zerr( "Name clash\n");
#endif
nameclash = TRUE;
strcat( targetdir, "/ZnXXXXXX");
if (mktemp( targetdir) != NIL &&
mkdir( targetdir,
(S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH)) == 0)
{
if (chown( targetdir, pwStruct->pw_uid, pwStruct->pw_gid) != 0)
{
chmod( targetdir, (S_IRWXU|S_IRWXG|S_IRWXO));
}
deliver = 0;
if (!((stat( targetdir, &statBuf) == 0) &&
(S_ISDIR( statBuf.st_mode)) &&
(S_IWUSR & statBuf.st_mode)))
{
sprintf( targetdir, "/tmp");
}
}
else
{
#if DEBUG
zerr( "Unable to make name clash directory\n");
#endif
deliver = -1;
}
}
else
{
deliver = 0;
}
}
}
if (deliver == 0)
{
if (strcmp( get_global_string( global, TYPEPROMPT), TYPE_FILE) == 0)
{
sprintf( buf, "%s > %s/%s",
(compressed) ? UNCOMPRESSPROG : CATPROG,
targetdir, quote_for_sh( targetfile));
}
else
{
/*
* Check filenames in tar as a safety precaution.
*/
sprintf( buf, "%s < %s | %s tf -",
(compressed) ? UNCOMPRESSPROG : CATPROG,
targetfile, TARPROG);
#if DEBUG
zerr( "%s", buf);
#endif
if ((tmpStream = popen_as_zend( buf, "r")) != NIL)
{
int len = strlen( targetfile);
char *s;
while (!tarCorrupted && fgets( buf, sizeof( buf), tmpStream))
{
/* All filenames should start with the directory name. */
if (strncmp( buf, targetfile, len) != 0 ||
!(buf[len] == '/' || buf[len] == '\n'))
{
tarCorrupted = TRUE;
break;
}
/*
* As an extra precaution, don't allow any reference
* to parent directories (..). These do not occur in
* well-formed tars.
*/
for (s = buf; (s = strchr( s, '.')); s++)
{
if (s[1] == '.' && ((s == buf || s[-1] == '/') &&
(s[2] == '/' || s[2] == '\n')))
{
tarCorrupted = TRUE;
break;
}
}
}
pclose( tmpStream);
}
if (tarCorrupted)
{
zlog( "BURGLAR ALARM! (corrupted filenames in tar)");
/* Deliver the tar instead of the directory. */
sprintf( buf, "cd %s && %s > %s",
targetdir, (compressed) ? UNCOMPRESSPROG : CATPROG,
quote_for_sh( targetfile));
}
else
{
sprintf( buf, "cd %s && %s | %s xf -",
targetdir, (compressed) ? UNCOMPRESSPROG : CATPROG,
TARPROG);
}
}
#if DEBUG
zerr( "%s", buf);
#endif
/* pipe the assembled file into the unpacking command. */
if ((tmpStream = fopen( assembledfile, "r")) == NIL)
{
deliver = -1;
}
else
{
FILE *cmdStream;
if ((cmdStream = popen_as( buf, "w",
pwStruct->pw_uid,
pwStruct->pw_gid)) == NIL)
{
deliver = -1;
}
else
{
size_t n;
char buf[BUFSIZ];
while (n = fread( buf, sizeof( char), sizeof( buf), tmpStream))
{
if (fwrite( buf, sizeof( char), n, cmdStream) != n)
{
deliver = -1;
break;
}
}
if (deliver == 0)
{
deliver = pclose( cmdStream);
}
}
fclose( tmpStream);
}
}
/*
* Remove all
*/
#if !DEBUG
kill_job( jobId);
#endif
/*
* Mail user
*/
if ((mailStream = mail_open( get_global_string( global, RECEIVINGUSERPROMPT))) != NIL)
{
if (pwStruct)
{
/* replace user's home directory with csh-like '~'. */
int homelen = strlen( pwStruct->pw_dir);
if (strncmp( targetdir, pwStruct->pw_dir, homelen) == 0 &&
targetdir[homelen] == '/' && homelen)
{
*(targetdir += homelen - 1) = '~';
}
}
fprintf( mailStream, "Subject: ZEND DELIVER%s %s/%s <- %s\n",
(deliver == 0) ? "ED" : "Y FAILED",
targetdir, targetfile, remote_user_address());
fprintf( mailStream, "\nZEND report:\n");
fprintf( mailStream, "User %s zent %s %s\n",
remote_user_address(),
strcmp( get_global_string( global, TYPEPROMPT), TYPE_FILE) == 0?
"file" : "directory",
targetfile);
if (filenameCorrupted || tarCorrupted)
{
fprintf( mailStream,
"\n!!USER %s TRIED TO CORRUPT THE ZEND PROTOCOL!!\n\n",
remote_user_address());
}
if (tarCorrupted)
{
fprintf( mailStream, "\n\
\tThe directory is delivered as the tar archive.\n\
\tWARNING: THIS TAR MAY CONTAIN `DANGEROUS' FILENAMES!\n\n");
}
if (!deliver)
{
if (nameclash)
{
fprintf( mailStream, "Name clash with existing file/directory.\n");
}
fprintf( mailStream, "It was succesfully delivered in %s.\n",
targetdir);
}
else
{
fprintf( mailStream, "Delivery failed. Exit status %d.\n",
deliver);
}
mail_close( mailStream);
}
zlog( (deliver == 0) ? "COMPLETED (successfully)" :
"COMPLETED (exit %d)", deliver);
}
#if _ANSI_DEFUN_
extern void handle_ack( void)
#else
extern void handle_ack()
#endif
{
char buf[PATHBUFSIZ];
Ushort try, nrofchunks;
Ushort chunkno = get_global_ushort( remoteglobal, CHUNKNRPROMPT);
Ulong jobId = get_global_ulong( remoteglobal, SENDINGJOBIDPROMPT);
FILE *mailStream;
#if DEBUG
zerr( "Handling %s for Chunk %u\n", ACTION_ACK, (unsigned int)chunkno);
#endif
if (read_jobfile_to_globs( global, jobId) != 0)
{
mail_err( "ACK: Never heard of local job %lu", jobId);
return;
}
#if DEBUG
zerr( "Local jobId (sender) is %lu\n", jobId);
#endif
/*
* Look if this was the last chunk to get the ACK for
*/
if (one_at_a_time( jobId, FILE_DELIVER) != 0)
{
zerr( "Unable to lock sending job for removal of chunk\n");
return;
}
nrofchunks = get_global_ushort( global, NROFCHUNKSPROMPT);
zlog( "ACK (%u of %u)", (unsigned int)chunkno, (unsigned int)nrofchunks);
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId, (unsigned int)chunkno);
#if DEBUG
zerr( "Unlinking %s\n", buf);
#endif
if (unlink( buf) != 0 && errno != ENOENT)
{
zerr( "Unable to unlink zent chunk %s (%s)\n", buf, strerror( errno));
}
for (try=1; try<=nrofchunks; try++)
{
struct stat statBuf;
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId, (unsigned int)try);
#if DEBUG
zerr( "Testing if %s is present\n", buf);
#endif
#if 0
if (access( buf, F_OK) == 0)
#endif
if (stat( buf, &statBuf) == 0)
{
/*
* still a chunk left. return.
*/
#if DEBUG
zerr( "Yep, %s is present\n", buf);
#endif
end_one_at_a_time( jobId, FILE_DELIVER);
/*
* Update timestamp (to forestall job timeout, since the other
* side is obviously still alive.)
*/
set_global( global, TIMESTAMPPROMPT, (Ulong) timestamp);
write_globs_to_jobfile( global, jobId);
return;
}
else
{
#if DEBUG
zerr( "Nope, %s is not present\n", buf);
#endif
}
}
end_one_at_a_time( jobId, FILE_DELIVER);
#if DEBUG
zerr( "I think all acknowledges are received\n");
#endif
/*
* remove directory and job file. file copy has been removed when chunks
* were sent.
*/
sprintf( buf, "%s/C.%lu", HOMEDIR, jobId);
#if DEBUG
zerr( "Unlinking %s\n", buf);
#endif
unlink( buf);
sprintf( buf, "%s/D.%lu", HOMEDIR, jobId);
#if DEBUG
zerr( "Removing dir %s\n", buf);
#endif
if (rmdir( buf) != 0)
{
zerr( "Unable to rmdir %s (%s)\n", buf, strerror( errno));
}
/*
* Mail user
*/
if ((mailStream = mail_open( get_global_string( global, SENDINGUSERPROMPT))) != NIL)
{
fprintf( mailStream, "Subject: ZENT %s -> %s\n",
get_global_string( global, FILEPROMPT), remote_user_address());
fprintf( mailStream, "\nZEND report:\n");
fprintf( mailStream, "%s %s zent succesfully to user %s\n",
get_global_string( global, TYPEPROMPT),
get_global_string( global, FILEPROMPT), remote_user_address());
mail_close( mailStream);
}
zlog( "COMPLETED");
}
#if _ANSI_DEFUN_
extern void handle_rsn( void)
#else
extern void handle_rsn()
#endif
{
char buf[PATHBUFSIZ];
unsigned int chunkno;
Ulong jobId = get_global_ulong( remoteglobal, SENDINGJOBIDPROMPT);
#if DEBUG
zerr( "Handling %s\n", ACTION_RSN);
#endif
if (read_jobfile_to_globs( global, jobId) != 0)
{
/* {[TRH] Should we do this? I mean, it is possible--if unlikely--that
a resend is received AFTER all chunks have been acknowledged.} */
mail_err( "RSN: Never heard of local job %lu", jobId);
return;
}
/*
* Update timestamp (to forestall job timeout, since the other
* side is obviously still alive.)
*/
set_global( global, TIMESTAMPPROMPT, (Ulong) timestamp);
write_globs_to_jobfile( global, jobId);
zlog( "RESEND");
/*
* Read requested chunks from stdin.
*/
while (scanf( "%u", &chunkno) > 0)
{
struct stat statBuf;
/* rezend the requested chunk (if still outstanding.) */
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId, chunkno);
#if 0
if (access( buf, F_OK) == 0)
#endif
if (stat( buf, &statBuf) == 0)
{
set_global( global, CHUNKNRPROMPT, chunkno);
mail_chunk();
}
}
if (scanf( "%s", buf) <= 0 || strcmp( ZENDDELIMITER, buf) != 0)
{
zerr( "garbled %s packet\n", ACTION_RSN);
}
}
#if _ANSI_DEFUN_
extern void handle_err( void)
#else
extern void handle_err()
#endif
{
#if DEBUG
FILE *mailStream;
Ushort try;
#endif
Ulong jobId = get_global_ulong( remoteglobal, SENDINGJOBIDPROMPT);
#if DEBUG
zerr( "Handling %s\n", ACTION_RSN);
#endif
if (read_jobfile_to_globs( global, jobId) == 0)
{
kill_job( jobId);
}
#if !DEBUG
mail_report_error( get_global_string( remoteglobal, REASONPROMPT));
#else
if ((mailStream = mail_open( "postmaster")) == NIL)
{
return;
}
/*
* The next fprintf is necessary, since some mail programs get confused
* by the header like contents of Zend messages. This forces us to go
* into body-mode.
*/
fprintf( mailStream, "\nZEND received error message:\n\n");
for (try=0; try<nrOfGlobalVariables; try++)
{
writeglobtostream( remoteglobal, remoteglobal[try].prompt, mailStream);
}
mail_close( mailStream);
#endif /* DEBUG */
}
#if _ANSI_DEFUN_
extern void mail_chunk( void)
#else
extern void mail_chunk()
#endif
{
char buf[PATHBUFSIZ];
FILE *mailStream;
FILE *chunkStream;
int number;
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR,
get_global_ulong( global, SENDINGJOBIDPROMPT),
(unsigned int)get_global_ushort( global, CHUNKNRPROMPT));
#if DEBUG
zerr( "Mail chunk %s\n", buf);
#endif
if ((chunkStream = fopen( buf, "r")) == NIL)
{
zerr( "Unable to read chunk %s\n", buf);
return;
}
if ((mailStream = mail_open( ZEND_ADDRESS)) == NIL)
{
return;
}
/*
* The next fprintf is necessary, since some mail programs get confused
* by the header like contents of Zend messages. This forces us to go
* into body-mode.
*/
fprintf( mailStream, "\n\n++++++\n\n");
writeglobtostream( global, SYSTEMNAMEPROMPT, mailStream);
writeglobtostream( global, ACTIONPROMPT, mailStream);
writeglobtostream( global, RECEIVINGJOBIDPROMPT, mailStream);
writeglobtostream( global, CHUNKNRPROMPT, mailStream);
writeglobtostream( global, NROFCHUNKSPROMPT, mailStream);
fprintf( mailStream, "%s\n", ZENDDELIMITER);
while ((number = fread( buf, sizeof(char), PATHBUFSIZ, chunkStream)) != 0)
{
if (fwrite( buf, sizeof( char), number, mailStream) != number)
{
zerr( "ERROR: failure copying chunk to mail\n");
break;
}
}
fprintf( mailStream, "%s\n", ZENDDELIMITER);
mail_close( mailStream);
}
#if _ANSI_DEFUN_
extern void mail_resend( void)
#else
extern void mail_resend()
#endif
{
char buf[PATHBUFSIZ];
FILE *mailStream;
Ulong jobId = get_global_ulong( global, SENDINGJOBIDPROMPT);
Ushort nrofchunks = get_global_ushort( global, NROFCHUNKSPROMPT);
Ushort try;
set_global( global, ACTIONPROMPT, ACTION_RSN);
#if DEBUG
zerr( "Mail message %s to zend at system %s\n",
ACTION_RSN, get_global_string( remoteglobal, SYSTEMNAMEPROMPT));
#endif
if ((mailStream = mail_open( ZEND_ADDRESS)) == NIL)
{
return;
}
/*
* The next fprintf is necessary, since some mail programs get confused
* by the header like contents of Zend messages. This forces us to go
* into body-mode.
*/
fprintf( mailStream, "\n\n++++++\n\n");
writeglobtostream( global, SYSTEMNAMEPROMPT, mailStream);
writeglobtostream( global, ACTIONPROMPT, mailStream);
writeglobtostream( global, SENDINGJOBIDPROMPT, mailStream);
fprintf( mailStream, "%s\n", ZENDDELIMITER);
for (try = 1; try <= nrofchunks; try++)
{
struct stat statBuf;
sprintf( buf, "%s/D.%lu/%05u", HOMEDIR, jobId, (unsigned int)try);
/*
* Build a list of chunk numbers that we want to have re-zent.
*/
#if 0
if (access( buf, F_OK) != 0)
#endif
if (stat( buf, &statBuf) != 0)
{
fprintf( mailStream, "%u\n", (unsigned int)try);
}
}
fprintf( mailStream, "%s\n", ZENDDELIMITER);
mail_close( mailStream);
}
#if _ANSI_DEFUN_
extern void mail_message( void)
#else
extern void mail_message()
#endif
{
char buf[PATHBUFSIZ];
FILE *mailStream;
char *action = get_global_string( global, ACTIONPROMPT);
#if DEBUG
zerr( "Mail message %s to zend at system %s\n",
action, get_global_string( remoteglobal, SYSTEMNAMEPROMPT));
#endif
if ((mailStream = mail_open( ZEND_ADDRESS)) == NIL)
{
if (strcmp( ACTION_AYT, action) == 0)
{
sprintf( buf, "%s/F.%lu", HOMEDIR,
get_global_ulong( global, SENDINGJOBIDPROMPT));
#if DEBUG
zerr( "Unlinking %s\n", buf);
#endif
if (unlink( buf) != 0)
{
zerr( "Unable to unlink copy of file %s\n", buf);
}
}
if (strcmp( ACTION_AYT, action) == 0 ||
strcmp( ACTION_UAR, action) == 0)
{
sprintf( buf, "%s/D.%lu", HOMEDIR,
get_global_ulong( global, SENDINGJOBIDPROMPT));
if (rmdir( buf) != 0)
{
zerr( "Unable to remove jobDir %s\n", buf);
}
}
return;
}
if (strcmp( ACTION_AYT, action) == 0)
{
FILE *tmpStream;
sprintf( buf, "%s/postmast.msg", HOMEDIR);
if ((tmpStream = fopen( buf, "r")) != NIL)
{
while (fgets( buf, PATHBUFSIZ, tmpStream))
{
fputs( buf, mailStream);
}
fclose( tmpStream);
}
#if DEBUG
zerr( "Postmaster message added.\n");
#endif
}
/*
* The next fprintf is necessary, since some mail programs get confused
* by the header like contents of Zend messages. This forces us to go
* into body-mode.
*/
fprintf( mailStream, "\n\n++++++\n\n");
writeglobtostream( global, ZENDIDPROMPT, mailStream);
writeglobtostream( global, SYSTEMNAMEPROMPT, mailStream);
writeglobtostream( global, ACTIONPROMPT, mailStream);
writeglobtostream( global, SENDINGJOBIDPROMPT, mailStream);
writeglobtostream( global, RECEIVINGJOBIDPROMPT, mailStream);
writeglobtostream( global, ROLEPROMPT, mailStream);
if (strcmp( ACTION_AYT, action) == 0)
{
writeglobtostream( global, FILEPROMPT, mailStream);
writeglobtostream( global, TYPEPROMPT, mailStream);
writeglobtostream( global, SENDINGUSERPROMPT, mailStream);
writeglobtostream( global, RECEIVINGUSERPROMPT, mailStream);
writeglobtostream( global, ZENDTRUESIZEPROMPT, mailStream);
writeglobtostream( global, ZENDSIZEPROMPT, mailStream);
writeglobtostream( global, COMPRESSEDPROMPT, mailStream);
writeglobtostream( global, PACKETTIMEOUTPROMPT, mailStream);
writeglobtostream( global, JOBTIMEOUTPROMPT, mailStream);
}
else if (strcmp( ACTION_UAR, action) == 0)
{
writeglobtostream( global, LINESPROMPT, mailStream);
writeglobtostream( global, JOBTIMEOUTPROMPT, mailStream);
}
else if (strcmp( ACTION_ACK, action) == 0)
{
writeglobtostream( global, CHUNKNRPROMPT, mailStream);
}
else if (strcmp( ACTION_ERR, action) == 0)
{
writeglobtostream( global, REASONPROMPT, mailStream);
}
fprintf( mailStream, "%s\n", ZENDDELIMITER);
mail_close( mailStream);
}
/*======================================================================
* $Log: zendhand.c,v $
* Revision 1.13 1993/02/21 13:07:09 gerben
* mail_err is global because we use it in zend.c
*
* Revision 1.12 1993/02/02 21:00:00 gerben
* *** empty log message ***
*
* Revision 1.12 1993/01/29 18:04:40 tom
* fix bug in sending empty mail body in mail_err().
*
* Revision 1.11 1993/01/28 18:54:26 tom
* allow zend to be installed setuid non-root. Plug some more security holes
* (environment; umask; subprogram execution as real user; be more careful with
* file access modes; read spoolfile through a pipe so user process does not
* have to access the spool directory); fix MAILTOPROMPT.
*
* Revision 1.10 1993/01/10 20:20:25 tom
* shell-quote user-supplied names; check filenames if tar'ed;
* Posixate access modes.
*
* Revision 1.9 1992/12/18 23:11:12 tom
* fix some non-ANSI C discrepancies; make receiving user own nameclash
* directory.
*
* Revision 1.8 1992/12/10 05:27:34 tom
* major cleanup to remove code duplication; plug security holes (see zend.c)
* add subject lines to user notification messages for easy identification.
*
*======================================================================*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.