1 /* $OpenBSD: uuencode.c,v 1.15 2019/03/10 20:49:24 schwarze Exp $ */
2 /* $FreeBSD: uuencode.c,v 1.18 2004/01/22 07:23:35 grehan 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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Encode a file so it can be mailed to a remote system.
35 */
36
37 #include <sys/stat.h>
38
39 #include <netinet/in.h>
40
41 #include <err.h>
42 #include <resolv.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 void encode(void);
49 void base64_encode(void);
50 static void __dead usage(void);
51
52 FILE *output;
53 int mode;
54 char **av;
55
56 enum program_mode {
57 MODE_ENCODE,
58 MODE_B64ENCODE
59 } pmode;
60
61 int
main(int argc,char * argv[])62 main(int argc, char *argv[])
63 {
64 struct stat sb;
65 int base64, ch;
66 char *outfile;
67 extern char *__progname;
68 static const char *optstr[2] = {
69 "mo:",
70 "o:"
71 };
72
73 base64 = 0;
74 outfile = NULL;
75
76 pmode = MODE_ENCODE;
77 if (strcmp(__progname, "b64encode") == 0) {
78 base64 = 1;
79 pmode = MODE_B64ENCODE;
80 }
81
82 while ((ch = getopt(argc, argv, optstr[pmode])) != -1) {
83 switch (ch) {
84 case 'm':
85 base64 = 1;
86 break;
87 case 'o':
88 outfile = optarg;
89 break;
90 default:
91 usage();
92 }
93 }
94 argv += optind;
95 argc -= optind;
96
97 if (argc == 2 || outfile) {
98 if (pledge("stdio rpath wpath cpath", NULL) == -1)
99 err(1, "pledge");
100 } else {
101 if (pledge("stdio", NULL) == -1)
102 err(1, "pledge");
103 }
104
105 switch(argc) {
106 case 2: /* optional first argument is input file */
107 if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb))
108 err(1, "%s", *argv);
109 #define RWX (S_IRWXU|S_IRWXG|S_IRWXO)
110 mode = sb.st_mode & RWX;
111 ++argv;
112 break;
113 case 1:
114 #define RW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
115 mode = RW & ~umask(RW);
116 break;
117 default:
118 usage();
119 }
120
121 av = argv;
122
123 if (outfile != NULL) {
124 output = fopen(outfile, "w+");
125 if (output == NULL)
126 err(1, "unable to open %s for output", outfile);
127 } else
128 output = stdout;
129 if (base64)
130 base64_encode();
131 else
132 encode();
133 if (ferror(output))
134 errx(1, "write error");
135 return 0;
136 }
137
138 /* ENC is the basic 1 character encoding function to make a char printing */
139 #define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
140
141 /*
142 * Copy from in to out, encoding in base64 as you go along.
143 */
144 void
base64_encode(void)145 base64_encode(void)
146 {
147 /*
148 * Output must fit into 80 columns, chunks come in 4, leave 1.
149 */
150 #define GROUPS ((80 / 4) - 1)
151 unsigned char buf[3];
152 char buf2[sizeof(buf) * 2 + 1];
153 size_t n;
154 int rv, sequence;
155
156 sequence = 0;
157
158 fprintf(output, "begin-base64 %o %s\n", mode, *av);
159 while ((n = fread(buf, 1, sizeof(buf), stdin))) {
160 ++sequence;
161 rv = b64_ntop(buf, n, buf2, (sizeof(buf2) / sizeof(buf2[0])));
162 if (rv == -1)
163 errx(1, "b64_ntop: error encoding base64");
164 fprintf(output, "%s%s", buf2, (sequence % GROUPS) ? "" : "\n");
165 }
166 if (sequence % GROUPS)
167 fprintf(output, "\n");
168 fprintf(output, "====\n");
169 }
170
171 /*
172 * Copy from in to out, encoding as you go along.
173 */
174 void
encode(void)175 encode(void)
176 {
177 int ch, n;
178 char *p;
179 char buf[80];
180
181 (void)fprintf(output, "begin %o %s\n", mode, *av);
182 while ((n = fread(buf, 1, 45, stdin))) {
183 ch = ENC(n);
184 if (fputc(ch, output) == EOF)
185 break;
186 for (p = buf; n > 0; n -= 3, p += 3) {
187 /* Pad with nulls if not a multiple of 3. */
188 if (n < 3) {
189 p[2] = '\0';
190 if (n < 2)
191 p[1] = '\0';
192 }
193 ch = *p >> 2;
194 ch = ENC(ch);
195 if (fputc(ch, output) == EOF)
196 break;
197 ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
198 ch = ENC(ch);
199 if (fputc(ch, output) == EOF)
200 break;
201 ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
202 ch = ENC(ch);
203 if (fputc(ch, output) == EOF)
204 break;
205 ch = p[2] & 077;
206 ch = ENC(ch);
207 if (fputc(ch, output) == EOF)
208 break;
209 }
210 if (fputc('\n', output) == EOF)
211 break;
212 }
213 if (ferror(stdin))
214 errx(1, "read error");
215 (void)fprintf(output, "%c\nend\n", ENC('\0'));
216 }
217
218 static void __dead
usage(void)219 usage(void)
220 {
221 switch (pmode) {
222 case MODE_ENCODE:
223 (void)fprintf(stderr,
224 "usage: uuencode [-m] [-o output_file] [file] name\n");
225 break;
226 case MODE_B64ENCODE:
227 (void)fprintf(stderr,
228 "usage: b64encode [-o output_file] [file] name\n");
229 break;
230 }
231 exit(1);
232 }
233