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