xref: /openbsd-src/usr.bin/uudecode/uudecode.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: uudecode.c,v 1.7 1998/09/15 15:59:44 millert 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.7 1998/09/15 15:59:44 millert 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 	extern int errno;
116 	struct passwd *pw;
117 	register int n;
118 	register char ch, *p;
119 	int mode, n1;
120 	char buf[MAXPATHLEN];
121 
122 	/* search for header line */
123 	do {
124 		if (!fgets(buf, sizeof(buf), stdin)) {
125 			(void)fprintf(stderr,
126 			    "uudecode: %s: no \"begin\" line\n", filename);
127 			return(1);
128 		}
129 	} while (strncmp(buf, "begin ", 6));
130 	(void)sscanf(buf, "begin %o %1023[^\n\r]", &mode, buf);
131 
132 	/* handle ~user/file format */
133 	if (buf[0] == '~') {
134 		if (!(p = strchr(buf, '/'))) {
135 			(void)fprintf(stderr, "uudecode: %s: illegal ~user.\n",
136 			    filename);
137 			return(1);
138 		}
139 		*p++ = NULL;
140 		if (!(pw = getpwnam(buf + 1))) {
141 			(void)fprintf(stderr, "uudecode: %s: no user %s.\n",
142 			    filename, buf);
143 			return(1);
144 		}
145 		n = strlen(pw->pw_dir);
146 		n1 = strlen(p);
147 		if (n + n1 + 2 > MAXPATHLEN) {
148 			(void)fprintf(stderr, "uudecode: %s: path too long.\n",
149 			    filename);
150 			return(1);
151 		}
152 		bcopy(p, buf + n + 1, n1 + 1);
153 		bcopy(pw->pw_dir, buf, n);
154 		buf[n] = '/';
155 	}
156 
157 	if (!tostdout) {
158 		/* create output file, set mode */
159 		if (!freopen(buf, "w", stdout) ||
160 		    fchmod(fileno(stdout), mode&0666)) {
161 			(void)fprintf(stderr, "uudecode: %s: %s: %s\n", buf,
162 			    filename, strerror(errno));
163 			return(1);
164 		}
165 	}
166 
167 	/* for each input line */
168 	for (;;) {
169 		if (!fgets(p = buf, sizeof(buf), stdin)) {
170 			(void)fprintf(stderr, "uudecode: %s: short file.\n",
171 			    filename);
172 			return(1);
173 		}
174 #define	DEC(c)	(((c) - ' ') & 077)		/* single character decode */
175 		/*
176 		 * `n' is used to avoid writing out all the characters
177 		 * at the end of the file.
178 		 */
179 		if ((n = DEC(*p)) <= 0)
180 			break;
181 		for (++p; n > 0; p += 4, n -= 3)
182 			if (n >= 3) {
183 				ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
184 				putchar(ch);
185 				ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
186 				putchar(ch);
187 				ch = DEC(p[2]) << 6 | DEC(p[3]);
188 				putchar(ch);
189 			}
190 			else {
191 				if (n >= 1) {
192 					ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
193 					putchar(ch);
194 				}
195 				if (n >= 2) {
196 					ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
197 					putchar(ch);
198 				}
199 				if (n >= 3) {
200 					ch = DEC(p[2]) << 6 | DEC(p[3]);
201 					putchar(ch);
202 				}
203 			}
204 	}
205 	if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) {
206 		(void)fprintf(stderr, "uudecode: %s: no \"end\" line.\n",
207 		    filename);
208 		return(1);
209 	}
210 	return(0);
211 }
212 
213 static void
214 usage()
215 {
216 	(void)fprintf(stderr, "usage: uudecode [-p] [file ...]\n");
217 	exit(1);
218 }
219