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