uudecode.c revision 103206
1170754Sdelphij/*- 2170754Sdelphij * Copyright (c) 1983, 1993 3170754Sdelphij * The Regents of the University of California. All rights reserved. 4170754Sdelphij * 5170754Sdelphij * Redistribution and use in source and binary forms, with or without 6170754Sdelphij * modification, are permitted provided that the following conditions 7170754Sdelphij * are met: 8170754Sdelphij * 1. Redistributions of source code must retain the above copyright 9170754Sdelphij * notice, this list of conditions and the following disclaimer. 10170754Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11170754Sdelphij * notice, this list of conditions and the following disclaimer in the 12170754Sdelphij * documentation and/or other materials provided with the distribution. 13170754Sdelphij * 3. All advertising materials mentioning features or use of this software 14170754Sdelphij * must display the following acknowledgement: 15170754Sdelphij * This product includes software developed by the University of 16170754Sdelphij * California, Berkeley and its contributors. 17170754Sdelphij * 4. Neither the name of the University nor the names of its contributors 18170754Sdelphij * may be used to endorse or promote products derived from this software 19170754Sdelphij * without specific prior written permission. 20170754Sdelphij * 21170754Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22170754Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23170754Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24170754Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25170754Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26170754Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27170754Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28170754Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29170754Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30170754Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31170754Sdelphij * SUCH DAMAGE. 32170754Sdelphij */ 33170754Sdelphij 34170754Sdelphij#ifndef lint 35170754Sdelphijstatic const char copyright[] = 36170754Sdelphij"@(#) Copyright (c) 1983, 1993\n\ 37170754Sdelphij The Regents of the University of California. All rights reserved.\n"; 38170754Sdelphij#endif /* not lint */ 39170754Sdelphij 40170754Sdelphij#if 0 41170754Sdelphij#ifndef lint 42170754Sdelphijstatic char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; 43170754Sdelphij#endif /* not lint */ 44170754Sdelphij#endif 45170754Sdelphij 46170754Sdelphij#include <sys/cdefs.h> 47170754Sdelphij__FBSDID("$FreeBSD: head/usr.bin/uudecode/uudecode.c 103206 2002-09-11 01:00:56Z mike $"); 48170754Sdelphij 49170754Sdelphij/* 50170754Sdelphij * uudecode [file ...] 51170754Sdelphij * 52170754Sdelphij * create the specified file, decoding as you go. 53170754Sdelphij * used with uuencode. 54170754Sdelphij */ 55170754Sdelphij#include <sys/param.h> 56170754Sdelphij#include <sys/socket.h> 57170754Sdelphij#include <sys/stat.h> 58170754Sdelphij 59170754Sdelphij#include <netinet/in.h> 60170754Sdelphij 61170754Sdelphij#include <err.h> 62170754Sdelphij#include <pwd.h> 63170754Sdelphij#include <resolv.h> 64170754Sdelphij#include <stdio.h> 65170754Sdelphij#include <stdlib.h> 66170754Sdelphij#include <string.h> 67170754Sdelphij#include <unistd.h> 68170754Sdelphij 69170754Sdelphijconst char *filename; 70170754Sdelphijchar *outfile; 71170754Sdelphijint cflag, iflag, oflag, pflag, sflag; 72170754Sdelphij 73170754Sdelphijstatic void usage(void); 74170754Sdelphijint decode(void); 75170754Sdelphijint decode2(void); 76170754Sdelphijint base64_decode(const char *); 77170754Sdelphij 78170754Sdelphijint 79170754Sdelphijmain(int argc, char *argv[]) 80170754Sdelphij{ 81170754Sdelphij int rval, ch; 82170754Sdelphij 83170754Sdelphij while ((ch = getopt(argc, argv, "cio:ps")) != -1) { 84170754Sdelphij switch(ch) { 85170754Sdelphij case 'c': 86170754Sdelphij if (oflag) 87170754Sdelphij usage(); 88170754Sdelphij cflag = 1; /* multiple uudecode'd files */ 89170754Sdelphij break; 90170754Sdelphij case 'i': 91170754Sdelphij iflag = 1; /* ask before override files */ 92170754Sdelphij break; 93170754Sdelphij case 'o': 94170754Sdelphij if (cflag || pflag || sflag) 95170754Sdelphij usage(); 96170754Sdelphij oflag = 1; /* output to the specified file */ 97170754Sdelphij sflag = 1; /* do not strip pathnames for output */ 98170754Sdelphij outfile = optarg; /* set the output filename */ 99170754Sdelphij break; 100170754Sdelphij case 'p': 101170754Sdelphij if (oflag) 102170754Sdelphij usage(); 103170754Sdelphij pflag = 1; /* print output to stdout */ 104170754Sdelphij break; 105170754Sdelphij case 's': 106170754Sdelphij if (oflag) 107170754Sdelphij usage(); 108170754Sdelphij sflag = 1; /* do not strip pathnames for output */ 109170754Sdelphij break; 110170754Sdelphij default: 111170754Sdelphij usage(); 112170754Sdelphij } 113170754Sdelphij } 114170754Sdelphij argc -= optind; 115170754Sdelphij argv += optind; 116170754Sdelphij 117170754Sdelphij if (*argv) { 118170754Sdelphij rval = 0; 119170754Sdelphij do { 120170754Sdelphij if (freopen(filename = *argv, "r", stdin) == NULL) { 121170754Sdelphij warn("%s", *argv); 122170754Sdelphij rval = 1; 123170754Sdelphij continue; 124170754Sdelphij } 125170754Sdelphij rval |= decode(); 126170754Sdelphij } while (*++argv); 127170754Sdelphij } else { 128170754Sdelphij filename = "stdin"; 129170754Sdelphij rval = decode(); 130170754Sdelphij } 131170754Sdelphij exit(rval); 132170754Sdelphij} 133170754Sdelphij 134170754Sdelphijint 135170754Sdelphijdecode(void) 136170754Sdelphij{ 137170754Sdelphij int r, v; 138170754Sdelphij 139170754Sdelphij v = decode2(); 140170754Sdelphij if (v == EOF) { 141170754Sdelphij warnx("%s: missing or bad \"begin\" line", filename); 142170754Sdelphij return (1); 143170754Sdelphij } 144170754Sdelphij for (r = v; cflag; r |= v) { 145170754Sdelphij v = decode2(); 146170754Sdelphij if (v == EOF) 147170754Sdelphij break; 148170754Sdelphij } 149170754Sdelphij return (r); 150170754Sdelphij} 151170754Sdelphij 152170754Sdelphijint 153170754Sdelphijdecode2(void) 154170754Sdelphij{ 155170754Sdelphij int base64; 156170754Sdelphij size_t n; 157170754Sdelphij char ch, *p, *q; 158170754Sdelphij void *mode; 159170754Sdelphij struct passwd *pw; 160170754Sdelphij struct stat st; 161170754Sdelphij char buf[MAXPATHLEN+1]; 162170754Sdelphij char buffn[MAXPATHLEN+1]; /* file name buffer */ 163170754Sdelphij 164170754Sdelphij base64 = 0; 165170754Sdelphij /* search for header line */ 166170754Sdelphij for (;;) { 167170754Sdelphij if (fgets(buf, sizeof(buf), stdin) == NULL) 168170754Sdelphij return (EOF); 169170754Sdelphij p = buf; 170170754Sdelphij if (strncmp(p, "begin-base64 ", 13) == 0) { 171170754Sdelphij base64 = 1; 172170754Sdelphij p += 13; 173170754Sdelphij } else if (strncmp(p, "begin ", 6) == 0) 174170754Sdelphij p += 6; 175170754Sdelphij else 176170754Sdelphij continue; 177170754Sdelphij /* p points to mode */ 178170754Sdelphij q = strchr(p, ' '); 179170754Sdelphij if (q == NULL) 180170754Sdelphij continue; 181170754Sdelphij *q++ = '\0'; 182170754Sdelphij /* q points to filename */ 183170754Sdelphij n = strlen(q); 184170754Sdelphij while (n > 0 && (q[n-1] == '\n' || q[n-1] == '\r')) 185170754Sdelphij q[--n] = '\0'; 186170754Sdelphij /* found valid header? */ 187170754Sdelphij if (n > 0) 188170754Sdelphij break; 189170754Sdelphij } 190170754Sdelphij 191170754Sdelphij mode = setmode(p); 192170754Sdelphij if (mode == NULL) { 193170754Sdelphij warnx("%s: unable to parse file mode", filename); 194170754Sdelphij return (1); 195170754Sdelphij } 196170754Sdelphij 197170754Sdelphij if (oflag) { 198170754Sdelphij /* use command-line filename */ 199170754Sdelphij n = strlcpy(buffn, outfile, sizeof(buffn)); 200170754Sdelphij } else if (sflag) { 201170754Sdelphij /* don't strip, so try ~user/file expansion */ 202170754Sdelphij p = NULL; 203170754Sdelphij pw = NULL; 204170754Sdelphij if (*q == '~') 205170754Sdelphij p = strchr(q, '/'); 206170754Sdelphij if (p != NULL) { 207170754Sdelphij *p = '\0'; 208170754Sdelphij pw = getpwnam(q + 1); 209170754Sdelphij *p = '/'; 210170754Sdelphij } 211170754Sdelphij if (pw != NULL) { 212170754Sdelphij strlcpy(buffn, pw->pw_dir, sizeof(buffn)); 213170754Sdelphij n = strlcat(buffn, p, sizeof(buffn)); 214170754Sdelphij } else { 215170754Sdelphij n = strlcpy(buffn, q, sizeof(buffn)); 216170754Sdelphij } 217170754Sdelphij } else { 218170754Sdelphij /* strip down to leaf name */ 219170754Sdelphij p = strrchr(q, '/'); 220170754Sdelphij if (p != NULL) 221170754Sdelphij n = strlcpy(buffn, p+1, sizeof(buffn)); 222170754Sdelphij else 223170754Sdelphij n = strlcpy(buffn, q, sizeof(buffn)); 224170754Sdelphij } 225170754Sdelphij if (n >= sizeof(buffn) || *buffn == '\0') { 226170754Sdelphij warnx("%s: bad output filename", filename); 227170754Sdelphij return (1); 228170754Sdelphij } 229170754Sdelphij 230170754Sdelphij if (!pflag) { 231170754Sdelphij if (iflag && !access(buffn, F_OK)) { 232170754Sdelphij warnx("not overwritten: %s", buffn); 233170754Sdelphij return (0); 234170754Sdelphij } 235170754Sdelphij if (freopen(buffn, "w", stdout) == NULL || 236170754Sdelphij stat(buffn, &st) < 0 || (S_ISREG(st.st_mode) && 237170754Sdelphij fchmod(fileno(stdout), getmode(mode, 0) & 0666) < 0)) { 238170754Sdelphij warn("%s: %s", filename, buffn); 239170754Sdelphij return (1); 240170754Sdelphij } 241170754Sdelphij } 242170754Sdelphij free(mode); 243170754Sdelphij 244170754Sdelphij if (base64) 245170754Sdelphij return (base64_decode(buffn)); 246170754Sdelphij 247170754Sdelphij /* for each input line */ 248170754Sdelphij for (;;) { 249170754Sdelphij if (fgets(p = buf, sizeof(buf), stdin) == NULL) { 250170754Sdelphij warnx("%s: short file", filename); 251170754Sdelphij return (1); 252170754Sdelphij } 253170754Sdelphij 254170754Sdelphij#define DEC(c) (((c) - ' ') & 077) /* single character decode */ 255170754Sdelphij#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) ) 256 257#define OUT_OF_RANGE do { \ 258 warnx("%s: %s: character out of range: [%d-%d]", \ 259 filename, buffn, 1 + ' ', 077 + ' ' + 1); \ 260 return (1); \ 261} while (0) 262 263 /* 264 * `n' is used to avoid writing out all the characters 265 * at the end of the file. 266 */ 267 if ((n = DEC(*p)) <= 0) 268 break; 269 for (++p; n > 0; p += 4, n -= 3) 270 if (n >= 3) { 271 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 272 IS_DEC(*(p + 2)) && IS_DEC(*(p + 3)))) 273 OUT_OF_RANGE; 274 275 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 276 putchar(ch); 277 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 278 putchar(ch); 279 ch = DEC(p[2]) << 6 | DEC(p[3]); 280 putchar(ch); 281 } 282 else { 283 if (n >= 1) { 284 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)))) 285 OUT_OF_RANGE; 286 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; 287 putchar(ch); 288 } 289 if (n >= 2) { 290 if (!(IS_DEC(*(p + 1)) && 291 IS_DEC(*(p + 2)))) 292 OUT_OF_RANGE; 293 294 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; 295 putchar(ch); 296 } 297 if (n >= 3) { 298 if (!(IS_DEC(*(p + 2)) && 299 IS_DEC(*(p + 3)))) 300 OUT_OF_RANGE; 301 ch = DEC(p[2]) << 6 | DEC(p[3]); 302 putchar(ch); 303 } 304 } 305 } 306 if (fgets(buf, sizeof(buf), stdin) == NULL || 307 (strcmp(buf, "end") && strcmp(buf, "end\n") && 308 strcmp(buf, "end\r\n"))) { 309 warnx("%s: no \"end\" line", filename); 310 return (1); 311 } 312 return (0); 313} 314 315int 316base64_decode(const char *outname) 317{ 318 int n; 319 char buf[MAXPATHLEN+1]; 320 unsigned char out[MAXPATHLEN * 4]; 321 322 for (;;) { 323 if (fgets(buf, sizeof(buf), stdin) == NULL) { 324 warnx("%s: short file", filename); 325 return (1); 326 } 327 if (strcmp(buf, "====") == 0 || 328 strcmp(buf, "====\n") == 0 || 329 strcmp(buf, "====\r\n") == 0) 330 return (0); 331 n = strlen(buf); 332 while (n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r')) 333 buf[--n] = '\0'; 334 n = b64_pton(buf, out, sizeof(out)); 335 if (n < 0) { 336 warnx("%s: %s: error decoding base64 input stream", filename, outname); 337 return (1); 338 } 339 fwrite(out, 1, n, stdout); 340 } 341} 342 343static void 344usage(void) 345{ 346 (void)fprintf(stderr, 347"usage: uudecode [-cips] [file ...]\n" 348" uudecode [-i] -o output_file [file]\n" 349" b64decode [-cips] [file ...]\n" 350" b64decode [-i] -o output_file [file]\n"); 351 exit(1); 352} 353