1 /* $OpenBSD: recvjob.c,v 1.26 2015/01/16 06:40:18 deraadt Exp $ */ 2 /* $NetBSD: recvjob.c,v 1.14 2001/12/04 22:52:44 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * Receive printer jobs from the network, queue them and 36 * start the printer daemon. 37 */ 38 #include <sys/types.h> 39 #include <sys/mount.h> 40 #include <sys/stat.h> 41 42 #include <unistd.h> 43 #include <signal.h> 44 #include <fcntl.h> 45 #include <dirent.h> 46 #include <syslog.h> 47 #include <stdio.h> 48 #include <errno.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <stdarg.h> 52 #include <limits.h> 53 #include "lp.h" 54 #include "lp.local.h" 55 #include "extern.h" 56 #include "pathnames.h" 57 58 #define ack() (void)write(STDOUT_FILENO, sp, 1); 59 60 static char dfname[NAME_MAX]; /* data files */ 61 static int minfree; /* keep at least minfree blocks available */ 62 static char *sp = ""; 63 static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 64 65 static int chksize(int); 66 static void frecverr(const char *, ...) 67 __attribute__((__format__(__printf__, 1, 2))); 68 static int noresponse(void); 69 static void rcleanup(int); 70 static int read_number(char *); 71 static int readfile(char *, int); 72 static int readjob(void); 73 74 75 void 76 recvjob(void) 77 { 78 struct stat stb; 79 int status; 80 81 /* 82 * Perform lookup for printer name or abbreviation 83 */ 84 if ((status = cgetent(&bp, printcapdb, printer)) == -2) 85 frecverr("cannot open printer description file"); 86 else if (status == -1) 87 frecverr("unknown printer %s", printer); 88 else if (status == -3) 89 fatal("potential reference loop detected in printcap file"); 90 91 if (cgetstr(bp, "lf", &LF) == -1) 92 LF = _PATH_CONSOLE; 93 if (cgetstr(bp, "sd", &SD) == -1) 94 SD = _PATH_DEFSPOOL; 95 if (cgetstr(bp, "lo", &LO) == -1) 96 LO = DEFLOCK; 97 98 (void)close(2); /* set up log file */ 99 PRIV_START; 100 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 101 syslog(LOG_ERR, "%s: %m", LF); 102 (void)open(_PATH_DEVNULL, O_WRONLY); 103 } 104 PRIV_END; 105 106 if (chdir(SD) < 0) 107 frecverr("%s: %s: %m", printer, SD); 108 if (stat(LO, &stb) == 0) { 109 if (stb.st_mode & 010) { 110 /* queue is disabled */ 111 putchar('\1'); /* return error code */ 112 exit(1); 113 } 114 } else if (stat(SD, &stb) < 0) 115 frecverr("%s: %s: %m", printer, SD); 116 117 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 118 signal(SIGTERM, rcleanup); 119 signal(SIGPIPE, rcleanup); 120 121 if (readjob()) 122 printjob(); 123 } 124 125 /* 126 * Read printer jobs sent by lpd and copy them to the spooling directory. 127 * Return the number of jobs successfully transferred. 128 */ 129 static int 130 readjob(void) 131 { 132 int size, nfiles; 133 char *cp; 134 135 ack(); 136 nfiles = 0; 137 for (;;) { 138 /* 139 * Read a command to tell us what to do 140 */ 141 cp = line; 142 do { 143 if ((size = read(STDOUT_FILENO, cp, 1)) != 1) { 144 if (size < 0) 145 frecverr("%s: Lost connection", 146 printer); 147 return(nfiles); 148 } 149 } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 150 if (cp - line + 1 >= sizeof(line)) 151 frecverr("readjob overflow"); 152 *--cp = '\0'; 153 cp = line; 154 switch (*cp++) { 155 case '\1': /* cleanup because data sent was bad */ 156 rcleanup(0); 157 continue; 158 159 case '\2': /* read cf file */ 160 size = 0; 161 while (*cp >= '0' && *cp <= '9') 162 size = size * 10 + (*cp++ - '0'); 163 if (*cp++ != ' ') 164 break; 165 /* 166 * host name has been authenticated, we use our 167 * view of the host name since we may be passed 168 * something different than what gethostbyaddr() 169 * returns 170 */ 171 strlcpy(cp + 6, from, sizeof(line) + line - cp - 6); 172 if (strchr(cp, '/')) 173 frecverr("readjob: %s: illegal path name", cp); 174 strlcpy(tfname, cp, sizeof(tfname)); 175 tfname[0] = 't'; 176 if (!chksize(size)) { 177 (void)write(STDOUT_FILENO, "\2", 1); 178 continue; 179 } 180 /* 181 * XXX 182 * We blindly believe what the remote host puts 183 * for the path to the df file. In general this 184 * is OK since we don't allow paths with '/' in 185 * them. Still, it would be better to sanity 186 * check the cf file sent to us and make the 187 * df name match the cf name we used. That way 188 * we avoid any possible collisions. 189 */ 190 if (!readfile(tfname, size)) { 191 rcleanup(0); 192 continue; 193 } 194 if (link(tfname, cp) < 0) 195 frecverr("link %s %s: %m", tfname, cp); 196 (void)unlink(tfname); 197 tfname[0] = '\0'; 198 nfiles++; 199 continue; 200 201 case '\3': /* read df file */ 202 size = 0; 203 while (*cp >= '0' && *cp <= '9') 204 size = size * 10 + (*cp++ - '0'); 205 if (*cp++ != ' ') 206 break; 207 if (strchr(cp, '/')) 208 frecverr("readjob: %s: illegal path name", cp); 209 if (!chksize(size)) { 210 (void)write(STDOUT_FILENO, "\2", 1); 211 continue; 212 } 213 (void)strlcpy(dfname, cp, sizeof(dfname)); 214 (void)readfile(dfname, size); 215 continue; 216 } 217 frecverr("protocol screwup: %s", line); 218 } 219 } 220 221 /* 222 * Read files send by lpd and copy them to the spooling directory. 223 */ 224 static int 225 readfile(char *file, int size) 226 { 227 char *cp; 228 char buf[BUFSIZ]; 229 int i, j, amt; 230 int fd, err; 231 232 if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD)) < 0) 233 frecverr("readfile: %s: illegal path name: %m", file); 234 ack(); 235 err = 0; 236 for (i = 0; i < size; i += BUFSIZ) { 237 amt = BUFSIZ; 238 cp = buf; 239 if (i + amt > size) 240 amt = size - i; 241 do { 242 j = read(STDOUT_FILENO, cp, amt); 243 if (j <= 0) 244 frecverr("Lost connection"); 245 amt -= j; 246 cp += j; 247 } while (amt > 0); 248 amt = BUFSIZ; 249 if (i + amt > size) 250 amt = size - i; 251 if (write(fd, buf, amt) != amt) { 252 err++; 253 break; 254 } 255 } 256 (void)close(fd); 257 if (err) 258 frecverr("%s: write error", file); 259 if (noresponse()) { /* file sent had bad data in it */ 260 if (strchr(file, '/') == NULL) 261 (void)unlink(file); 262 return(0); 263 } 264 ack(); 265 return(1); 266 } 267 268 static int 269 noresponse(void) 270 { 271 char resp; 272 273 if (read(STDOUT_FILENO, &resp, 1) != 1) 274 frecverr("Lost connection"); 275 if (resp == '\0') 276 return(0); 277 return(1); 278 } 279 280 /* 281 * Check to see if there is enough space on the disk for size bytes. 282 * 1 == OK, 0 == Not OK. 283 */ 284 static int 285 chksize(int size) 286 { 287 int64_t spacefree; 288 struct statfs sfb; 289 290 if (size <= 0) 291 return (0); 292 if (statfs(".", &sfb) < 0) { 293 syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 294 return (1); 295 } 296 spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 297 size = (size + 511) / 512; 298 if (minfree + size > spacefree) 299 return(0); 300 return(1); 301 } 302 303 static int 304 read_number(char *fn) 305 { 306 char lin[80]; 307 FILE *fp; 308 309 if ((fp = fopen(fn, "r")) == NULL) 310 return (0); 311 if (fgets(lin, sizeof(lin), fp) == NULL) { 312 fclose(fp); 313 return (0); 314 } 315 fclose(fp); 316 return (atoi(lin)); 317 } 318 319 /* 320 * Remove all the files associated with the current job being transferred. 321 */ 322 static void 323 rcleanup(int signo) 324 { 325 int save_errno = errno; 326 327 if (tfname[0] && strchr(tfname, '/') == NULL) 328 (void)unlink(tfname); 329 if (dfname[0] && strchr(dfname, '/') == NULL) { 330 do { 331 do 332 (void)unlink(dfname); 333 while (dfname[2]-- != 'A') 334 ; 335 dfname[2] = 'z'; 336 } while (dfname[0]-- != 'd'); 337 } 338 dfname[0] = '\0'; 339 errno = save_errno; 340 } 341 342 static void 343 frecverr(const char *msg, ...) 344 { 345 extern char fromb[]; 346 va_list ap; 347 348 va_start(ap, msg); 349 rcleanup(0); 350 syslog(LOG_ERR, "%s", fromb); 351 vsyslog(LOG_ERR, msg, ap); 352 va_end(ap); 353 putchar('\1'); /* return error code */ 354 exit(1); 355 } 356