Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!rutgers!iuvax!pur-ee!j.cc.purdue.edu!h.cc.purdue.edu!s.cc.purdue.edu!bryce%cogsci.Berkeley.EDU From: bryce%cogsci.Berkeley.EDU@ucbvax.Berkeley.EDU (Bryce Nesbitt) Newsgroups: comp.sources.amiga Subject: v02i020: secure uuencode and uudecode Message-ID: <905@s.cc.purdue.edu> Date: Tue, 8-Sep-87 14:08:25 EDT Article-I.D.: s.905 Posted: Tue Sep 8 14:08:25 1987 Date-Received: Wed, 9-Sep-87 07:29:22 EDT Sender: doc@s.cc.purdue.edu Followup-To: comp.sources.amiga Organization: Purdue University Computing Center Lines: 558 Approved: doc@s.cc.purdue.edu (Craig Norborg) Archive-Name: uucodes.src.sh This is the uuencode that will be used for this newsgroup unless otherwise noted. I have reviewed a couple of versions and have decided that this one is the most compatible with the current uuencode. Thanx to Bryce for his help on this! -Doc # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # uudecode.c # uuencode.c # uuencode.1 # This archive created: Tue Sep 8 13:00:35 1987 # By: Craig Norborg (Purdue University Computing Center) cat << \SHAR_EOF > uudecode.c /* #ifndef lint static char sccsid[] = "@(#)uudecode.c 5.3-1 (Berkeley) 4/10/85"; #endif */ /* Written by Mark Horton */ /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */ /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for compatibility */ /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix some very misleading error messages on the Amiga port, to fix a bug that prevented decoding certain files, to work even if trailing spaces have been removed from a file, to check the filesize (if present), to add some error checking, and to loop for multiple decodes from a single file. Also kludged around a missing string function in Aztec C */ /* * uudecode [input] * * Decode a file encoded with uuencode. */ #include #include #ifdef AMIGA #define AMIGA_LATTICE /* Set for Amiga Lattice C */ #define MCH_AMIGA #define MPU68000 #endif #ifdef unix #include #include #include #endif #define SUMSIZE 64 #define DEC(c) (((c) - ' ') & 077) /* single character decode */ main(argc, argv) char **argv; { FILE *in, *out; int through_loop=0; /* Dejavu indicator */ int mode; /* file's mode (from header) */ long filesize; /* theoretical file size (from header) */ char dest[128]; char buf[80]; #ifdef AMIGA_LATTICE extern int Enable_Abort; Enable_Abort=1; #endif /* A filename can be specified to be uudecoded, or nothing can be specified, and the input will come from STDIN */ switch (argc) { case 1: in=stdin; break; case 2: if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "ERROR: can't find %s\n", argv[1]); fprintf(stderr, "USAGE: uudecode [infile]\n"); exit(10); } break; default: fprintf(stderr, "USAGE: uudecode [infile]\n"); exit(11); break; } /* Loop through file, searching for headers. Decode anything with a header, complain if there where no headers. */ for (;;) { /* search file for header line */ for (;;) { if (fgets(buf, sizeof buf, in) == NULL) { if (!through_loop) { fprintf(stderr, "ERROR: no `begin' line!\n"); exit(12); } else { exit(0); } } if (strncmp(buf, "begin ", 6) == 0) break; } sscanf(buf, "begin %o %s", &mode, dest); #ifdef unix /* handle ~user/file format */ if (dest[0] == '~') { char *sl; struct passwd *getpwnam(); char *index(); struct passwd *user; char dnbuf[100]; sl = index(dest, '/'); if (sl == NULL) { fprintf(stderr, "Illegal ~user\n"); exit(13); } *sl++ = 0; user = getpwnam(dest+1); if (user == NULL) { fprintf(stderr, "No such user as %s\n", dest); exit(14); } strcpy(dnbuf, user->pw_dir); strcat(dnbuf, "/"); strcat(dnbuf, sl); strcpy(dest, dnbuf); } #endif /* create output file */ if ((out = fopen(dest, "w")) == NULL) { fprintf(stderr, "ERROR: can't open output file %s\n", dest); exit(15); } #ifdef unix chmod(dest, mode); #endif decode(in, out, dest); if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3)) { /* don't be overly picky about newline ^ */ fprintf(stderr, "ERROR: no `end' line\n"); exit(16); } if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3))) { sscanf(buf, "size %ld", &filesize); if (ftell(out) != filesize) { fprintf(stderr, "ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out)); exit(17); } } through_loop = 1; } /* forever */ } /* main */ /* * Copy from in to out, decoding as you go. * If a return or newline is encountered too early in a line, it is * assumed that means that some editor has truncated trailing spaces. */ decode(in, out, dest) FILE *in; FILE *out; char *dest; { char buf[80]; char *bp; int nosum=0; #ifndef unix extern errno; #endif register int j; register int n; int checksum, line; for (line = 1; ; line++) /* for each input line */ { if (fgets(buf, sizeof buf, in) == NULL) { fprintf(stderr, "ERROR: input ended unexpectedly!\n"); exit(18); } /* Pad end of lines in case some editor truncated trailing spaces */ for (n=0;n<79;n++) /* search for first \r, \n or \000 */ { if(buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000') break; } for (;n<79;n++) /* when found, fill rest of line with space */ { buf[n]=' '; } buf[79]=0; /* terminate new string */ checksum = 0; n = DEC(buf[0]); if (n <= 0) break; /* 0 bytes on a line?? Must be the last line */ bp = &buf[1]; /* FOUR input characters go into each THREE output charcters */ while (n >= 4) { j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j; j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j; j = DEC(bp[2]) << 6 | DEC(bp[3]); putc(j, out); checksum += j; checksum = checksum % SUMSIZE; bp += 4; n -= 3; } j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; checksum += j; if (n >= 1) putc(j, out); j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; checksum += j; if (n >= 2) putc(j, out); j = DEC(bp[2]) << 6 | DEC(bp[3]); checksum += j; if (n >= 3) putc(j, out); checksum = checksum % SUMSIZE; bp += 4; n -= 3; #ifndef unix /* Error checking under UNIX??? You must be kidding... */ /* Check if an error occured while writing to that last line */ if (errno) { fprintf(stderr, "ERROR: error writing to %s\n",dest); exit(19); } #endif /* The line has been decoded; now check that sum */ nosum |= !isspace(*bp); if (nosum) /* Is there a checksum at all?? */ { if (checksum != DEC(*bp)) /* Does that checksum match? */ { fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line); } } /* sum */ } /* line */ } /* function */ #ifdef unix /* * Return the ptr in sp at which the character c appears; * 0 if not found */ char * index(sp, c) register char *sp, c; { do { if (*sp == c) return(sp); } while (*sp++); return(0); } #endif unix SHAR_EOF cat << \SHAR_EOF > uuencode.c /* #ifndef lint static char sccsid[] = "@(#)uuencode.c 5.3-1 (Berkeley) 1/22/85"; #endif */ /* Written by Mark Horton */ /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */ /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for compatibility */ /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a very misleading error message on the Amiga port, enable CTRL-C for LATTICE, and add a transparant file size trailer for later check. */ /* * uuencode >outfile infile name * * Encode a file so it can be mailed to a remote system. This version * transparantly adds line checksums and a file size for sanity checks. * */ #include #ifdef AMIGA #define AMIGA_LATTICE /* Set for Amiga Lattice C */ #define MCH_AMIGA #define MPU68000 #endif #ifdef unix #include #include #endif #define SUMSIZE 64 /* 6 bits */ /* ENC is the basic 1 character encode function to make a char printing */ /* Each output character represents 6 bits of input */ #define ENC(c) ((c) ? ((c) & 077) + ' ': '`') long totalsize=0; /* Used to count the file size because ftell() does not return sane results for pipes */ main(argc, argv) char **argv; { FILE *in; int mode; #ifdef unix struct stat sbuf; #endif #ifdef AMIGA_LATTICE extern int Enable_Abort; /* Enable CTRL-C for Lattice */ Enable_Abort=1; #endif /* optional 1st argument */ if (argc > 2) { if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "ERROR: can't find %s\n", argv[1]); fprintf(stderr, "USAGE: uuencode >outfile infile name\n"); exit(10); } argv++; argc--; } else in = stdin; if (argc != 2) { fprintf(stderr, "USAGE: uuencode >outfile infile name\n"); exit(11); } #ifdef unix /* figure out the input file mode */ fstat(fileno(in), &sbuf); mode = sbuf.st_mode & 0777; #else mode = 0644; /* Default permissions */ #endif printf("\nbegin %o %s\n", mode, argv[1]); encode(in, stdout); printf("end\n"); printf("size %ld\n",totalsize); exit(0); } /* * copy from in to out, encoding as you go along. */ encode(in, out) FILE *in; FILE *out; { #ifndef unix extern errno; #endif char buf[80]; int i, n, checksum; for (;;) { /* 1 (up to) 45 character line */ n = fr(in, buf, 45); putc(ENC(n), out); checksum = 0; for (i=0; i> 2; c2 = (*p << 4) & 060 | (p[1] >> 4) & 017; c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03; c4 = p[2] & 077; putc(ENC(c1), f); putc(ENC(c2), f); putc(ENC(c3), f); putc(ENC(c4), f); return((p[0]+p[1]+p[2]) % SUMSIZE); } /* fr: like read but stdio */ int fr(fd, buf, cnt) FILE *fd; char *buf; int cnt; { int c, i; for (i=0; i uuencode.1 .TH UUENCODE 1 "17 July 1987" .UC 4 .SH NAME uuencode,uudecode \- encode/decode a binary file for transmission via (plain text) mail .SH SYNOPSIS .B uuencode [source] remotedest | .B mail sys1!sys2!..!decode .br .B uuencode >outfile.uue source remotedest .br .B uuencode >outfile.uue