1*47bcbde9SPiotr Pawel Stefaniak /*- 2*47bcbde9SPiotr Pawel Stefaniak * SPDX-License-Identifier: BSD-3-Clause 3*47bcbde9SPiotr Pawel Stefaniak * 4*47bcbde9SPiotr Pawel Stefaniak * Copyright (c) 1983, 1993 5*47bcbde9SPiotr Pawel Stefaniak * The Regents of the University of California. All rights reserved. 6*47bcbde9SPiotr Pawel Stefaniak * 7*47bcbde9SPiotr Pawel Stefaniak * Redistribution and use in source and binary forms, with or without 8*47bcbde9SPiotr Pawel Stefaniak * modification, are permitted provided that the following conditions 9*47bcbde9SPiotr Pawel Stefaniak * are met: 10*47bcbde9SPiotr Pawel Stefaniak * 1. Redistributions of source code must retain the above copyright 11*47bcbde9SPiotr Pawel Stefaniak * notice, this list of conditions and the following disclaimer. 12*47bcbde9SPiotr Pawel Stefaniak * 2. Redistributions in binary form must reproduce the above copyright 13*47bcbde9SPiotr Pawel Stefaniak * notice, this list of conditions and the following disclaimer in the 14*47bcbde9SPiotr Pawel Stefaniak * documentation and/or other materials provided with the distribution. 15*47bcbde9SPiotr Pawel Stefaniak * 3. Neither the name of the University nor the names of its contributors 16*47bcbde9SPiotr Pawel Stefaniak * may be used to endorse or promote products derived from this software 17*47bcbde9SPiotr Pawel Stefaniak * without specific prior written permission. 18*47bcbde9SPiotr Pawel Stefaniak * 19*47bcbde9SPiotr Pawel Stefaniak * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20*47bcbde9SPiotr Pawel Stefaniak * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*47bcbde9SPiotr Pawel Stefaniak * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*47bcbde9SPiotr Pawel Stefaniak * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23*47bcbde9SPiotr Pawel Stefaniak * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*47bcbde9SPiotr Pawel Stefaniak * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*47bcbde9SPiotr Pawel Stefaniak * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*47bcbde9SPiotr Pawel Stefaniak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*47bcbde9SPiotr Pawel Stefaniak * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*47bcbde9SPiotr Pawel Stefaniak * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29*47bcbde9SPiotr Pawel Stefaniak * SUCH DAMAGE. 30*47bcbde9SPiotr Pawel Stefaniak */ 31*47bcbde9SPiotr Pawel Stefaniak 32*47bcbde9SPiotr Pawel Stefaniak #if 0 33*47bcbde9SPiotr Pawel Stefaniak #ifndef lint 34*47bcbde9SPiotr Pawel Stefaniak static const char copyright[] = 35*47bcbde9SPiotr Pawel Stefaniak "@(#) Copyright (c) 1983, 1993\n\ 36*47bcbde9SPiotr Pawel Stefaniak The Regents of the University of California. All rights reserved.\n"; 37*47bcbde9SPiotr Pawel Stefaniak #endif /* not lint */ 38*47bcbde9SPiotr Pawel Stefaniak 39*47bcbde9SPiotr Pawel Stefaniak #ifndef lint 40*47bcbde9SPiotr Pawel Stefaniak static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; 41*47bcbde9SPiotr Pawel Stefaniak #endif /* not lint */ 42*47bcbde9SPiotr Pawel Stefaniak #endif 43*47bcbde9SPiotr Pawel Stefaniak #include <sys/cdefs.h> 44*47bcbde9SPiotr Pawel Stefaniak __FBSDID("$FreeBSD$"); 45*47bcbde9SPiotr Pawel Stefaniak 46*47bcbde9SPiotr Pawel Stefaniak /* 47*47bcbde9SPiotr Pawel Stefaniak * uudecode [file ...] 48*47bcbde9SPiotr Pawel Stefaniak * 49*47bcbde9SPiotr Pawel Stefaniak * create the specified file, decoding as you go. 50*47bcbde9SPiotr Pawel Stefaniak * used with uuencode. 51*47bcbde9SPiotr Pawel Stefaniak */ 52*47bcbde9SPiotr Pawel Stefaniak #include <sys/param.h> 53*47bcbde9SPiotr Pawel Stefaniak #include <sys/socket.h> 54*47bcbde9SPiotr Pawel Stefaniak #include <sys/stat.h> 55*47bcbde9SPiotr Pawel Stefaniak 56*47bcbde9SPiotr Pawel Stefaniak #include <netinet/in.h> 57*47bcbde9SPiotr Pawel Stefaniak 58*47bcbde9SPiotr Pawel Stefaniak #include <ctype.h> 59*47bcbde9SPiotr Pawel Stefaniak #include <err.h> 60*47bcbde9SPiotr Pawel Stefaniak #include <errno.h> 61*47bcbde9SPiotr Pawel Stefaniak #include <fcntl.h> 62*47bcbde9SPiotr Pawel Stefaniak #include <libgen.h> 63*47bcbde9SPiotr Pawel Stefaniak #include <pwd.h> 64*47bcbde9SPiotr Pawel Stefaniak #include <resolv.h> 65*47bcbde9SPiotr Pawel Stefaniak #include <stdbool.h> 66*47bcbde9SPiotr Pawel Stefaniak #include <stdio.h> 67*47bcbde9SPiotr Pawel Stefaniak #include <stdlib.h> 68*47bcbde9SPiotr Pawel Stefaniak #include <string.h> 69*47bcbde9SPiotr Pawel Stefaniak #include <unistd.h> 70*47bcbde9SPiotr Pawel Stefaniak 71*47bcbde9SPiotr Pawel Stefaniak extern int main_decode(int, char *[]); 72*47bcbde9SPiotr Pawel Stefaniak 73*47bcbde9SPiotr Pawel Stefaniak static const char *infile, *outfile; 74*47bcbde9SPiotr Pawel Stefaniak static FILE *infp, *outfp; 75*47bcbde9SPiotr Pawel Stefaniak static bool base64, cflag, iflag, oflag, pflag, rflag, sflag; 76*47bcbde9SPiotr Pawel Stefaniak 77*47bcbde9SPiotr Pawel Stefaniak static void usage(void); 78*47bcbde9SPiotr Pawel Stefaniak static int decode(void); 79*47bcbde9SPiotr Pawel Stefaniak static int decode2(void); 80*47bcbde9SPiotr Pawel Stefaniak static int uu_decode(void); 81*47bcbde9SPiotr Pawel Stefaniak static int base64_decode(void); 82*47bcbde9SPiotr Pawel Stefaniak 83*47bcbde9SPiotr Pawel Stefaniak int 84*47bcbde9SPiotr Pawel Stefaniak main_decode(int argc, char *argv[]) 85*47bcbde9SPiotr Pawel Stefaniak { 86*47bcbde9SPiotr Pawel Stefaniak int rval, ch; 87*47bcbde9SPiotr Pawel Stefaniak 88*47bcbde9SPiotr Pawel Stefaniak if (strcmp(basename(argv[0]), "b64decode") == 0) 89*47bcbde9SPiotr Pawel Stefaniak base64 = true; 90*47bcbde9SPiotr Pawel Stefaniak 91*47bcbde9SPiotr Pawel Stefaniak while ((ch = getopt(argc, argv, "cimo:prs")) != -1) { 92*47bcbde9SPiotr Pawel Stefaniak switch (ch) { 93*47bcbde9SPiotr Pawel Stefaniak case 'c': 94*47bcbde9SPiotr Pawel Stefaniak if (oflag || rflag) 95*47bcbde9SPiotr Pawel Stefaniak usage(); 96*47bcbde9SPiotr Pawel Stefaniak cflag = true; /* multiple uudecode'd files */ 97*47bcbde9SPiotr Pawel Stefaniak break; 98*47bcbde9SPiotr Pawel Stefaniak case 'i': 99*47bcbde9SPiotr Pawel Stefaniak iflag = true; /* ask before override files */ 100*47bcbde9SPiotr Pawel Stefaniak break; 101*47bcbde9SPiotr Pawel Stefaniak case 'm': 102*47bcbde9SPiotr Pawel Stefaniak base64 = true; 103*47bcbde9SPiotr Pawel Stefaniak break; 104*47bcbde9SPiotr Pawel Stefaniak case 'o': 105*47bcbde9SPiotr Pawel Stefaniak if (cflag || pflag || rflag || sflag) 106*47bcbde9SPiotr Pawel Stefaniak usage(); 107*47bcbde9SPiotr Pawel Stefaniak oflag = true; /* output to the specified file */ 108*47bcbde9SPiotr Pawel Stefaniak sflag = true; /* do not strip pathnames for output */ 109*47bcbde9SPiotr Pawel Stefaniak outfile = optarg; /* set the output filename */ 110*47bcbde9SPiotr Pawel Stefaniak break; 111*47bcbde9SPiotr Pawel Stefaniak case 'p': 112*47bcbde9SPiotr Pawel Stefaniak if (oflag) 113*47bcbde9SPiotr Pawel Stefaniak usage(); 114*47bcbde9SPiotr Pawel Stefaniak pflag = true; /* print output to stdout */ 115*47bcbde9SPiotr Pawel Stefaniak break; 116*47bcbde9SPiotr Pawel Stefaniak case 'r': 117*47bcbde9SPiotr Pawel Stefaniak if (cflag || oflag) 118*47bcbde9SPiotr Pawel Stefaniak usage(); 119*47bcbde9SPiotr Pawel Stefaniak rflag = true; /* decode raw data */ 120*47bcbde9SPiotr Pawel Stefaniak break; 121*47bcbde9SPiotr Pawel Stefaniak case 's': 122*47bcbde9SPiotr Pawel Stefaniak if (oflag) 123*47bcbde9SPiotr Pawel Stefaniak usage(); 124*47bcbde9SPiotr Pawel Stefaniak sflag = true; /* do not strip pathnames for output */ 125*47bcbde9SPiotr Pawel Stefaniak break; 126*47bcbde9SPiotr Pawel Stefaniak default: 127*47bcbde9SPiotr Pawel Stefaniak usage(); 128*47bcbde9SPiotr Pawel Stefaniak } 129*47bcbde9SPiotr Pawel Stefaniak } 130*47bcbde9SPiotr Pawel Stefaniak argc -= optind; 131*47bcbde9SPiotr Pawel Stefaniak argv += optind; 132*47bcbde9SPiotr Pawel Stefaniak 133*47bcbde9SPiotr Pawel Stefaniak if (*argv != NULL) { 134*47bcbde9SPiotr Pawel Stefaniak rval = 0; 135*47bcbde9SPiotr Pawel Stefaniak do { 136*47bcbde9SPiotr Pawel Stefaniak infp = fopen(infile = *argv, "r"); 137*47bcbde9SPiotr Pawel Stefaniak if (infp == NULL) { 138*47bcbde9SPiotr Pawel Stefaniak warn("%s", *argv); 139*47bcbde9SPiotr Pawel Stefaniak rval = 1; 140*47bcbde9SPiotr Pawel Stefaniak continue; 141*47bcbde9SPiotr Pawel Stefaniak } 142*47bcbde9SPiotr Pawel Stefaniak rval |= decode(); 143*47bcbde9SPiotr Pawel Stefaniak fclose(infp); 144*47bcbde9SPiotr Pawel Stefaniak } while (*++argv); 145*47bcbde9SPiotr Pawel Stefaniak } else { 146*47bcbde9SPiotr Pawel Stefaniak infile = "stdin"; 147*47bcbde9SPiotr Pawel Stefaniak infp = stdin; 148*47bcbde9SPiotr Pawel Stefaniak rval = decode(); 149*47bcbde9SPiotr Pawel Stefaniak } 150*47bcbde9SPiotr Pawel Stefaniak exit(rval); 151*47bcbde9SPiotr Pawel Stefaniak } 152*47bcbde9SPiotr Pawel Stefaniak 153*47bcbde9SPiotr Pawel Stefaniak static int 154*47bcbde9SPiotr Pawel Stefaniak decode(void) 155*47bcbde9SPiotr Pawel Stefaniak { 156*47bcbde9SPiotr Pawel Stefaniak int r, v; 157*47bcbde9SPiotr Pawel Stefaniak 158*47bcbde9SPiotr Pawel Stefaniak if (rflag) { 159*47bcbde9SPiotr Pawel Stefaniak /* relaxed alternative to decode2() */ 160*47bcbde9SPiotr Pawel Stefaniak outfile = "/dev/stdout"; 161*47bcbde9SPiotr Pawel Stefaniak outfp = stdout; 162*47bcbde9SPiotr Pawel Stefaniak if (base64) 163*47bcbde9SPiotr Pawel Stefaniak return (base64_decode()); 164*47bcbde9SPiotr Pawel Stefaniak else 165*47bcbde9SPiotr Pawel Stefaniak return (uu_decode()); 166*47bcbde9SPiotr Pawel Stefaniak } 167*47bcbde9SPiotr Pawel Stefaniak v = decode2(); 168*47bcbde9SPiotr Pawel Stefaniak if (v == EOF) { 169*47bcbde9SPiotr Pawel Stefaniak warnx("%s: missing or bad \"begin\" line", infile); 170*47bcbde9SPiotr Pawel Stefaniak return (1); 171*47bcbde9SPiotr Pawel Stefaniak } 172*47bcbde9SPiotr Pawel Stefaniak for (r = v; cflag; r |= v) { 173*47bcbde9SPiotr Pawel Stefaniak v = decode2(); 174*47bcbde9SPiotr Pawel Stefaniak if (v == EOF) 175*47bcbde9SPiotr Pawel Stefaniak break; 176*47bcbde9SPiotr Pawel Stefaniak } 177*47bcbde9SPiotr Pawel Stefaniak return (r); 178*47bcbde9SPiotr Pawel Stefaniak } 179*47bcbde9SPiotr Pawel Stefaniak 180*47bcbde9SPiotr Pawel Stefaniak static int 181*47bcbde9SPiotr Pawel Stefaniak decode2(void) 182*47bcbde9SPiotr Pawel Stefaniak { 183*47bcbde9SPiotr Pawel Stefaniak int flags, fd, mode; 184*47bcbde9SPiotr Pawel Stefaniak size_t n, m; 185*47bcbde9SPiotr Pawel Stefaniak char *p, *q; 186*47bcbde9SPiotr Pawel Stefaniak void *handle; 187*47bcbde9SPiotr Pawel Stefaniak struct passwd *pw; 188*47bcbde9SPiotr Pawel Stefaniak struct stat st; 189*47bcbde9SPiotr Pawel Stefaniak char buf[MAXPATHLEN + 1]; 190*47bcbde9SPiotr Pawel Stefaniak 191*47bcbde9SPiotr Pawel Stefaniak base64 = false; 192*47bcbde9SPiotr Pawel Stefaniak /* search for header line */ 193*47bcbde9SPiotr Pawel Stefaniak for (;;) { 194*47bcbde9SPiotr Pawel Stefaniak if (fgets(buf, sizeof(buf), infp) == NULL) 195*47bcbde9SPiotr Pawel Stefaniak return (EOF); 196*47bcbde9SPiotr Pawel Stefaniak p = buf; 197*47bcbde9SPiotr Pawel Stefaniak if (strncmp(p, "begin-base64 ", 13) == 0) { 198*47bcbde9SPiotr Pawel Stefaniak base64 = true; 199*47bcbde9SPiotr Pawel Stefaniak p += 13; 200*47bcbde9SPiotr Pawel Stefaniak } else if (strncmp(p, "begin ", 6) == 0) 201*47bcbde9SPiotr Pawel Stefaniak p += 6; 202*47bcbde9SPiotr Pawel Stefaniak else 203*47bcbde9SPiotr Pawel Stefaniak continue; 204*47bcbde9SPiotr Pawel Stefaniak /* p points to mode */ 205*47bcbde9SPiotr Pawel Stefaniak q = strchr(p, ' '); 206*47bcbde9SPiotr Pawel Stefaniak if (q == NULL) 207*47bcbde9SPiotr Pawel Stefaniak continue; 208*47bcbde9SPiotr Pawel Stefaniak *q++ = '\0'; 209*47bcbde9SPiotr Pawel Stefaniak /* q points to filename */ 210*47bcbde9SPiotr Pawel Stefaniak n = strlen(q); 211*47bcbde9SPiotr Pawel Stefaniak while (n > 0 && (q[n-1] == '\n' || q[n-1] == '\r')) 212*47bcbde9SPiotr Pawel Stefaniak q[--n] = '\0'; 213*47bcbde9SPiotr Pawel Stefaniak /* found valid header? */ 214*47bcbde9SPiotr Pawel Stefaniak if (n > 0) 215*47bcbde9SPiotr Pawel Stefaniak break; 216*47bcbde9SPiotr Pawel Stefaniak } 217*47bcbde9SPiotr Pawel Stefaniak 218*47bcbde9SPiotr Pawel Stefaniak handle = setmode(p); 219*47bcbde9SPiotr Pawel Stefaniak if (handle == NULL) { 220*47bcbde9SPiotr Pawel Stefaniak warnx("%s: unable to parse file mode", infile); 221*47bcbde9SPiotr Pawel Stefaniak return (1); 222*47bcbde9SPiotr Pawel Stefaniak } 223*47bcbde9SPiotr Pawel Stefaniak mode = getmode(handle, 0) & 0666; 224*47bcbde9SPiotr Pawel Stefaniak free(handle); 225*47bcbde9SPiotr Pawel Stefaniak 226*47bcbde9SPiotr Pawel Stefaniak if (sflag) { 227*47bcbde9SPiotr Pawel Stefaniak /* don't strip, so try ~user/file expansion */ 228*47bcbde9SPiotr Pawel Stefaniak p = NULL; 229*47bcbde9SPiotr Pawel Stefaniak pw = NULL; 230*47bcbde9SPiotr Pawel Stefaniak if (*q == '~') 231*47bcbde9SPiotr Pawel Stefaniak p = strchr(q, '/'); 232*47bcbde9SPiotr Pawel Stefaniak if (p != NULL) { 233*47bcbde9SPiotr Pawel Stefaniak *p = '\0'; 234*47bcbde9SPiotr Pawel Stefaniak pw = getpwnam(q + 1); 235*47bcbde9SPiotr Pawel Stefaniak *p = '/'; 236*47bcbde9SPiotr Pawel Stefaniak } 237*47bcbde9SPiotr Pawel Stefaniak if (pw != NULL) { 238*47bcbde9SPiotr Pawel Stefaniak n = strlen(pw->pw_dir); 239*47bcbde9SPiotr Pawel Stefaniak if (buf + n > p) { 240*47bcbde9SPiotr Pawel Stefaniak /* make room */ 241*47bcbde9SPiotr Pawel Stefaniak m = strlen(p); 242*47bcbde9SPiotr Pawel Stefaniak if (sizeof(buf) < n + m) { 243*47bcbde9SPiotr Pawel Stefaniak warnx("%s: bad output filename", 244*47bcbde9SPiotr Pawel Stefaniak infile); 245*47bcbde9SPiotr Pawel Stefaniak return (1); 246*47bcbde9SPiotr Pawel Stefaniak } 247*47bcbde9SPiotr Pawel Stefaniak p = memmove(buf + n, p, m); 248*47bcbde9SPiotr Pawel Stefaniak } 249*47bcbde9SPiotr Pawel Stefaniak q = memcpy(p - n, pw->pw_dir, n); 250*47bcbde9SPiotr Pawel Stefaniak } 251*47bcbde9SPiotr Pawel Stefaniak } else { 252*47bcbde9SPiotr Pawel Stefaniak /* strip down to leaf name */ 253*47bcbde9SPiotr Pawel Stefaniak p = strrchr(q, '/'); 254*47bcbde9SPiotr Pawel Stefaniak if (p != NULL) 255*47bcbde9SPiotr Pawel Stefaniak q = p + 1; 256*47bcbde9SPiotr Pawel Stefaniak } 257*47bcbde9SPiotr Pawel Stefaniak if (!oflag) 258*47bcbde9SPiotr Pawel Stefaniak outfile = q; 259*47bcbde9SPiotr Pawel Stefaniak 260*47bcbde9SPiotr Pawel Stefaniak /* POSIX says "/dev/stdout" is a 'magic cookie' not a special file. */ 261*47bcbde9SPiotr Pawel Stefaniak if (pflag || strcmp(outfile, "/dev/stdout") == 0) 262*47bcbde9SPiotr Pawel Stefaniak outfp = stdout; 263*47bcbde9SPiotr Pawel Stefaniak else { 264*47bcbde9SPiotr Pawel Stefaniak flags = O_WRONLY | O_CREAT | O_EXCL; 265*47bcbde9SPiotr Pawel Stefaniak if (lstat(outfile, &st) == 0) { 266*47bcbde9SPiotr Pawel Stefaniak if (iflag) { 267*47bcbde9SPiotr Pawel Stefaniak warnc(EEXIST, "%s: %s", infile, outfile); 268*47bcbde9SPiotr Pawel Stefaniak return (0); 269*47bcbde9SPiotr Pawel Stefaniak } 270*47bcbde9SPiotr Pawel Stefaniak switch (st.st_mode & S_IFMT) { 271*47bcbde9SPiotr Pawel Stefaniak case S_IFREG: 272*47bcbde9SPiotr Pawel Stefaniak case S_IFLNK: 273*47bcbde9SPiotr Pawel Stefaniak /* avoid symlink attacks */ 274*47bcbde9SPiotr Pawel Stefaniak if (unlink(outfile) == 0 || errno == ENOENT) 275*47bcbde9SPiotr Pawel Stefaniak break; 276*47bcbde9SPiotr Pawel Stefaniak warn("%s: unlink %s", infile, outfile); 277*47bcbde9SPiotr Pawel Stefaniak return (1); 278*47bcbde9SPiotr Pawel Stefaniak case S_IFDIR: 279*47bcbde9SPiotr Pawel Stefaniak warnc(EISDIR, "%s: %s", infile, outfile); 280*47bcbde9SPiotr Pawel Stefaniak return (1); 281*47bcbde9SPiotr Pawel Stefaniak default: 282*47bcbde9SPiotr Pawel Stefaniak if (oflag) { 283*47bcbde9SPiotr Pawel Stefaniak /* trust command-line names */ 284*47bcbde9SPiotr Pawel Stefaniak flags &= ~O_EXCL; 285*47bcbde9SPiotr Pawel Stefaniak break; 286*47bcbde9SPiotr Pawel Stefaniak } 287*47bcbde9SPiotr Pawel Stefaniak warnc(EEXIST, "%s: %s", infile, outfile); 288*47bcbde9SPiotr Pawel Stefaniak return (1); 289*47bcbde9SPiotr Pawel Stefaniak } 290*47bcbde9SPiotr Pawel Stefaniak } else if (errno != ENOENT) { 291*47bcbde9SPiotr Pawel Stefaniak warn("%s: %s", infile, outfile); 292*47bcbde9SPiotr Pawel Stefaniak return (1); 293*47bcbde9SPiotr Pawel Stefaniak } 294*47bcbde9SPiotr Pawel Stefaniak if ((fd = open(outfile, flags, mode)) < 0 || 295*47bcbde9SPiotr Pawel Stefaniak (outfp = fdopen(fd, "w")) == NULL) { 296*47bcbde9SPiotr Pawel Stefaniak warn("%s: %s", infile, outfile); 297*47bcbde9SPiotr Pawel Stefaniak return (1); 298*47bcbde9SPiotr Pawel Stefaniak } 299*47bcbde9SPiotr Pawel Stefaniak } 300*47bcbde9SPiotr Pawel Stefaniak 301*47bcbde9SPiotr Pawel Stefaniak if (base64) 302*47bcbde9SPiotr Pawel Stefaniak return (base64_decode()); 303*47bcbde9SPiotr Pawel Stefaniak else 304*47bcbde9SPiotr Pawel Stefaniak return (uu_decode()); 305*47bcbde9SPiotr Pawel Stefaniak } 306*47bcbde9SPiotr Pawel Stefaniak 307*47bcbde9SPiotr Pawel Stefaniak static int 308*47bcbde9SPiotr Pawel Stefaniak get_line(char *buf, size_t size) 309*47bcbde9SPiotr Pawel Stefaniak { 310*47bcbde9SPiotr Pawel Stefaniak 311*47bcbde9SPiotr Pawel Stefaniak if (fgets(buf, size, infp) != NULL) 312*47bcbde9SPiotr Pawel Stefaniak return (2); 313*47bcbde9SPiotr Pawel Stefaniak if (rflag) 314*47bcbde9SPiotr Pawel Stefaniak return (0); 315*47bcbde9SPiotr Pawel Stefaniak warnx("%s: %s: short file", infile, outfile); 316*47bcbde9SPiotr Pawel Stefaniak return (1); 317*47bcbde9SPiotr Pawel Stefaniak } 318*47bcbde9SPiotr Pawel Stefaniak 319*47bcbde9SPiotr Pawel Stefaniak static int 320*47bcbde9SPiotr Pawel Stefaniak checkend(const char *ptr, const char *end, const char *msg) 321*47bcbde9SPiotr Pawel Stefaniak { 322*47bcbde9SPiotr Pawel Stefaniak size_t n; 323*47bcbde9SPiotr Pawel Stefaniak 324*47bcbde9SPiotr Pawel Stefaniak n = strlen(end); 325*47bcbde9SPiotr Pawel Stefaniak if (strncmp(ptr, end, n) != 0 || 326*47bcbde9SPiotr Pawel Stefaniak strspn(ptr + n, " \t\r\n") != strlen(ptr + n)) { 327*47bcbde9SPiotr Pawel Stefaniak warnx("%s: %s: %s", infile, outfile, msg); 328*47bcbde9SPiotr Pawel Stefaniak return (1); 329*47bcbde9SPiotr Pawel Stefaniak } 330*47bcbde9SPiotr Pawel Stefaniak if (fclose(outfp) != 0) { 331*47bcbde9SPiotr Pawel Stefaniak warn("%s: %s", infile, outfile); 332*47bcbde9SPiotr Pawel Stefaniak return (1); 333*47bcbde9SPiotr Pawel Stefaniak } 334*47bcbde9SPiotr Pawel Stefaniak return (0); 335*47bcbde9SPiotr Pawel Stefaniak } 336*47bcbde9SPiotr Pawel Stefaniak 337*47bcbde9SPiotr Pawel Stefaniak static int 338*47bcbde9SPiotr Pawel Stefaniak uu_decode(void) 339*47bcbde9SPiotr Pawel Stefaniak { 340*47bcbde9SPiotr Pawel Stefaniak int i, ch; 341*47bcbde9SPiotr Pawel Stefaniak char *p; 342*47bcbde9SPiotr Pawel Stefaniak char buf[MAXPATHLEN+1]; 343*47bcbde9SPiotr Pawel Stefaniak 344*47bcbde9SPiotr Pawel Stefaniak /* for each input line */ 345*47bcbde9SPiotr Pawel Stefaniak for (;;) { 346*47bcbde9SPiotr Pawel Stefaniak switch (get_line(buf, sizeof(buf))) { 347*47bcbde9SPiotr Pawel Stefaniak case 0: 348*47bcbde9SPiotr Pawel Stefaniak return (0); 349*47bcbde9SPiotr Pawel Stefaniak case 1: 350*47bcbde9SPiotr Pawel Stefaniak return (1); 351*47bcbde9SPiotr Pawel Stefaniak } 352*47bcbde9SPiotr Pawel Stefaniak 353*47bcbde9SPiotr Pawel Stefaniak #define DEC(c) (((c) - ' ') & 077) /* single character decode */ 354*47bcbde9SPiotr Pawel Stefaniak #define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) ) 355*47bcbde9SPiotr Pawel Stefaniak 356*47bcbde9SPiotr Pawel Stefaniak #define OUT_OF_RANGE do { \ 357*47bcbde9SPiotr Pawel Stefaniak warnx("%s: %s: character out of range: [%d-%d]", \ 358*47bcbde9SPiotr Pawel Stefaniak infile, outfile, ' ', 077 + ' ' + 1); \ 359*47bcbde9SPiotr Pawel Stefaniak return (1); \ 360*47bcbde9SPiotr Pawel Stefaniak } while (0) 361*47bcbde9SPiotr Pawel Stefaniak 362*47bcbde9SPiotr Pawel Stefaniak /* 363*47bcbde9SPiotr Pawel Stefaniak * `i' is used to avoid writing out all the characters 364*47bcbde9SPiotr Pawel Stefaniak * at the end of the file. 365*47bcbde9SPiotr Pawel Stefaniak */ 366*47bcbde9SPiotr Pawel Stefaniak p = buf; 367*47bcbde9SPiotr Pawel Stefaniak if ((i = DEC(*p)) <= 0) 368*47bcbde9SPiotr Pawel Stefaniak break; 369*47bcbde9SPiotr Pawel Stefaniak for (++p; i > 0; p += 4, i -= 3) 370*47bcbde9SPiotr Pawel Stefaniak if (i >= 3) { 371*47bcbde9SPiotr Pawel Stefaniak if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 372*47bcbde9SPiotr Pawel Stefaniak IS_DEC(*(p + 2)) && IS_DEC(*(p + 3)))) 373*47bcbde9SPiotr Pawel Stefaniak OUT_OF_RANGE; 374*47bcbde9SPiotr Pawel Stefaniak 375*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 376*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 377*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 378*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 379*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[2]) << 6 | DEC(p[3]); 380*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 381*47bcbde9SPiotr Pawel Stefaniak } else { 382*47bcbde9SPiotr Pawel Stefaniak if (i >= 1) { 383*47bcbde9SPiotr Pawel Stefaniak if (!(IS_DEC(*p) && IS_DEC(*(p + 1)))) 384*47bcbde9SPiotr Pawel Stefaniak OUT_OF_RANGE; 385*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 386*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 387*47bcbde9SPiotr Pawel Stefaniak } 388*47bcbde9SPiotr Pawel Stefaniak if (i >= 2) { 389*47bcbde9SPiotr Pawel Stefaniak if (!(IS_DEC(*(p + 1)) && 390*47bcbde9SPiotr Pawel Stefaniak IS_DEC(*(p + 2)))) 391*47bcbde9SPiotr Pawel Stefaniak OUT_OF_RANGE; 392*47bcbde9SPiotr Pawel Stefaniak 393*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 394*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 395*47bcbde9SPiotr Pawel Stefaniak } 396*47bcbde9SPiotr Pawel Stefaniak if (i >= 3) { 397*47bcbde9SPiotr Pawel Stefaniak if (!(IS_DEC(*(p + 2)) && 398*47bcbde9SPiotr Pawel Stefaniak IS_DEC(*(p + 3)))) 399*47bcbde9SPiotr Pawel Stefaniak OUT_OF_RANGE; 400*47bcbde9SPiotr Pawel Stefaniak ch = DEC(p[2]) << 6 | DEC(p[3]); 401*47bcbde9SPiotr Pawel Stefaniak putc(ch, outfp); 402*47bcbde9SPiotr Pawel Stefaniak } 403*47bcbde9SPiotr Pawel Stefaniak } 404*47bcbde9SPiotr Pawel Stefaniak } 405*47bcbde9SPiotr Pawel Stefaniak switch (get_line(buf, sizeof(buf))) { 406*47bcbde9SPiotr Pawel Stefaniak case 0: 407*47bcbde9SPiotr Pawel Stefaniak return (0); 408*47bcbde9SPiotr Pawel Stefaniak case 1: 409*47bcbde9SPiotr Pawel Stefaniak return (1); 410*47bcbde9SPiotr Pawel Stefaniak default: 411*47bcbde9SPiotr Pawel Stefaniak return (checkend(buf, "end", "no \"end\" line")); 412*47bcbde9SPiotr Pawel Stefaniak } 413*47bcbde9SPiotr Pawel Stefaniak } 414*47bcbde9SPiotr Pawel Stefaniak 415*47bcbde9SPiotr Pawel Stefaniak static int 416*47bcbde9SPiotr Pawel Stefaniak base64_decode(void) 417*47bcbde9SPiotr Pawel Stefaniak { 418*47bcbde9SPiotr Pawel Stefaniak int n, count, count4; 419*47bcbde9SPiotr Pawel Stefaniak char inbuf[MAXPATHLEN + 1], *p; 420*47bcbde9SPiotr Pawel Stefaniak unsigned char outbuf[MAXPATHLEN * 4]; 421*47bcbde9SPiotr Pawel Stefaniak char leftover[MAXPATHLEN + 1]; 422*47bcbde9SPiotr Pawel Stefaniak 423*47bcbde9SPiotr Pawel Stefaniak leftover[0] = '\0'; 424*47bcbde9SPiotr Pawel Stefaniak for (;;) { 425*47bcbde9SPiotr Pawel Stefaniak strcpy(inbuf, leftover); 426*47bcbde9SPiotr Pawel Stefaniak switch (get_line(inbuf + strlen(inbuf), 427*47bcbde9SPiotr Pawel Stefaniak sizeof(inbuf) - strlen(inbuf))) { 428*47bcbde9SPiotr Pawel Stefaniak case 0: 429*47bcbde9SPiotr Pawel Stefaniak return (0); 430*47bcbde9SPiotr Pawel Stefaniak case 1: 431*47bcbde9SPiotr Pawel Stefaniak return (1); 432*47bcbde9SPiotr Pawel Stefaniak } 433*47bcbde9SPiotr Pawel Stefaniak 434*47bcbde9SPiotr Pawel Stefaniak count = 0; 435*47bcbde9SPiotr Pawel Stefaniak count4 = -1; 436*47bcbde9SPiotr Pawel Stefaniak p = inbuf; 437*47bcbde9SPiotr Pawel Stefaniak while (*p != '\0') { 438*47bcbde9SPiotr Pawel Stefaniak /* 439*47bcbde9SPiotr Pawel Stefaniak * Base64 encoded strings have the following 440*47bcbde9SPiotr Pawel Stefaniak * characters in them: A-Z, a-z, 0-9 and +, / and = 441*47bcbde9SPiotr Pawel Stefaniak */ 442*47bcbde9SPiotr Pawel Stefaniak if (isalnum(*p) || *p == '+' || *p == '/' || *p == '=') 443*47bcbde9SPiotr Pawel Stefaniak count++; 444*47bcbde9SPiotr Pawel Stefaniak if (count % 4 == 0) 445*47bcbde9SPiotr Pawel Stefaniak count4 = p - inbuf; 446*47bcbde9SPiotr Pawel Stefaniak p++; 447*47bcbde9SPiotr Pawel Stefaniak } 448*47bcbde9SPiotr Pawel Stefaniak 449*47bcbde9SPiotr Pawel Stefaniak strcpy(leftover, inbuf + count4 + 1); 450*47bcbde9SPiotr Pawel Stefaniak inbuf[count4 + 1] = 0; 451*47bcbde9SPiotr Pawel Stefaniak 452*47bcbde9SPiotr Pawel Stefaniak n = b64_pton(inbuf, outbuf, sizeof(outbuf)); 453*47bcbde9SPiotr Pawel Stefaniak 454*47bcbde9SPiotr Pawel Stefaniak if (n < 0) 455*47bcbde9SPiotr Pawel Stefaniak break; 456*47bcbde9SPiotr Pawel Stefaniak fwrite(outbuf, 1, n, outfp); 457*47bcbde9SPiotr Pawel Stefaniak } 458*47bcbde9SPiotr Pawel Stefaniak return (checkend(inbuf, "====", "error decoding base64 input stream")); 459*47bcbde9SPiotr Pawel Stefaniak } 460*47bcbde9SPiotr Pawel Stefaniak 461*47bcbde9SPiotr Pawel Stefaniak static void 462*47bcbde9SPiotr Pawel Stefaniak usage(void) 463*47bcbde9SPiotr Pawel Stefaniak { 464*47bcbde9SPiotr Pawel Stefaniak 465*47bcbde9SPiotr Pawel Stefaniak (void)fprintf(stderr, 466*47bcbde9SPiotr Pawel Stefaniak "usage: uudecode [-cimprs] [file ...]\n" 467*47bcbde9SPiotr Pawel Stefaniak " uudecode [-i] -o output_file [file]\n" 468*47bcbde9SPiotr Pawel Stefaniak " b64decode [-cimprs] [file ...]\n" 469*47bcbde9SPiotr Pawel Stefaniak " b64decode [-i] -o output_file [file]\n"); 470*47bcbde9SPiotr Pawel Stefaniak exit(1); 471*47bcbde9SPiotr Pawel Stefaniak } 472