uudecode.c revision 103194
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1983, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3528564Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 4096438Smike#if 0 411590Srgrimes#ifndef lint 421590Srgrimesstatic char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; 4396438Smike#endif /* not lint */ 4428564Scharnier#endif 451590Srgrimes 4696438Smike#include <sys/cdefs.h> 4796438Smike__FBSDID("$FreeBSD: head/usr.bin/uudecode/uudecode.c 103194 2002-09-10 18:28:19Z fanf $"); 4896438Smike 491590Srgrimes/* 501590Srgrimes * uudecode [file ...] 511590Srgrimes * 521590Srgrimes * create the specified file, decoding as you go. 531590Srgrimes * used with uuencode. 541590Srgrimes */ 551590Srgrimes#include <sys/param.h> 5691661Sjmallett#include <sys/socket.h> 571590Srgrimes#include <sys/stat.h> 581590Srgrimes 5991661Sjmallett#include <netinet/in.h> 6091661Sjmallett 6128564Scharnier#include <err.h> 621590Srgrimes#include <pwd.h> 6391661Sjmallett#include <resolv.h> 641590Srgrimes#include <stdio.h> 6528564Scharnier#include <stdlib.h> 661590Srgrimes#include <string.h> 6728564Scharnier#include <unistd.h> 681590Srgrimes 6987304Sdwmaloneconst char *filename; 7089882Smikechar *outfile; 7189882Smikeint cflag, iflag, oflag, pflag, sflag; 721590Srgrimes 7392922Simpstatic void usage(void); 7492922Simpint decode(void); 7592922Simpint decode2(int); 7692922Simpvoid base64_decode(const char *); 7719078Swosch 781590Srgrimesint 7996386Salfredmain(int argc, char *argv[]) 801590Srgrimes{ 8119078Swosch int rval, ch; 821590Srgrimes 8389882Smike while ((ch = getopt(argc, argv, "cio:ps")) != -1) { 8419078Swosch switch(ch) { 8519078Swosch case 'c': 8689882Smike if (oflag) 8789882Smike usage(); 8819078Swosch cflag = 1; /* multiple uudecode'd files */ 8919078Swosch break; 9032780Swosch case 'i': 9132780Swosch iflag = 1; /* ask before override files */ 9232780Swosch break; 9389882Smike case 'o': 9489882Smike if (cflag || pflag || sflag) 9589882Smike usage(); 9689882Smike oflag = 1; /* output to the specified file */ 9789882Smike sflag = 1; /* do not strip pathnames for output */ 9889882Smike outfile = optarg; /* set the output filename */ 9989882Smike break; 10019078Swosch case 'p': 10189882Smike if (oflag) 10289882Smike usage(); 10319078Swosch pflag = 1; /* print output to stdout */ 10419078Swosch break; 10532780Swosch case 's': 10689882Smike if (oflag) 10789882Smike usage(); 10832780Swosch sflag = 1; /* do not strip pathnames for output */ 10932780Swosch break; 11019078Swosch default: 11128564Scharnier usage(); 11219078Swosch } 11319078Swosch } 11419078Swosch argc -= optind; 11519078Swosch argv += optind; 11619078Swosch 11719078Swosch if (*argv) { 1181590Srgrimes rval = 0; 1191590Srgrimes do { 1201590Srgrimes if (!freopen(filename = *argv, "r", stdin)) { 12128564Scharnier warn("%s", *argv); 1221590Srgrimes rval = 1; 1231590Srgrimes continue; 1241590Srgrimes } 1251590Srgrimes rval |= decode(); 1261590Srgrimes } while (*++argv); 1271590Srgrimes } else { 1281590Srgrimes filename = "stdin"; 1291590Srgrimes rval = decode(); 1301590Srgrimes } 1311590Srgrimes exit(rval); 1321590Srgrimes} 1331590Srgrimes 13419078Swoschint 13596438Smikedecode(void) 1361590Srgrimes{ 13719078Swosch int flag; 13819078Swosch 13919078Swosch /* decode only one file per input stream */ 140102890Sfanf if (!cflag) 14119078Swosch return(decode2(0)); 14219078Swosch 14319078Swosch /* multiple uudecode'd files */ 14419078Swosch for (flag = 0; ; flag++) 14519078Swosch if (decode2(flag)) 14619078Swosch return(1); 14719078Swosch else if (feof(stdin)) 14819078Swosch break; 14919078Swosch 15019078Swosch return(0); 15119078Swosch} 15219078Swosch 15319078Swoschint 15496438Smikedecode2(int flag) 15519078Swosch{ 1561590Srgrimes struct passwd *pw; 1571590Srgrimes register int n; 15858828Ssheldonh register char ch, *p; 15992623Sjmallett int base64, ignore, n1; 16092623Sjmallett char buf[MAXPATHLEN+1]; 16192623Sjmallett char buffn[MAXPATHLEN+1]; /* file name buffer */ 16292623Sjmallett char *mode, *s; 16392623Sjmallett void *mode_handle; 164103194Sfanf struct stat st; 1651590Srgrimes 16691661Sjmallett base64 = ignore = 0; 1671590Srgrimes /* search for header line */ 1681590Srgrimes do { 1691590Srgrimes if (!fgets(buf, sizeof(buf), stdin)) { 17019078Swosch if (flag) /* no error */ 17119078Swosch return(0); 17219078Swosch 17328564Scharnier warnx("%s: no \"begin\" line", filename); 1741590Srgrimes return(1); 1751590Srgrimes } 17691661Sjmallett } while (strncmp(buf, "begin", 5) != 0); 17722887Swosch 17891661Sjmallett if (strncmp(buf, "begin-base64", 12) == 0) 17991661Sjmallett base64 = 1; 18091661Sjmallett 18192623Sjmallett /* Parse the header: begin{,-base64} mode outfile. */ 18292623Sjmallett s = strtok(buf, " "); 18392623Sjmallett if (s == NULL) 18492623Sjmallett errx(1, "no mode or filename in input file"); 18592623Sjmallett s = strtok(NULL, " "); 18692623Sjmallett if (s == NULL) 18792623Sjmallett errx(1, "no mode in input file"); 18892623Sjmallett else { 18992623Sjmallett mode = strdup(s); 19092623Sjmallett if (mode == NULL) 19192623Sjmallett err(1, "strdup()"); 19291661Sjmallett } 19392623Sjmallett if (!oflag) { 19492637Sjmallett outfile = strtok(NULL, "\r\n"); 19592623Sjmallett if (outfile == NULL) 19692623Sjmallett errx(1, "no filename in input file"); 19792623Sjmallett } 1981590Srgrimes 19992623Sjmallett if (strlcpy(buf, outfile, sizeof(buf)) >= sizeof(buf)) 20092623Sjmallett errx(1, "%s: filename too long", outfile); 20132780Swosch if (!sflag && !pflag) { 202102890Sfanf strlcpy(buffn, buf, sizeof(buffn)); 20332780Swosch if (strrchr(buffn, '/') != NULL) 20432780Swosch strncpy(buf, strrchr(buffn, '/') + 1, sizeof(buf)); 20532780Swosch if (buf[0] == '\0') { 20632780Swosch warnx("%s: illegal filename", buffn); 20732780Swosch return(1); 20832780Swosch } 20932780Swosch 21092623Sjmallett /* handle ~user/file format */ 21192623Sjmallett if (buf[0] == '~') { 21292623Sjmallett if (!(p = index(buf, '/'))) { 21392623Sjmallett warnx("%s: illegal ~user", filename); 21492623Sjmallett return(1); 21592623Sjmallett } 21692623Sjmallett *p++ = '\0'; 21792623Sjmallett if (!(pw = getpwnam(buf + 1))) { 21892623Sjmallett warnx("%s: no user %s", filename, buf); 21992623Sjmallett return(1); 22092623Sjmallett } 22192623Sjmallett n = strlen(pw->pw_dir); 22292623Sjmallett n1 = strlen(p); 22392623Sjmallett if (n + n1 + 2 > MAXPATHLEN) { 22492623Sjmallett warnx("%s: path too long", filename); 22592623Sjmallett return(1); 22692623Sjmallett } 22792623Sjmallett bcopy(p, buf + n + 1, n1 + 1); 22892623Sjmallett bcopy(pw->pw_dir, buf, n); 22992623Sjmallett buf[n] = '/'; 2301590Srgrimes } 2311590Srgrimes } 2321590Srgrimes 2331590Srgrimes /* create output file, set mode */ 23419078Swosch if (pflag) 23519078Swosch ; /* print to stdout */ 23619078Swosch 23732780Swosch else { 23892623Sjmallett mode_handle = setmode(mode); 23992623Sjmallett if (mode_handle == NULL) 24092623Sjmallett err(1, "setmode()"); 24158666Ssheldonh if (iflag && !access(buf, F_OK)) { 24232780Swosch (void)fprintf(stderr, "not overwritten: %s\n", buf); 24358666Ssheldonh ignore++; 244103194Sfanf } else if (freopen(buf, "w", stdout) == NULL || 245103194Sfanf stat(buf, &st) < 0 || (S_ISREG(st.st_mode) && 246103194Sfanf fchmod(fileno(stdout), getmode(mode_handle, 0) & 0666))) { 24732780Swosch warn("%s: %s", buf, filename); 24832780Swosch return(1); 24932780Swosch } 25092623Sjmallett free(mode_handle); 25192623Sjmallett free(mode); 2521590Srgrimes } 25322887Swosch strcpy(buffn, buf); /* store file name from header line */ 2541590Srgrimes 2551590Srgrimes /* for each input line */ 25691661Sjmallettnext: 2571590Srgrimes for (;;) { 2581590Srgrimes if (!fgets(p = buf, sizeof(buf), stdin)) { 25928564Scharnier warnx("%s: short file", filename); 2601590Srgrimes return(1); 2611590Srgrimes } 26291661Sjmallett if (base64) { 26391661Sjmallett if (strncmp(buf, "====", 4) == 0) 26491661Sjmallett return (0); 26591661Sjmallett base64_decode(buf); 26691661Sjmallett goto next; 26791661Sjmallett } 2681590Srgrimes#define DEC(c) (((c) - ' ') & 077) /* single character decode */ 26924263Swosch#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) ) 27022887Swosch/* #define IS_DEC(c) (1) */ 27122887Swosch 27222887Swosch#define OUT_OF_RANGE \ 27322887Swosch{ \ 27428564Scharnier warnx( \ 27528564Scharnier"\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \ 27628564Scharnier filename, buffn, 1 + ' ', 077 + ' ' + 1); \ 27722887Swosch return(1); \ 27822887Swosch} 27958666Ssheldonh#define PUTCHAR(c) \ 28058666Ssheldonhif (!ignore) \ 28158666Ssheldonh putchar(c) 28222887Swosch 28322887Swosch 2841590Srgrimes /* 2851590Srgrimes * `n' is used to avoid writing out all the characters 2861590Srgrimes * at the end of the file. 2871590Srgrimes */ 2881590Srgrimes if ((n = DEC(*p)) <= 0) 2891590Srgrimes break; 2901590Srgrimes for (++p; n > 0; p += 4, n -= 3) 2911590Srgrimes if (n >= 3) { 292102890Sfanf if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 29322887Swosch IS_DEC(*(p + 2)) && IS_DEC(*(p + 3)))) 29422887Swosch OUT_OF_RANGE 29522887Swosch 2961590Srgrimes ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 29758666Ssheldonh PUTCHAR(ch); 2981590Srgrimes ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 29958666Ssheldonh PUTCHAR(ch); 3001590Srgrimes ch = DEC(p[2]) << 6 | DEC(p[3]); 30158666Ssheldonh PUTCHAR(ch); 3021590Srgrimes } 3031590Srgrimes else { 3041590Srgrimes if (n >= 1) { 30522887Swosch if (!(IS_DEC(*p) && IS_DEC(*(p + 1)))) 30622887Swosch OUT_OF_RANGE 3071590Srgrimes ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 30858666Ssheldonh PUTCHAR(ch); 3091590Srgrimes } 3101590Srgrimes if (n >= 2) { 311102890Sfanf if (!(IS_DEC(*(p + 1)) && 31222887Swosch IS_DEC(*(p + 2)))) 31322887Swosch OUT_OF_RANGE 31422887Swosch 3151590Srgrimes ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 31658666Ssheldonh PUTCHAR(ch); 3171590Srgrimes } 3181590Srgrimes if (n >= 3) { 319102890Sfanf if (!(IS_DEC(*(p + 2)) && 32022887Swosch IS_DEC(*(p + 3)))) 32122887Swosch OUT_OF_RANGE 3221590Srgrimes ch = DEC(p[2]) << 6 | DEC(p[3]); 32358666Ssheldonh PUTCHAR(ch); 3241590Srgrimes } 3251590Srgrimes } 3261590Srgrimes } 327102890Sfanf if (fgets(buf, sizeof(buf), stdin) == NULL || 32822894Swosch (strcmp(buf, "end") && strcmp(buf, "end\n") && 32922894Swosch strcmp(buf, "end\r\n"))) { 33028564Scharnier warnx("%s: no \"end\" line", filename); 3311590Srgrimes return(1); 3321590Srgrimes } 3331590Srgrimes return(0); 3341590Srgrimes} 3351590Srgrimes 33691661Sjmallettvoid 33796438Smikebase64_decode(const char *stream) 33891661Sjmallett{ 33991661Sjmallett unsigned char out[MAXPATHLEN * 4]; 34091661Sjmallett int rv; 34191661Sjmallett 34295101Sjmallett if (index(stream, '\r') != NULL) 34395101Sjmallett *index(stream, '\r') = '\0'; 34495101Sjmallett if (index(stream, '\n') != NULL) 34595101Sjmallett *index(stream, '\n') = '\0'; 34691661Sjmallett rv = b64_pton(stream, out, (sizeof(out) / sizeof(out[0]))); 34791661Sjmallett if (rv == -1) 34891661Sjmallett errx(1, "b64_pton: error decoding base64 input stream"); 34995103Sjmallett fwrite(out, 1, rv, stdout); 35091661Sjmallett} 35191661Sjmallett 35228564Scharnierstatic void 35396438Smikeusage(void) 3541590Srgrimes{ 35596943Sjmallett (void)fprintf(stderr, 35696943Sjmallett"usage: uudecode [-cips] [file ...]\n" 35796943Sjmallett" uudecode [-i] -o output_file [file]\n" 35896943Sjmallett" b64decode [-cips] [file ...]\n" 35996943Sjmallett" b64decode [-i] -o output_file [file]\n"); 3601590Srgrimes exit(1); 3611590Srgrimes} 362