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.