Deleted Added
full compact
1/*-
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94";
43#endif /* not lint */
44#endif
45
46#include <sys/cdefs.h>
47__FBSDID("$FreeBSD: head/usr.bin/uudecode/uudecode.c 103201 2002-09-10 20:53:46Z fanf $");
47__FBSDID("$FreeBSD: head/usr.bin/uudecode/uudecode.c 103203 2002-09-10 21:10:33Z fanf $");
48
49/*
50 * uudecode [file ...]
51 *
52 * create the specified file, decoding as you go.
53 * used with uuencode.
54 */
55#include <sys/param.h>
56#include <sys/socket.h>
57#include <sys/stat.h>
58
59#include <netinet/in.h>
60
61#include <err.h>
62#include <pwd.h>
63#include <resolv.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <unistd.h>
68
69const char *filename;
70char *outfile;
71int cflag, iflag, oflag, pflag, sflag;
72
73static void usage(void);
74int decode(void);
75int decode2(void);
76void base64_decode(const char *);
76int base64_decode(const char *);
77
78int
79main(int argc, char *argv[])
80{
81 int rval, ch;
82
83 while ((ch = getopt(argc, argv, "cio:ps")) != -1) {
84 switch(ch) {
85 case 'c':
86 if (oflag)
87 usage();
88 cflag = 1; /* multiple uudecode'd files */
89 break;
90 case 'i':
91 iflag = 1; /* ask before override files */
92 break;
93 case 'o':
94 if (cflag || pflag || sflag)
95 usage();
96 oflag = 1; /* output to the specified file */
97 sflag = 1; /* do not strip pathnames for output */
98 outfile = optarg; /* set the output filename */
99 break;
100 case 'p':
101 if (oflag)
102 usage();
103 pflag = 1; /* print output to stdout */
104 break;
105 case 's':
106 if (oflag)
107 usage();
108 sflag = 1; /* do not strip pathnames for output */
109 break;
110 default:
111 usage();
112 }
113 }
114 argc -= optind;
115 argv += optind;
116
117 if (*argv) {
118 rval = 0;
119 do {
120 if (freopen(filename = *argv, "r", stdin) == NULL) {
121 warn("%s", *argv);
122 rval = 1;
123 continue;
124 }
125 rval |= decode();
126 } while (*++argv);
127 } else {
128 filename = "stdin";
129 rval = decode();
130 }
131 exit(rval);
132}
133
134int
135decode(void)
136{
137 int r, v;
138
139 v = decode2();
140 if (v == EOF) {
141 warnx("%s: missing or bad \"begin\" line", filename);
142 return (1);
143 }
144 for (r = v; cflag; r |= v) {
145 v = decode2();
146 if (v == EOF)
147 break;
148 }
149 return (r);
150}
151
152int
153decode2(void)
154{
155 int base64;
156 int n;
157 char ch, *p, *q;
158 void *mode;
159 struct passwd *pw;
160 struct stat st;
161 char buf[MAXPATHLEN+1];
162 char buffn[MAXPATHLEN+1]; /* file name buffer */
163
164 base64 = 0;
165 /* search for header line */
166 for (;;) {
167 if (fgets(buf, sizeof(buf), stdin) == NULL)
168 return (EOF);
169 p = buf;
170 if (strncmp(p, "begin-base64 ", 13) == 0) {
171 base64 = 1;
172 p += 13;
173 } else if (strncmp(p, "begin ", 6) == 0)
174 p += 6;
175 else
176 continue;
177 /* p points to mode */
178 q = strchr(p, ' ');
179 if (q == NULL)
180 continue;
181 *q++ = '\0';
182 /* q points to filename */
183 n = strlen(q);
184 while (n > 0 && (q[n-1] == '\n' || q[n-1] == '\r'))
185 q[--n] = '\0';
186 /* found valid header? */
187 if (n > 0)
188 break;
189 }
190
191 mode = setmode(p);
192 if (mode == NULL) {
193 warnx("%s: unable to parse file mode", filename);
194 return (1);
195 }
196
197 if (oflag) {
198 /* use command-line filename */
199 n = strlcpy(buffn, outfile, sizeof(buffn));
200 } else if (sflag) {
201 /* don't strip, so try ~user/file expansion */
202 p = NULL;
203 pw = NULL;
204 if (*q == '~')
205 p = strchr(q, '/');
206 if (p != NULL) {
207 *p = '\0';
208 pw = getpwnam(q + 1);
209 *p = '/';
210 }
211 if (pw != NULL) {
212 strlcpy(buffn, pw->pw_dir, sizeof(buffn));
213 n = strlcat(buffn, p, sizeof(buffn));
214 } else {
215 n = strlcpy(buffn, q, sizeof(buffn));
216 }
217 } else {
218 /* strip down to leaf name */
219 p = strrchr(q, '/');
220 if (p != NULL)
221 n = strlcpy(buffn, p+1, sizeof(buffn));
222 else
223 n = strlcpy(buffn, q, sizeof(buffn));
224 }
225 if (n >= sizeof(buffn) || *buffn == '\0') {
226 warnx("%s: bad output filename", filename);
227 return (1);
228 }
229
230 if (!pflag) {
231 if (iflag && !access(buffn, F_OK)) {
232 warnx("not overwritten: %s", buffn);
233 return (0);
234 }
235 if (freopen(buffn, "w", stdout) == NULL ||
236 stat(buffn, &st) < 0 || (S_ISREG(st.st_mode) &&
237 fchmod(fileno(stdout), getmode(mode, 0) & 0666) < 0)) {
238 warn("%s: %s", filename, buffn);
239 return (1);
240 }
241 }
242 free(mode);
243
244 if (base64)
245 return (base64_decode(buffn));
246
247 /* for each input line */
248 for (;;) {
249 if (fgets(p = buf, sizeof(buf), stdin) == NULL) {
250 warnx("%s: short file", filename);
251 return (1);
252 }
250 if (base64) {
251 if (strncmp(buf, "====", 4) == 0)
252 return (0);
253 base64_decode(buf);
254 continue;
255 }
253
254#define DEC(c) (((c) - ' ') & 077) /* single character decode */
255#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
256/* #define IS_DEC(c) (1) */
257
258#define OUT_OF_RANGE \
259{ \
260 warnx( \
261"\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \
262 filename, buffn, 1 + ' ', 077 + ' ' + 1); \
263 return (1); \
264}
265
266 /*
267 * `n' is used to avoid writing out all the characters
268 * at the end of the file.
269 */
270 if ((n = DEC(*p)) <= 0)
271 break;
272 for (++p; n > 0; p += 4, n -= 3)
273 if (n >= 3) {
274 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
275 IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
276 OUT_OF_RANGE
277
278 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
279 putchar(ch);
280 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
281 putchar(ch);
282 ch = DEC(p[2]) << 6 | DEC(p[3]);
283 putchar(ch);
284 }
285 else {
286 if (n >= 1) {
287 if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
288 OUT_OF_RANGE
289 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
290 putchar(ch);
291 }
292 if (n >= 2) {
293 if (!(IS_DEC(*(p + 1)) &&
294 IS_DEC(*(p + 2))))
295 OUT_OF_RANGE
296
297 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
298 putchar(ch);
299 }
300 if (n >= 3) {
301 if (!(IS_DEC(*(p + 2)) &&
302 IS_DEC(*(p + 3))))
303 OUT_OF_RANGE
304 ch = DEC(p[2]) << 6 | DEC(p[3]);
305 putchar(ch);
306 }
307 }
308 }
309 if (fgets(buf, sizeof(buf), stdin) == NULL ||
310 (strcmp(buf, "end") && strcmp(buf, "end\n") &&
311 strcmp(buf, "end\r\n"))) {
312 warnx("%s: no \"end\" line", filename);
313 return (1);
314 }
315 return (0);
316}
317
320void
321base64_decode(const char *stream)
318int
319base64_decode(const char *outname)
320{
321 int n;
322 char buf[MAXPATHLEN+1];
323 unsigned char out[MAXPATHLEN * 4];
324 int rv;
324
326 if (index(stream, '\r') != NULL)
327 *index(stream, '\r') = '\0';
328 if (index(stream, '\n') != NULL)
329 *index(stream, '\n') = '\0';
330 rv = b64_pton(stream, out, (sizeof(out) / sizeof(out[0])));
331 if (rv == -1)
332 errx(1, "b64_pton: error decoding base64 input stream");
333 fwrite(out, 1, rv, stdout);
325 for (;;) {
326 if (fgets(buf, sizeof(buf), stdin) == NULL) {
327 warnx("%s: short file", filename);
328 return (1);
329 }
330 if (strcmp(buf, "====") == 0 ||
331 strcmp(buf, "====\n") == 0 ||
332 strcmp(buf, "====\r\n") == 0)
333 return (0);
334 n = strlen(buf);
335 while (n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r'))
336 buf[--n] = '\0';
337 n = b64_pton(buf, out, sizeof(out));
338 if (n < 0) {
339 warnx("%s: %s: error decoding base64 input stream", filename, outname);
340 return (1);
341 }
342 fwrite(out, 1, n, stdout);
343 }
344}
345
346static void
347usage(void)
348{
349 (void)fprintf(stderr,
350"usage: uudecode [-cips] [file ...]\n"
351" uudecode [-i] -o output_file [file]\n"
352" b64decode [-cips] [file ...]\n"
353" b64decode [-i] -o output_file [file]\n");
354 exit(1);
355}