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