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