1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1983, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 static char sccsid[] = "@(#)uuencode.c 8.2 (Berkeley) 4/2/94"; 41 #endif /* not lint */ 42 #endif 43 #include <sys/cdefs.h> 44 /* 45 * uuencode [input] output 46 * 47 * Encode a file so it can be mailed to a remote system. 48 */ 49 #include <sys/param.h> 50 #include <sys/socket.h> 51 #include <sys/stat.h> 52 53 #include <netinet/in.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <libgen.h> 58 #include <resolv.h> 59 #include <stdio.h> 60 #include <stdbool.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 65 extern int main_encode(int, char *[]); 66 extern int main_base64_encode(const char *, const char *); 67 68 static void encode(void); 69 static void base64_encode(void); 70 static int arg_to_col(const char *); 71 static void usage(void) __dead2; 72 73 static FILE *output; 74 static int mode; 75 static bool raw; 76 static char **av; 77 static int columns = 76; 78 79 int 80 main_base64_encode(const char *in, const char *w) 81 { 82 raw = 1; 83 if (in != NULL && freopen(in, "r", stdin) == NULL) 84 err(1, "%s", in); 85 output = stdout; 86 if (w != NULL) 87 columns = arg_to_col(w); 88 base64_encode(); 89 if (ferror(output)) 90 errx(1, "write error"); 91 exit(0); 92 } 93 94 int 95 main_encode(int argc, char *argv[]) 96 { 97 struct stat sb; 98 bool base64; 99 int ch; 100 const char *outfile; 101 102 base64 = false; 103 outfile = NULL; 104 105 if (strcmp(basename(argv[0]), "b64encode") == 0) 106 base64 = 1; 107 108 while ((ch = getopt(argc, argv, "mo:rw:")) != -1) { 109 switch (ch) { 110 case 'm': 111 base64 = true; 112 break; 113 case 'o': 114 outfile = optarg; 115 break; 116 case 'r': 117 raw = true; 118 break; 119 case 'w': 120 columns = arg_to_col(optarg); 121 break; 122 case '?': 123 default: 124 usage(); 125 } 126 } 127 argv += optind; 128 argc -= optind; 129 130 switch (argc) { 131 case 2: /* optional first argument is input file */ 132 if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb)) 133 err(1, "%s", *argv); 134 #define RWX (S_IRWXU|S_IRWXG|S_IRWXO) 135 mode = sb.st_mode & RWX; 136 ++argv; 137 break; 138 case 1: 139 #define RW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) 140 mode = RW & ~umask(RW); 141 break; 142 case 0: 143 default: 144 usage(); 145 } 146 147 av = argv; 148 149 if (outfile != NULL) { 150 output = fopen(outfile, "w+"); 151 if (output == NULL) 152 err(1, "unable to open %s for output", outfile); 153 } else 154 output = stdout; 155 if (base64) 156 base64_encode(); 157 else 158 encode(); 159 if (ferror(output)) 160 errx(1, "write error"); 161 exit(0); 162 } 163 164 /* ENC is the basic 1 character encoding function to make a char printing */ 165 #define ENC(c) ((c) ? ((c) & 077) + ' ': '`') 166 167 /* 168 * Copy from in to out, encoding in base64 as you go along. 169 */ 170 static void 171 base64_encode(void) 172 { 173 /* 174 * This buffer's length should be a multiple of 24 bits to avoid "=" 175 * padding. Once it reached ~1 KB, further expansion didn't improve 176 * performance for me. 177 */ 178 unsigned char buf[1023]; 179 char buf2[sizeof(buf) * 2 + 1]; 180 size_t n; 181 unsigned carry = 0; 182 int rv, written; 183 184 if (!raw) 185 fprintf(output, "begin-base64 %o %s\n", mode, *av); 186 while ((n = fread(buf, 1, sizeof(buf), stdin))) { 187 rv = b64_ntop(buf, n, buf2, nitems(buf2)); 188 if (rv == -1) 189 errx(1, "b64_ntop: error encoding base64"); 190 if (columns == 0) { 191 fputs(buf2, output); 192 continue; 193 } 194 for (int i = 0; i < rv; i += written) { 195 written = fprintf(output, "%.*s", columns - carry, 196 &buf2[i]); 197 198 carry = (carry + written) % columns; 199 if (carry == 0) 200 fputc('\n', output); 201 } 202 } 203 if (columns == 0 || carry != 0) 204 fputc('\n', output); 205 if (!raw) 206 fprintf(output, "====\n"); 207 } 208 209 /* 210 * Copy from in to out, encoding as you go along. 211 */ 212 static void 213 encode(void) 214 { 215 int ch, n; 216 char *p; 217 char buf[80]; 218 219 if (!raw) 220 (void)fprintf(output, "begin %o %s\n", mode, *av); 221 while ((n = fread(buf, 1, 45, stdin))) { 222 ch = ENC(n); 223 if (fputc(ch, output) == EOF) 224 break; 225 for (p = buf; n > 0; n -= 3, p += 3) { 226 /* Pad with nulls if not a multiple of 3. */ 227 if (n < 3) { 228 p[2] = '\0'; 229 if (n < 2) 230 p[1] = '\0'; 231 } 232 ch = *p >> 2; 233 ch = ENC(ch); 234 if (fputc(ch, output) == EOF) 235 break; 236 ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017); 237 ch = ENC(ch); 238 if (fputc(ch, output) == EOF) 239 break; 240 ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); 241 ch = ENC(ch); 242 if (fputc(ch, output) == EOF) 243 break; 244 ch = p[2] & 077; 245 ch = ENC(ch); 246 if (fputc(ch, output) == EOF) 247 break; 248 } 249 if (fputc('\n', output) == EOF) 250 break; 251 } 252 if (ferror(stdin)) 253 errx(1, "read error"); 254 if (!raw) 255 (void)fprintf(output, "%c\nend\n", ENC('\0')); 256 } 257 258 static int 259 arg_to_col(const char *w) 260 { 261 char *ep; 262 long option; 263 264 errno = 0; 265 option = strtol(w, &ep, 10); 266 if (option > INT_MAX) 267 errno = ERANGE; 268 else if (ep[0] != '\0') 269 errno = EINVAL; 270 if (errno != 0) 271 err(2, NULL); 272 273 if (option < 0) { 274 errno = EINVAL; 275 err(2, "columns argument must be non-negative"); 276 } 277 return (option); 278 } 279 280 static void 281 usage(void) 282 { 283 (void)fprintf(stderr, 284 "usage: uuencode [-m] [-o outfile] [infile] remotefile\n" 285 " b64encode [-o outfile] [infile] remotefile\n"); 286 exit(1); 287 } 288