xref: /openbsd-src/usr.bin/uudecode/uudecode.c (revision ce7e0fc6a9d74d25b78fb6ad846387717f5172b6)
1 /*	$OpenBSD: uudecode.c,v 1.9 2001/11/19 19:02:17 mpech Exp $	*/
2 /*	$NetBSD: uudecode.c,v 1.6 1994/11/17 07:40:43 jtc Exp $	*/
3 
4 /*-
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 char copyright[] =
38 "@(#) Copyright (c) 1983, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n";
40 
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)uudecode.c	8.2 (Berkeley) 4/2/94";
44 #endif
45 static char rcsid[] = "$OpenBSD: uudecode.c,v 1.9 2001/11/19 19:02:17 mpech Exp $";
46 #endif /* not lint */
47 
48 /*
49  * uudecode [-p] [file ...]
50  *
51  * create the specified file, decoding as you go.
52  * used with uuencode.
53  *
54  * Write to stdout if '-p' is specified.  Use this option if you care about
55  * security at all.
56  */
57 #include <stdio.h>
58 #include <string.h>
59 #include <locale.h>
60 #include <errno.h>
61 #include <sys/param.h>
62 #include <sys/stat.h>
63 
64 #include <pwd.h>
65 #include <unistd.h>
66 
67 static int decode(int);
68 static void usage();
69 char *filename;
70 
71 int
72 main(argc, argv)
73 	int argc;
74 	char *argv[];
75 {
76 	int rval;
77 	int ch;
78 	int tostdout = 0;
79 
80 	setlocale(LC_ALL, "");
81 
82 	while ((ch = getopt(argc, argv, "p")) != -1)
83 		switch((char)ch) {
84 		case 'p':
85 			tostdout++;
86 			break;
87 		case '?':
88 		default:
89 			usage();
90 		}
91 	argc -= optind;
92 	argv += optind;
93 
94 	if (*argv) {
95 		rval = 0;
96 		do {
97 			if (!freopen(filename = *argv, "r", stdin)) {
98 				(void)fprintf(stderr, "uudecode: %s: %s\n",
99 				    *argv, strerror(errno));
100 				rval = 1;
101 				continue;
102 			}
103 			rval |= decode(tostdout);
104 		} while (*++argv);
105 	} else {
106 		filename = "stdin";
107 		rval = decode(tostdout);
108 	}
109 	exit(rval);
110 }
111 
112 static int
113 decode(int tostdout)
114 {
115 	struct passwd *pw;
116 	int n;
117 	char ch, *p;
118 	int mode, n1;
119 	char buf[MAXPATHLEN];
120 
121 	/* search for header line */
122 	do {
123 		if (!fgets(buf, sizeof(buf), stdin)) {
124 			(void)fprintf(stderr,
125 			    "uudecode: %s: no \"begin\" line\n", filename);
126 			return(1);
127 		}
128 	} while (strncmp(buf, "begin ", 6));
129 	(void)sscanf(buf, "begin %o %1023[^\n\r]", &mode, buf);
130 
131 	/* handle ~user/file format */
132 	if (buf[0] == '~') {
133 		if (!(p = strchr(buf, '/'))) {
134 			(void)fprintf(stderr, "uudecode: %s: illegal ~user.\n",
135 			    filename);
136 			return(1);
137 		}
138 		*p++ = NULL;
139 		if (!(pw = getpwnam(buf + 1))) {
140 			(void)fprintf(stderr, "uudecode: %s: no user %s.\n",
141 			    filename, buf);
142 			return(1);
143 		}
144 		n = strlen(pw->pw_dir);
145 		n1 = strlen(p);
146 		if (n + n1 + 2 > MAXPATHLEN) {
147 			(void)fprintf(stderr, "uudecode: %s: path too long.\n",
148 			    filename);
149 			return(1);
150 		}
151 		bcopy(p, buf + n + 1, n1 + 1);
152 		bcopy(pw->pw_dir, buf, n);
153 		buf[n] = '/';
154 	}
155 
156 	if (!tostdout) {
157 		/* create output file, set mode */
158 		if (!freopen(buf, "w", stdout) ||
159 		    fchmod(fileno(stdout), mode&0666)) {
160 			(void)fprintf(stderr, "uudecode: %s: %s: %s\n", buf,
161 			    filename, strerror(errno));
162 			return(1);
163 		}
164 	}
165 
166 	/* for each input line */
167 	for (;;) {
168 		if (!fgets(p = buf, sizeof(buf), stdin)) {
169 			(void)fprintf(stderr, "uudecode: %s: short file.\n",
170 			    filename);
171 			return(1);
172 		}
173 #define	DEC(c)	(((c) - ' ') & 077)		/* single character decode */
174 		/*
175 		 * `n' is used to avoid writing out all the characters
176 		 * at the end of the file.
177 		 */
178 		if ((n = DEC(*p)) <= 0)
179 			break;
180 		for (++p; n > 0; p += 4, n -= 3)
181 			if (n >= 3) {
182 				ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
183 				putchar(ch);
184 				ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
185 				putchar(ch);
186 				ch = DEC(p[2]) << 6 | DEC(p[3]);
187 				putchar(ch);
188 			}
189 			else {
190 				if (n >= 1) {
191 					ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
192 					putchar(ch);
193 				}
194 				if (n >= 2) {
195 					ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
196 					putchar(ch);
197 				}
198 				if (n >= 3) {
199 					ch = DEC(p[2]) << 6 | DEC(p[3]);
200 					putchar(ch);
201 				}
202 			}
203 	}
204 	if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) {
205 		(void)fprintf(stderr, "uudecode: %s: no \"end\" line.\n",
206 		    filename);
207 		return(1);
208 	}
209 	return(0);
210 }
211 
212 static void
213 usage()
214 {
215 	(void)fprintf(stderr, "usage: uudecode [-p] [file ...]\n");
216 	exit(1);
217 }
218