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