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