1/* uudecode.c -- uudecode utility. 2 * Copyright (C) 1994, 1995 Free Software Foundation, Inc. 3 * 4 * This product is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2, or (at your option) 7 * any later version. 8 * 9 * This product is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this product; see the file COPYING. If not, write to 16 * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 17 * 02111-1307, USA. 18 * 19 * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. 20 * 21 * Original copyright notice is retained at the end of this file. 22 */ 23 24 25 26#include <stdio.h> 27#include <errno.h> 28#include <getopt.h> 29#include <string.h> 30#include <stdlib.h> 31#include "busybox.h" 32#include "pwd_grp/pwd.h" 33#include "pwd_grp/grp.h" 34 35/*struct passwd *getpwnam();*/ 36 37/* Single character decode. */ 38#define DEC(Char) (((Char) - ' ') & 077) 39 40static int read_stduu (const char *inname) 41{ 42 char buf[2 * BUFSIZ]; 43 44 while (1) { 45 int n; 46 char *p; 47 48 if (fgets (buf, sizeof(buf), stdin) == NULL) { 49 error_msg("%s: Short file", inname); 50 return FALSE; 51 } 52 p = buf; 53 54 /* N is used to avoid writing out all the characters at the end of 55 the file. */ 56 n = DEC (*p); 57 if (n <= 0) 58 break; 59 for (++p; n > 0; p += 4, n -= 3) { 60 char ch; 61 62 if (n >= 3) { 63 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; 64 putchar (ch); 65 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; 66 putchar (ch); 67 ch = DEC (p[2]) << 6 | DEC (p[3]); 68 putchar (ch); 69 } else { 70 if (n >= 1) { 71 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; 72 putchar (ch); 73 } 74 if (n >= 2) { 75 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; 76 putchar (ch); 77 } 78 } 79 } 80 } 81 82 if (fgets (buf, sizeof(buf), stdin) == NULL 83 || strcmp (buf, "end\n")) { 84 error_msg("%s: No `end' line", inname); 85 return FALSE; 86 } 87 88 return TRUE; 89} 90 91static int read_base64 (const char *inname) 92{ 93 static const char b64_tab[256] = { 94 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/ 95 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/ 96 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/ 97 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/ 98 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/ 99 '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/ 100 '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/ 101 '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/ 102 '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/ 103 '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/ 104 '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/ 105 '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/ 106 '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/ 107 '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/ 108 '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/ 109 '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/ 110 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/ 111 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/ 112 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/ 113 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/ 114 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/ 115 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/ 116 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/ 117 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/ 118 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/ 119 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/ 120 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/ 121 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/ 122 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/ 123 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/ 124 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/ 125 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/ 126 }; 127 unsigned char buf[2 * BUFSIZ]; 128 129 while (1) { 130 int last_data = 0; 131 unsigned char *p; 132 133 if (fgets (buf, sizeof(buf), stdin) == NULL) { 134 error_msg("%s: Short file", inname); 135 return FALSE; 136 } 137 p = buf; 138 139 if (memcmp (buf, "====", 4) == 0) 140 break; 141 if (last_data != 0) { 142 error_msg("%s: data following `=' padding character", inname); 143 return FALSE; 144 } 145 146 /* The following implementation of the base64 decoding might look 147 a bit clumsy but I only try to follow the POSIX standard: 148 ``All line breaks or other characters not found in the table 149 [with base64 characters] shall be ignored by decoding 150 software.'' */ 151 while (*p != '\n') { 152 char c1, c2, c3; 153 154 while ((b64_tab[*p] & '\100') != 0) 155 if (*p == '\n' || *p++ == '=') 156 break; 157 if (*p == '\n') 158 /* This leaves the loop. */ 159 continue; 160 c1 = b64_tab[*p++]; 161 162 while ((b64_tab[*p] & '\100') != 0) 163 if (*p == '\n' || *p++ == '=') { 164 error_msg("%s: illegal line", inname); 165 return FALSE; 166 } 167 c2 = b64_tab[*p++]; 168 169 while (b64_tab[*p] == '\177') 170 if (*p++ == '\n') { 171 error_msg("%s: illegal line", inname); 172 return FALSE; 173 } 174 if (*p == '=') { 175 putchar (c1 << 2 | c2 >> 4); 176 last_data = 1; 177 break; 178 } 179 c3 = b64_tab[*p++]; 180 181 while (b64_tab[*p] == '\177') 182 if (*p++ == '\n') { 183 error_msg("%s: illegal line", inname); 184 return FALSE; 185 } 186 putchar (c1 << 2 | c2 >> 4); 187 putchar (c2 << 4 | c3 >> 2); 188 if (*p == '=') { 189 last_data = 1; 190 break; 191 } 192 else 193 putchar (c3 << 6 | b64_tab[*p++]); 194 } 195 } 196 197 return TRUE; 198} 199 200static int decode (const char *inname, 201 const char *forced_outname) 202{ 203 struct passwd *pw; 204 register char *p; 205 int mode; 206 char buf[2 * BUFSIZ]; 207 char *outname; 208 int do_base64 = 0; 209 int res; 210 int dofre; 211 212 /* Search for header line. */ 213 214 while (1) { 215 if (fgets (buf, sizeof (buf), stdin) == NULL) { 216 error_msg("%s: No `begin' line", inname); 217 return FALSE; 218 } 219 220 if (strncmp (buf, "begin", 5) == 0) { 221 if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) { 222 do_base64 = 1; 223 break; 224 } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2) 225 break; 226 } 227 } 228 229 /* If the output file name is given on the command line this rules. */ 230 dofre = FALSE; 231 if (forced_outname != NULL) 232 outname = (char *) forced_outname; 233 else { 234 /* Handle ~user/file format. */ 235 if (buf[0] != '~') 236 outname = buf; 237 else { 238 p = buf + 1; 239 while (*p != '/') 240 ++p; 241 if (*p == '\0') { 242 error_msg("%s: Illegal ~user", inname); 243 return FALSE; 244 } 245 *p++ = '\0'; 246 pw = getpwnam (buf + 1); 247 if (pw == NULL) { 248 error_msg("%s: No user `%s'", inname, buf + 1); 249 return FALSE; 250 } 251 outname = concat_path_file(pw->pw_dir, p); 252 dofre = TRUE; 253 } 254 } 255 256 /* Create output file and set mode. */ 257 if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0 258 && (freopen (outname, "w", stdout) == NULL 259 || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) 260 )) { 261 perror_msg("%s", outname); /* */ 262 if (dofre) 263 free(outname); 264 return FALSE; 265 } 266 267 /* We differenciate decoding standard UU encoding and base64. A 268 common function would only slow down the program. */ 269 270 /* For each input line: */ 271 if (do_base64) 272 res = read_base64 (inname); 273 else 274 res = read_stduu (inname); 275 if (dofre) 276 free(outname); 277 return res; 278} 279 280int uudecode_main (int argc, 281 char **argv) 282{ 283 int opt; 284 int exit_status; 285 const char *outname; 286 outname = NULL; 287 288 while ((opt = getopt(argc, argv, "o:")) != EOF) { 289 switch (opt) { 290 case 0: 291 break; 292 293 case 'o': 294 outname = optarg; 295 break; 296 297 default: 298 show_usage(); 299 } 300 } 301 302 if (optind == argc) 303 exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 304 else { 305 exit_status = EXIT_SUCCESS; 306 do { 307 if (freopen (argv[optind], "r", stdin) != NULL) { 308 if (decode (argv[optind], outname) != 0) 309 exit_status = FALSE; 310 } else { 311 perror_msg("%s", argv[optind]); 312 exit_status = EXIT_FAILURE; 313 } 314 optind++; 315 } 316 while (optind < argc); 317 } 318 return(exit_status); 319} 320 321/* Copyright (c) 1983 Regents of the University of California. 322 * All rights reserved. 323 * 324 * Redistribution and use in source and binary forms, with or without 325 * modification, are permitted provided that the following conditions 326 * are met: 327 * 1. Redistributions of source code must retain the above copyright 328 * notice, this list of conditions and the following disclaimer. 329 * 2. Redistributions in binary form must reproduce the above copyright 330 * notice, this list of conditions and the following disclaimer in the 331 * documentation and/or other materials provided with the distribution. 332 * 333 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 334 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 335 * 336 * 4. Neither the name of the University nor the names of its contributors 337 * may be used to endorse or promote products derived from this software 338 * without specific prior written permission. 339 * 340 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 341 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 342 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 343 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 344 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 345 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 346 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 347 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 348 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 349 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 350 * SUCH DAMAGE. 351 */ 352 353 354