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 * 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 #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 #if 0 40 #ifndef lint 41 static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 42 #endif /* not lint */ 43 #endif 44 45 #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 46 __FBSDID("$FreeBSD$"); 47 48 /* 49 * Receive printer jobs from the network, queue them and 50 * start the printer daemon. 51 */ 52 #include <sys/param.h> 53 #include <sys/mount.h> 54 #include <sys/stat.h> 55 56 #include <unistd.h> 57 #include <signal.h> 58 #include <fcntl.h> 59 #include <dirent.h> 60 #include <errno.h> 61 #include <syslog.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include "lp.h" 66 #include "lp.local.h" 67 #include "ctlinfo.h" 68 #include "extern.h" 69 #include "pathnames.h" 70 71 #define ack() (void) write(STDOUT_FILENO, sp, (size_t)1); 72 73 /* 74 * The buffer size to use when reading/writing spool files. 75 */ 76 #define SPL_BUFSIZ BUFSIZ 77 78 static char dfname[NAME_MAX]; /* data files */ 79 static int minfree; /* keep at least minfree blocks available */ 80 static const char *sp = ""; 81 static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 82 83 static int chksize(int _size); 84 static void frecverr(const char *_msg, ...) __printf0like(1, 2); 85 static int noresponse(void); 86 static void rcleanup(int _signo); 87 static int read_number(const char *_fn); 88 static int readfile(struct printer *_pp, char *_file, size_t _size); 89 static int readjob(struct printer *_pp); 90 91 92 void 93 recvjob(const char *printer) 94 { 95 struct stat stb; 96 int status; 97 struct printer myprinter, *pp = &myprinter; 98 99 /* 100 * Perform lookup for printer name or abbreviation 101 */ 102 init_printer(pp); 103 status = getprintcap(printer, pp); 104 switch (status) { 105 case PCAPERR_OSERR: 106 frecverr("cannot open printer description file"); 107 break; 108 case PCAPERR_NOTFOUND: 109 frecverr("unknown printer %s", printer); 110 break; 111 case PCAPERR_TCLOOP: 112 fatal(pp, "potential reference loop detected in printcap file"); 113 default: 114 break; 115 } 116 117 (void) close(STDERR_FILENO); /* set up log file */ 118 if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 119 syslog(LOG_ERR, "%s: %m", pp->log_file); 120 (void) open(_PATH_DEVNULL, O_WRONLY); 121 } 122 123 if (chdir(pp->spool_dir) < 0) 124 frecverr("%s: chdir(%s): %s", pp->printer, pp->spool_dir, 125 strerror(errno)); 126 if (stat(pp->lock_file, &stb) == 0) { 127 if (stb.st_mode & 010) { 128 /* queue is disabled */ 129 putchar('\1'); /* return error code */ 130 exit(1); 131 } 132 } else if (stat(pp->spool_dir, &stb) < 0) 133 frecverr("%s: stat(%s): %s", pp->printer, pp->spool_dir, 134 strerror(errno)); 135 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 136 signal(SIGTERM, rcleanup); 137 signal(SIGPIPE, rcleanup); 138 139 if (readjob(pp)) 140 printjob(pp); 141 } 142 143 /* 144 * Read printer jobs sent by lpd and copy them to the spooling directory. 145 * Return the number of jobs successfully transferred. 146 */ 147 static int 148 readjob(struct printer *pp) 149 { 150 register int size; 151 int cfcnt, dfcnt; 152 char *cp, *clastp, *errmsg; 153 char givenid[32], givenhost[MAXHOSTNAMELEN]; 154 155 ack(); 156 cfcnt = 0; 157 dfcnt = 0; 158 for (;;) { 159 /* 160 * Read a command to tell us what to do 161 */ 162 cp = line; 163 clastp = line + sizeof(line) - 1; 164 do { 165 size = read(STDOUT_FILENO, cp, (size_t)1); 166 if (size != (ssize_t)1) { 167 if (size < (ssize_t)0) { 168 frecverr("%s: lost connection", 169 pp->printer); 170 /*NOTREACHED*/ 171 } 172 return (cfcnt); 173 } 174 } while ((*cp++ != '\n') && (cp <= clastp)); 175 if (cp > clastp) { 176 frecverr("%s: readjob overflow", pp->printer); 177 /*NOTREACHED*/ 178 } 179 *--cp = '\0'; 180 cp = line; 181 switch (*cp++) { 182 case '\1': /* cleanup because data sent was bad */ 183 rcleanup(0); 184 continue; 185 186 case '\2': /* read cf file */ 187 size = 0; 188 dfcnt = 0; 189 while (*cp >= '0' && *cp <= '9') 190 size = size * 10 + (*cp++ - '0'); 191 if (*cp++ != ' ') 192 break; 193 /* 194 * host name has been authenticated, we use our 195 * view of the host name since we may be passed 196 * something different than what gethostbyaddr() 197 * returns 198 */ 199 strlcpy(cp + 6, from_host, sizeof(line) 200 + (size_t)(line - cp - 6)); 201 if (strchr(cp, '/')) { 202 frecverr("readjob: %s: illegal path name", cp); 203 /*NOTREACHED*/ 204 } 205 strlcpy(tfname, cp, sizeof(tfname)); 206 tfname[sizeof (tfname) - 1] = '\0'; 207 tfname[0] = 't'; 208 if (!chksize(size)) { 209 (void) write(STDOUT_FILENO, "\2", (size_t)1); 210 continue; 211 } 212 if (!readfile(pp, tfname, (size_t)size)) { 213 rcleanup(0); 214 continue; 215 } 216 errmsg = ctl_renametf(pp->printer, tfname); 217 tfname[0] = '\0'; 218 if (errmsg != NULL) { 219 frecverr("%s: %s", pp->printer, errmsg); 220 /*NOTREACHED*/ 221 } 222 cfcnt++; 223 continue; 224 225 case '\3': /* read df file */ 226 *givenid = '\0'; 227 *givenhost = '\0'; 228 size = 0; 229 while (*cp >= '0' && *cp <= '9') 230 size = size * 10 + (*cp++ - '0'); 231 if (*cp++ != ' ') 232 break; 233 if (strchr(cp, '/')) { 234 frecverr("readjob: %s: illegal path name", cp); 235 /*NOTREACHED*/ 236 } 237 if (!chksize(size)) { 238 (void) write(STDOUT_FILENO, "\2", (size_t)1); 239 continue; 240 } 241 strlcpy(dfname, cp, sizeof(dfname)); 242 dfcnt++; 243 trstat_init(pp, dfname, dfcnt); 244 (void) readfile(pp, dfname, (size_t)size); 245 trstat_write(pp, TR_RECVING, (size_t)size, givenid, 246 from_host, givenhost); 247 continue; 248 } 249 frecverr("protocol screwup: %s", line); 250 /*NOTREACHED*/ 251 } 252 } 253 254 /* 255 * Read files send by lpd and copy them to the spooling directory. 256 */ 257 static int 258 readfile(struct printer *pp, char *file, size_t size) 259 { 260 register char *cp; 261 char buf[SPL_BUFSIZ]; 262 size_t amt, i; 263 int err, fd, j; 264 265 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 266 if (fd < 0) { 267 frecverr("%s: readfile: error on open(%s): %s", 268 pp->printer, file, strerror(errno)); 269 /*NOTREACHED*/ 270 } 271 ack(); 272 err = 0; 273 for (i = 0; i < size; i += SPL_BUFSIZ) { 274 amt = SPL_BUFSIZ; 275 cp = buf; 276 if (i + amt > size) 277 amt = size - i; 278 do { 279 j = read(STDOUT_FILENO, cp, amt); 280 if (j <= 0) { 281 frecverr("%s: lost connection", pp->printer); 282 /*NOTREACHED*/ 283 } 284 amt -= j; 285 cp += j; 286 } while (amt > 0); 287 amt = SPL_BUFSIZ; 288 if (i + amt > size) 289 amt = size - i; 290 if (write(fd, buf, amt) != (ssize_t)amt) { 291 err++; 292 break; 293 } 294 } 295 (void) close(fd); 296 if (err) { 297 frecverr("%s: write error on close(%s)", pp->printer, file); 298 /*NOTREACHED*/ 299 } 300 if (noresponse()) { /* file sent had bad data in it */ 301 if (strchr(file, '/') == NULL) 302 (void) unlink(file); 303 return (0); 304 } 305 ack(); 306 return (1); 307 } 308 309 static int 310 noresponse(void) 311 { 312 char resp; 313 314 if (read(STDOUT_FILENO, &resp, (size_t)1) != 1) { 315 frecverr("lost connection in noresponse()"); 316 /*NOTREACHED*/ 317 } 318 if (resp == '\0') 319 return(0); 320 return(1); 321 } 322 323 /* 324 * Check to see if there is enough space on the disk for size bytes. 325 * 1 == OK, 0 == Not OK. 326 */ 327 static int 328 chksize(int size) 329 { 330 int64_t spacefree; 331 struct statfs sfb; 332 333 if (statfs(".", &sfb) < 0) { 334 syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 335 return (1); 336 } 337 spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 338 size = (size + 511) / 512; 339 if (minfree + size > spacefree) 340 return(0); 341 return(1); 342 } 343 344 static int 345 read_number(const char *fn) 346 { 347 char lin[80]; 348 register FILE *fp; 349 350 if ((fp = fopen(fn, "r")) == NULL) 351 return (0); 352 if (fgets(lin, sizeof(lin), fp) == NULL) { 353 fclose(fp); 354 return (0); 355 } 356 fclose(fp); 357 return (atoi(lin)); 358 } 359 360 /* 361 * Remove all the files associated with the current job being transferred. 362 */ 363 static void 364 rcleanup(int signo __unused) 365 { 366 if (tfname[0] && strchr(tfname, '/') == NULL) 367 (void) unlink(tfname); 368 if (dfname[0] && strchr(dfname, '/') == NULL) { 369 do { 370 do 371 (void) unlink(dfname); 372 while (dfname[2]-- != 'A'); 373 dfname[2] = 'z'; 374 } while (dfname[0]-- != 'd'); 375 } 376 dfname[0] = '\0'; 377 } 378 379 #include <stdarg.h> 380 381 static void 382 frecverr(const char *msg, ...) 383 { 384 va_list ap; 385 va_start(ap, msg); 386 syslog(LOG_ERR, "Error receiving job from %s:", from_host); 387 vsyslog(LOG_ERR, msg, ap); 388 va_end(ap); 389 /* 390 * rcleanup is not called until AFTER logging the error message, 391 * because rcleanup will zap some variables which may have been 392 * supplied as parameters for that msg... 393 */ 394 rcleanup(0); 395 /* 396 * Add a minimal delay before returning the final error code to 397 * the sending host. This just in case that machine responds 398 * this error by INSTANTLY retrying (and instantly re-failing...). 399 * It would be stupid of the sending host to do that, but if there 400 * was a broken implementation which did it, the result might be 401 * obscure performance problems and a flood of syslog messages on 402 * the receiving host. 403 */ 404 sleep(2); /* a paranoid throttling measure */ 405 putchar('\1'); /* return error code */ 406 exit(1); 407 } 408