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