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