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