1 /* $OpenBSD: common.c,v 1.34 2012/03/04 04:05:15 fgsch Exp $ */ 2 /* $NetBSD: common.c,v 1.21 2000/08/09 14:28:50 itojun Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/stat.h> 40 #include <sys/time.h> 41 42 #include <sys/socket.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <netdb.h> 46 47 #include <dirent.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <string.h> 54 #include <signal.h> 55 #include <stdarg.h> 56 #include <ifaddrs.h> 57 #include "lp.h" 58 #include "pathnames.h" 59 60 /* 61 * Routines and data common to all the line printer functions. 62 */ 63 64 char *AF; /* accounting file */ 65 long BR; /* baud rate if lp is a tty */ 66 char *CF; /* name of cifplot filter (per job) */ 67 char *DF; /* name of tex filter (per job) */ 68 long DU; /* daemon user-id */ 69 long FC; /* flags to clear if lp is a tty */ 70 char *FF; /* form feed string */ 71 long FS; /* flags to set if lp is a tty */ 72 char *GF; /* name of graph(1G) filter (per job) */ 73 long HL; /* print header last */ 74 char *IF; /* name of input filter (created per job) */ 75 char *LF; /* log file for error messages */ 76 char *LO; /* lock file name */ 77 char *LP; /* line printer device name */ 78 long MC; /* maximum number of copies allowed */ 79 char *MS; /* stty flags to set if lp is a tty */ 80 long MX; /* maximum number of blocks to copy */ 81 char *NF; /* name of ditroff filter (per job) */ 82 char *OF; /* name of output filter (created once) */ 83 long PL; /* page length */ 84 long PW; /* page width */ 85 long PX; /* page width in pixels */ 86 long PY; /* page length in pixels */ 87 char *RF; /* name of fortran text filter (per job) */ 88 char *RG; /* restricted group */ 89 char *RM; /* remote machine name */ 90 char *RP; /* remote printer name */ 91 long RS; /* restricted to those with local accounts */ 92 long RW; /* open LP for reading and writing */ 93 long SB; /* short banner instead of normal header */ 94 long SC; /* suppress multiple copies */ 95 char *SD; /* spool directory */ 96 long SF; /* suppress FF on each print job */ 97 long SH; /* suppress header page */ 98 char *ST; /* status file name */ 99 char *TF; /* name of troff filter (per job) */ 100 char *TR; /* trailer string to be output when Q empties */ 101 char *VF; /* name of vplot filter (per job) */ 102 long XC; /* flags to clear for local mode */ 103 long XS; /* flags to set for local mode */ 104 105 char line[BUFSIZ]; 106 int remote; /* true if sending files to a remote host */ 107 108 static int compar(const void *, const void *); 109 110 /* 111 * Create a TCP connection to host "rhost" at port "rport". 112 * If rport == 0, then use the printer service port. 113 * Most of this code comes from rcmd.c. 114 */ 115 int 116 getport(char *rhost, int rport) 117 { 118 struct addrinfo hints, *res, *r; 119 u_int timo = 1; 120 int s, lport = IPPORT_RESERVED - 1; 121 int error; 122 int refuse, trial; 123 char pbuf[NI_MAXSERV]; 124 125 /* 126 * Get the host address and port number to connect to. 127 */ 128 if (rhost == NULL) 129 fatal("no remote host to connect to"); 130 memset(&hints, 0, sizeof(hints)); 131 hints.ai_family = PF_UNSPEC; 132 hints.ai_socktype = SOCK_STREAM; 133 if (rport) 134 snprintf(pbuf, sizeof(pbuf), "%d", rport); 135 else 136 snprintf(pbuf, sizeof(pbuf), "printer"); 137 siginterrupt(SIGINT, 1); 138 error = getaddrinfo(rhost, pbuf, &hints, &res); 139 siginterrupt(SIGINT, 0); 140 if (error) 141 fatal("printer/tcp: %s", gai_strerror(error)); 142 143 /* 144 * Try connecting to the server. 145 */ 146 retry: 147 s = -1; 148 refuse = trial = 0; 149 for (r = res; r; r = r->ai_next) { 150 trial++; 151 retryport: 152 PRIV_START; 153 s = rresvport_af(&lport, r->ai_family); 154 PRIV_END; 155 if (s < 0) { 156 /* fall back to non-privileged port */ 157 if (errno != EACCES || 158 (s = socket(r->ai_family, SOCK_STREAM, 0)) < 0) { 159 freeaddrinfo(res); 160 return(-1); 161 } 162 } 163 siginterrupt(SIGINT, 1); 164 if (connect(s, r->ai_addr, r->ai_addrlen) < 0) { 165 error = errno; 166 siginterrupt(SIGINT, 0); 167 (void)close(s); 168 s = -1; 169 errno = error; 170 if (errno == EADDRINUSE) { 171 lport--; 172 goto retryport; 173 } else if (errno == ECONNREFUSED) 174 refuse++; 175 continue; 176 } else { 177 siginterrupt(SIGINT, 0); 178 break; 179 } 180 } 181 if (s < 0 && trial == refuse && timo <= 16) { 182 sleep(timo); 183 timo *= 2; 184 goto retry; 185 } 186 if (res) 187 freeaddrinfo(res); 188 189 /* Don't worry if we get an error from setsockopt(). */ 190 trial = 1; 191 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &trial, sizeof(trial)); 192 193 return(s); 194 } 195 196 /* 197 * Getline reads a line from the control file cfp, removes tabs, converts 198 * new-line to null and leaves it in line. 199 * Returns 0 at EOF or the number of characters read. 200 */ 201 int 202 get_line(FILE *cfp) 203 { 204 int linel = 0; 205 char *lp = line; 206 int c; 207 208 while ((c = getc(cfp)) != '\n' && linel+1<sizeof(line)) { 209 if (c == EOF) 210 return(0); 211 if (c == '\t') { 212 do { 213 *lp++ = ' '; 214 linel++; 215 } while ((linel & 07) != 0 && linel+1 < sizeof(line)); 216 continue; 217 } 218 *lp++ = c; 219 linel++; 220 } 221 *lp++ = '\0'; 222 return(linel); 223 } 224 225 /* 226 * Scan the current directory and make a list of daemon files sorted by 227 * creation time. 228 * Return the number of entries and a pointer to the list. 229 */ 230 int 231 getq(struct queue ***namelist) 232 { 233 struct dirent *d; 234 struct queue *q, **queue = NULL; 235 size_t nitems = 0, arraysz; 236 struct stat stbuf; 237 DIR *dirp; 238 239 PRIV_START; 240 dirp = opendir(SD); 241 PRIV_END; 242 if (dirp == NULL) 243 return(-1); 244 if (fstat(dirfd(dirp), &stbuf) < 0) 245 goto errdone; 246 247 /* 248 * Estimate the array size by taking the size of the directory file 249 * and dividing it by a multiple of the minimum size entry. 250 */ 251 arraysz = (stbuf.st_size / 24); 252 queue = (struct queue **)calloc(arraysz, sizeof(struct queue *)); 253 if (queue == NULL) 254 goto errdone; 255 256 while ((d = readdir(dirp)) != NULL) { 257 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 258 continue; /* daemon control files only */ 259 PRIV_START; 260 if (stat(d->d_name, &stbuf) < 0) { 261 PRIV_END; 262 continue; /* Doesn't exist */ 263 } 264 PRIV_END; 265 q = (struct queue *)malloc(sizeof(struct queue)); 266 if (q == NULL) 267 goto errdone; 268 q->q_time = stbuf.st_mtime; 269 strlcpy(q->q_name, d->d_name, sizeof(q->q_name)); 270 271 /* 272 * Check to make sure the array has space left and 273 * realloc the maximum size. 274 */ 275 if (nitems == arraysz) { 276 struct queue **newqueue; 277 size_t newarraysz = arraysz * 2; 278 newqueue = (struct queue **)realloc(queue, 279 newarraysz * sizeof(struct queue *)); 280 if (newqueue == NULL) { 281 free(q); 282 goto errdone; 283 } 284 queue = newqueue; 285 arraysz = newarraysz; 286 } 287 queue[nitems++] = q; 288 } 289 closedir(dirp); 290 if (nitems) 291 qsort(queue, nitems, sizeof(struct queue *), compar); 292 *namelist = queue; 293 return(nitems); 294 295 errdone: 296 if (queue != NULL) { 297 while (nitems--) 298 free(queue[nitems]); 299 free(queue); 300 } 301 closedir(dirp); 302 return(-1); 303 } 304 305 /* 306 * Compare modification times. 307 */ 308 static int 309 compar(const void *v1, const void *v2) 310 { 311 struct queue *p1 = *(struct queue **)v1; 312 struct queue *p2 = *(struct queue **)v2; 313 314 return(p1->q_time - p2->q_time); 315 } 316 317 /* 318 * Figure out whether the local machine is the same 319 * as the remote machine (RM) entry (if it exists). 320 */ 321 char * 322 checkremote(void) 323 { 324 char lname[NI_MAXHOST], rname[NI_MAXHOST]; 325 struct addrinfo hints, *res, *res0; 326 static char errbuf[128]; 327 int error; 328 struct ifaddrs *ifap, *ifa; 329 const int niflags = NI_NUMERICHOST; 330 #ifdef __KAME__ 331 struct sockaddr_in6 sin6; 332 struct sockaddr_in6 *sin6p; 333 #endif 334 335 remote = 0; /* assume printer is local on failure */ 336 337 if (RM == NULL || *RM == '\0') 338 return NULL; 339 340 /* get the local interface addresses */ 341 siginterrupt(SIGINT, 1); 342 if (getifaddrs(&ifap) < 0) { 343 (void)snprintf(errbuf, sizeof(errbuf), 344 "unable to get local interface address: %s", 345 strerror(errno)); 346 siginterrupt(SIGINT, 0); 347 return errbuf; 348 } 349 siginterrupt(SIGINT, 0); 350 351 /* get the remote host addresses (RM) */ 352 memset(&hints, 0, sizeof(hints)); 353 hints.ai_flags = AI_CANONNAME; 354 hints.ai_family = PF_UNSPEC; 355 hints.ai_socktype = SOCK_STREAM; 356 res = NULL; 357 siginterrupt(SIGINT, 1); 358 error = getaddrinfo(RM, NULL, &hints, &res0); 359 siginterrupt(SIGINT, 0); 360 if (error) { 361 (void)snprintf(errbuf, sizeof(errbuf), 362 "unable to resolve remote machine %s: %s", 363 RM, gai_strerror(error)); 364 freeifaddrs(ifap); 365 return errbuf; 366 } 367 368 remote = 1; /* assume printer is remote */ 369 370 for (res = res0; res; res = res->ai_next) { 371 siginterrupt(SIGINT, 1); 372 error = getnameinfo(res->ai_addr, res->ai_addrlen, 373 rname, sizeof(rname), NULL, 0, niflags); 374 siginterrupt(SIGINT, 0); 375 if (error != 0) 376 continue; 377 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 378 #ifdef __KAME__ 379 sin6p = (struct sockaddr_in6 *)ifa->ifa_addr; 380 if (ifa->ifa_addr->sa_family == AF_INET6 && 381 ifa->ifa_addr->sa_len == sizeof(sin6) && 382 IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr) && 383 *(u_int16_t *)&sin6p->sin6_addr.s6_addr[2]) { 384 /* kame scopeid hack */ 385 memcpy(&sin6, ifa->ifa_addr, sizeof(sin6)); 386 sin6.sin6_scope_id = 387 ntohs(*(u_int16_t *)&sin6p->sin6_addr.s6_addr[2]); 388 sin6.sin6_addr.s6_addr[2] = 0; 389 sin6.sin6_addr.s6_addr[3] = 0; 390 siginterrupt(SIGINT, 1); 391 error = getnameinfo((struct sockaddr *)&sin6, 392 sin6.sin6_len, lname, sizeof(lname), 393 NULL, 0, niflags); 394 siginterrupt(SIGINT, 0); 395 if (error != 0) 396 continue; 397 } else 398 #endif 399 siginterrupt(SIGINT, 1); 400 error = getnameinfo(ifa->ifa_addr, 401 ifa->ifa_addr->sa_len, lname, sizeof(lname), NULL, 402 0, niflags); 403 siginterrupt(SIGINT, 0); 404 if (error != 0) 405 continue; 406 407 if (strcmp(rname, lname) == 0) { 408 remote = 0; 409 goto done; 410 } 411 } 412 } 413 done: 414 freeaddrinfo(res0); 415 freeifaddrs(ifap); 416 return NULL; 417 } 418 419 /* sleep n milliseconds */ 420 void 421 delay(int n) 422 { 423 struct timeval tdelay; 424 425 if (n <= 0 || n > 10000) 426 fatal("unreasonable delay period (%d)", n); 427 tdelay.tv_sec = n / 1000; 428 tdelay.tv_usec = n * 1000 % 1000000; 429 (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay); 430 } 431 432 __dead void 433 fatal(const char *msg, ...) 434 { 435 extern char *__progname; 436 va_list ap; 437 438 va_start(ap, msg); 439 if (from != host) 440 (void)printf("%s: ", host); 441 (void)printf("%s: ", __progname); 442 if (printer) 443 (void)printf("%s: ", printer); 444 (void)vprintf(msg, ap); 445 va_end(ap); 446 (void)putchar('\n'); 447 exit(1); 448 } 449 450 int 451 safe_open(const char *path, int flags, mode_t mode) 452 { 453 int fd, serrno; 454 struct stat stbuf; 455 456 if ((fd = open(path, flags|O_NONBLOCK, mode)) < 0 || 457 fstat(fd, &stbuf) < 0) { 458 if (fd >= 0) { 459 serrno = errno; 460 close(fd); 461 errno = serrno; 462 } 463 return (-1); 464 } 465 if (!S_ISREG(stbuf.st_mode)) { 466 close(fd); 467 errno = EACCES; 468 return (-1); 469 } 470 if (mode) 471 (void)fchmod(fd, mode); 472 return (fd); 473 } 474