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