14a1a0dbeSGarrett Wollman /* 24a1a0dbeSGarrett Wollman * Copyright (c) 1983, 1993 34a1a0dbeSGarrett Wollman * The Regents of the University of California. All rights reserved. 44a1a0dbeSGarrett Wollman * (c) UNIX System Laboratories, Inc. 54a1a0dbeSGarrett Wollman * All or some portions of this file are derived from material licensed 64a1a0dbeSGarrett Wollman * to the University of California by American Telephone and Telegraph 74a1a0dbeSGarrett Wollman * Co. or Unix System Laboratories, Inc. and are reproduced herein with 84a1a0dbeSGarrett Wollman * the permission of UNIX System Laboratories, Inc. 94a1a0dbeSGarrett Wollman * 104a1a0dbeSGarrett Wollman * Redistribution and use in source and binary forms, with or without 114a1a0dbeSGarrett Wollman * modification, are permitted provided that the following conditions 124a1a0dbeSGarrett Wollman * are met: 134a1a0dbeSGarrett Wollman * 1. Redistributions of source code must retain the above copyright 144a1a0dbeSGarrett Wollman * notice, this list of conditions and the following disclaimer. 154a1a0dbeSGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 164a1a0dbeSGarrett Wollman * notice, this list of conditions and the following disclaimer in the 174a1a0dbeSGarrett Wollman * documentation and/or other materials provided with the distribution. 184a1a0dbeSGarrett Wollman * 3. All advertising materials mentioning features or use of this software 194a1a0dbeSGarrett Wollman * must display the following acknowledgement: 204a1a0dbeSGarrett Wollman * This product includes software developed by the University of 214a1a0dbeSGarrett Wollman * California, Berkeley and its contributors. 224a1a0dbeSGarrett Wollman * 4. Neither the name of the University nor the names of its contributors 234a1a0dbeSGarrett Wollman * may be used to endorse or promote products derived from this software 244a1a0dbeSGarrett Wollman * without specific prior written permission. 254a1a0dbeSGarrett Wollman * 264a1a0dbeSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 274a1a0dbeSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 284a1a0dbeSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 294a1a0dbeSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 304a1a0dbeSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 314a1a0dbeSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 324a1a0dbeSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 334a1a0dbeSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 344a1a0dbeSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 354a1a0dbeSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 364a1a0dbeSGarrett Wollman * SUCH DAMAGE. 374a1a0dbeSGarrett Wollman * 384a1a0dbeSGarrett Wollman * From: @(#)common.c 8.5 (Berkeley) 4/28/95 394a1a0dbeSGarrett Wollman */ 404a1a0dbeSGarrett Wollman 411f589b47SGarance A Drosehn #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 421f589b47SGarance A Drosehn __FBSDID("$FreeBSD$"); 434a1a0dbeSGarrett Wollman 444a1a0dbeSGarrett Wollman #include <sys/param.h> 454a1a0dbeSGarrett Wollman #include <sys/socket.h> 464a1a0dbeSGarrett Wollman #include <sys/stat.h> 474a1a0dbeSGarrett Wollman #include <sys/time.h> 484a1a0dbeSGarrett Wollman #include <sys/uio.h> 494a1a0dbeSGarrett Wollman 504a1a0dbeSGarrett Wollman #include <netinet/in.h> 514a1a0dbeSGarrett Wollman #include <arpa/inet.h> 524a1a0dbeSGarrett Wollman #include <netdb.h> 534a1a0dbeSGarrett Wollman 544a1a0dbeSGarrett Wollman #include <dirent.h> /* required for lp.h, not used here */ 551d1d4a47SEitan Adler #include <err.h> 564a1a0dbeSGarrett Wollman #include <errno.h> 574a1a0dbeSGarrett Wollman #include <stdarg.h> 584a1a0dbeSGarrett Wollman #include <stdio.h> 594a1a0dbeSGarrett Wollman #include <stdlib.h> 604a1a0dbeSGarrett Wollman #include <string.h> 614a1a0dbeSGarrett Wollman #include <unistd.h> 624a1a0dbeSGarrett Wollman 634a1a0dbeSGarrett Wollman #include "lp.h" 644a1a0dbeSGarrett Wollman #include "lp.local.h" 654a1a0dbeSGarrett Wollman #include "pathnames.h" 664a1a0dbeSGarrett Wollman 67cc3fd56fSGarance A Drosehn /* 68cc3fd56fSGarance A Drosehn * 'local_host' is always the hostname of the machine which is running 69cc3fd56fSGarance A Drosehn * lpr (lpd, whatever), while 'from_host' either points at 'local_host' 70cc3fd56fSGarance A Drosehn * or points at a different buffer when receiving a job from a remote 71cc3fd56fSGarance A Drosehn * machine (and that buffer has the hostname of that remote machine). 72cc3fd56fSGarance A Drosehn */ 73cc3fd56fSGarance A Drosehn char local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */ 74cc3fd56fSGarance A Drosehn const char *from_host = local_host; /* client's machine name */ 75cc3fd56fSGarance A Drosehn const char *from_ip = ""; /* client machine's IP address */ 7608829865SHajimu UMEMOTO 7708829865SHajimu UMEMOTO #ifdef INET6 7808829865SHajimu UMEMOTO u_char family = PF_UNSPEC; 7908829865SHajimu UMEMOTO #else 8008829865SHajimu UMEMOTO u_char family = PF_INET; 8108829865SHajimu UMEMOTO #endif 824a1a0dbeSGarrett Wollman 834a1a0dbeSGarrett Wollman extern uid_t uid, euid; 844a1a0dbeSGarrett Wollman 854a1a0dbeSGarrett Wollman /* 864a1a0dbeSGarrett Wollman * Create a TCP connection to host "rhost" at port "rport". 874a1a0dbeSGarrett Wollman * If rport == 0, then use the printer service port. 884a1a0dbeSGarrett Wollman * Most of this code comes from rcmd.c. 894a1a0dbeSGarrett Wollman */ 904a1a0dbeSGarrett Wollman int 914a1a0dbeSGarrett Wollman getport(const struct printer *pp, const char *rhost, int rport) 924a1a0dbeSGarrett Wollman { 9308829865SHajimu UMEMOTO struct addrinfo hints, *res, *ai; 944a1a0dbeSGarrett Wollman int s, timo = 1, lport = IPPORT_RESERVED - 1; 951d1d4a47SEitan Adler int error, refused = 0; 964a1a0dbeSGarrett Wollman 974a1a0dbeSGarrett Wollman /* 984a1a0dbeSGarrett Wollman * Get the host address and port number to connect to. 994a1a0dbeSGarrett Wollman */ 1004a1a0dbeSGarrett Wollman if (rhost == NULL) 1014a1a0dbeSGarrett Wollman fatal(pp, "no remote host to connect to"); 10208829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 10308829865SHajimu UMEMOTO hints.ai_family = family; 10408829865SHajimu UMEMOTO hints.ai_socktype = SOCK_STREAM; 10508829865SHajimu UMEMOTO hints.ai_protocol = 0; 1061d1d4a47SEitan Adler error = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL), 10708829865SHajimu UMEMOTO &hints, &res); 1081d1d4a47SEitan Adler if (error) 1091d1d4a47SEitan Adler fatal(pp, "%s\n", gai_strerror(error)); 11008829865SHajimu UMEMOTO if (rport != 0) 11108829865SHajimu UMEMOTO ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport); 1124a1a0dbeSGarrett Wollman 1134a1a0dbeSGarrett Wollman /* 1144a1a0dbeSGarrett Wollman * Try connecting to the server. 1154a1a0dbeSGarrett Wollman */ 11608829865SHajimu UMEMOTO ai = res; 1174a1a0dbeSGarrett Wollman retry: 1181d1d4a47SEitan Adler PRIV_START 11908829865SHajimu UMEMOTO s = rresvport_af(&lport, ai->ai_family); 1201d1d4a47SEitan Adler PRIV_END 12108829865SHajimu UMEMOTO if (s < 0) { 12208829865SHajimu UMEMOTO if (errno != EAGAIN) { 12308829865SHajimu UMEMOTO if (ai->ai_next) { 12408829865SHajimu UMEMOTO ai = ai->ai_next; 12508829865SHajimu UMEMOTO goto retry; 12608829865SHajimu UMEMOTO } 12708829865SHajimu UMEMOTO if (refused && timo <= 16) { 12808829865SHajimu UMEMOTO sleep(timo); 12908829865SHajimu UMEMOTO timo *= 2; 13008829865SHajimu UMEMOTO refused = 0; 13108829865SHajimu UMEMOTO ai = res; 13208829865SHajimu UMEMOTO goto retry; 13308829865SHajimu UMEMOTO } 13408829865SHajimu UMEMOTO } 13508829865SHajimu UMEMOTO freeaddrinfo(res); 1364a1a0dbeSGarrett Wollman return(-1); 13708829865SHajimu UMEMOTO } 13808829865SHajimu UMEMOTO if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { 1391d1d4a47SEitan Adler error = errno; 1404a1a0dbeSGarrett Wollman (void) close(s); 1411d1d4a47SEitan Adler errno = error; 1424a1a0dbeSGarrett Wollman /* 1434a1a0dbeSGarrett Wollman * This used to decrement lport, but the current semantics 1444a1a0dbeSGarrett Wollman * of rresvport do not provide such a function (in fact, 1454a1a0dbeSGarrett Wollman * rresvport should guarantee that the chosen port will 1464a1a0dbeSGarrett Wollman * never result in an EADDRINUSE). 1474a1a0dbeSGarrett Wollman */ 14808829865SHajimu UMEMOTO if (errno == EADDRINUSE) { 1494a1a0dbeSGarrett Wollman goto retry; 15008829865SHajimu UMEMOTO } 1514a1a0dbeSGarrett Wollman 15208829865SHajimu UMEMOTO if (errno == ECONNREFUSED) 15308829865SHajimu UMEMOTO refused++; 15408829865SHajimu UMEMOTO 15508829865SHajimu UMEMOTO if (ai->ai_next != NULL) { 15608829865SHajimu UMEMOTO ai = ai->ai_next; 15708829865SHajimu UMEMOTO goto retry; 15808829865SHajimu UMEMOTO } 15908829865SHajimu UMEMOTO if (refused && timo <= 16) { 1604a1a0dbeSGarrett Wollman sleep(timo); 1614a1a0dbeSGarrett Wollman timo *= 2; 16208829865SHajimu UMEMOTO refused = 0; 16308829865SHajimu UMEMOTO ai = res; 1644a1a0dbeSGarrett Wollman goto retry; 1654a1a0dbeSGarrett Wollman } 16608829865SHajimu UMEMOTO freeaddrinfo(res); 1674a1a0dbeSGarrett Wollman return(-1); 1684a1a0dbeSGarrett Wollman } 16908829865SHajimu UMEMOTO freeaddrinfo(res); 1704a1a0dbeSGarrett Wollman return(s); 1714a1a0dbeSGarrett Wollman } 1724a1a0dbeSGarrett Wollman 1734a1a0dbeSGarrett Wollman /* 1744a1a0dbeSGarrett Wollman * Figure out whether the local machine is the same 1754a1a0dbeSGarrett Wollman * as the remote machine (RM) entry (if it exists). 1764a1a0dbeSGarrett Wollman * We do this by counting the intersection of our 1774a1a0dbeSGarrett Wollman * address list and theirs. This is better than the 1784a1a0dbeSGarrett Wollman * old method (comparing the canonical names), as it 1794a1a0dbeSGarrett Wollman * allows load-sharing between multiple print servers. 1804a1a0dbeSGarrett Wollman * The return value is an error message which must be 1814a1a0dbeSGarrett Wollman * free()d. 1824a1a0dbeSGarrett Wollman */ 1834a1a0dbeSGarrett Wollman char * 1844a1a0dbeSGarrett Wollman checkremote(struct printer *pp) 1854a1a0dbeSGarrett Wollman { 186ba7a1ad7SGarance A Drosehn char lclhost[MAXHOSTNAMELEN]; 18708829865SHajimu UMEMOTO struct addrinfo hints, *local_res, *remote_res, *lr, *rr; 1881d1d4a47SEitan Adler char *error; 1891d1d4a47SEitan Adler int ncommonaddrs, errno; 19008829865SHajimu UMEMOTO char h1[NI_MAXHOST], h2[NI_MAXHOST]; 1914a1a0dbeSGarrett Wollman 192d5483ddfSJordan K. Hubbard if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ 193d5483ddfSJordan K. Hubbard pp->remote = 1; 194d5483ddfSJordan K. Hubbard return NULL; 195d5483ddfSJordan K. Hubbard } 196d5483ddfSJordan K. Hubbard 1974a1a0dbeSGarrett Wollman pp->remote = 0; /* assume printer is local */ 19808829865SHajimu UMEMOTO if (pp->remote_host == NULL) 19908829865SHajimu UMEMOTO return NULL; 20008829865SHajimu UMEMOTO 2014a1a0dbeSGarrett Wollman /* get the addresses of the local host */ 202ba7a1ad7SGarance A Drosehn gethostname(lclhost, sizeof(lclhost)); 203ba7a1ad7SGarance A Drosehn lclhost[sizeof(lclhost) - 1] = '\0'; 20408829865SHajimu UMEMOTO 20508829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 20608829865SHajimu UMEMOTO hints.ai_family = family; 20708829865SHajimu UMEMOTO hints.ai_socktype = SOCK_STREAM; 20808829865SHajimu UMEMOTO hints.ai_flags = AI_PASSIVE; 2091d1d4a47SEitan Adler if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) { 2101d1d4a47SEitan Adler asprintf(&error, "unable to get official name " 2114a1a0dbeSGarrett Wollman "for local machine %s: %s", 2121d1d4a47SEitan Adler lclhost, gai_strerror(errno)); 2131d1d4a47SEitan Adler return error; 2144a1a0dbeSGarrett Wollman } 2154a1a0dbeSGarrett Wollman 2164a1a0dbeSGarrett Wollman /* get the official name of RM */ 21708829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 21808829865SHajimu UMEMOTO hints.ai_family = family; 21908829865SHajimu UMEMOTO hints.ai_socktype = SOCK_STREAM; 22008829865SHajimu UMEMOTO hints.ai_flags = AI_PASSIVE; 2211d1d4a47SEitan Adler if ((errno = getaddrinfo(pp->remote_host, NULL, 22208829865SHajimu UMEMOTO &hints, &remote_res)) != 0) { 2231d1d4a47SEitan Adler asprintf(&error, "unable to get address list for " 2244a1a0dbeSGarrett Wollman "remote machine %s: %s", 2251d1d4a47SEitan Adler pp->remote_host, gai_strerror(errno)); 22608829865SHajimu UMEMOTO freeaddrinfo(local_res); 2271d1d4a47SEitan Adler return error; 2284a1a0dbeSGarrett Wollman } 2294a1a0dbeSGarrett Wollman 2304a1a0dbeSGarrett Wollman ncommonaddrs = 0; 23108829865SHajimu UMEMOTO for (lr = local_res; lr; lr = lr->ai_next) { 23208829865SHajimu UMEMOTO h1[0] = '\0'; 23308829865SHajimu UMEMOTO if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1), 2349ccf2f38SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) != 0) 23508829865SHajimu UMEMOTO continue; 23608829865SHajimu UMEMOTO for (rr = remote_res; rr; rr = rr->ai_next) { 23708829865SHajimu UMEMOTO h2[0] = '\0'; 23808829865SHajimu UMEMOTO if (getnameinfo(rr->ai_addr, rr->ai_addrlen, 23908829865SHajimu UMEMOTO h2, sizeof(h2), NULL, 0, 2409ccf2f38SHajimu UMEMOTO NI_NUMERICHOST) != 0) 24108829865SHajimu UMEMOTO continue; 24208829865SHajimu UMEMOTO if (strcmp(h1, h2) == 0) 2434a1a0dbeSGarrett Wollman ncommonaddrs++; 2444a1a0dbeSGarrett Wollman } 2454a1a0dbeSGarrett Wollman } 2464a1a0dbeSGarrett Wollman 2474a1a0dbeSGarrett Wollman /* 2484a1a0dbeSGarrett Wollman * if the two hosts do not share at least one IP address 2494a1a0dbeSGarrett Wollman * then the printer must be remote. 2504a1a0dbeSGarrett Wollman */ 2514a1a0dbeSGarrett Wollman if (ncommonaddrs == 0) 2524a1a0dbeSGarrett Wollman pp->remote = 1; 25308829865SHajimu UMEMOTO freeaddrinfo(local_res); 25408829865SHajimu UMEMOTO freeaddrinfo(remote_res); 2554a1a0dbeSGarrett Wollman return NULL; 2564a1a0dbeSGarrett Wollman } 2574a1a0dbeSGarrett Wollman 2584a1a0dbeSGarrett Wollman /* 2594a1a0dbeSGarrett Wollman * This isn't really network-related, but it's used here to write 2604a1a0dbeSGarrett Wollman * multi-part strings onto sockets without using stdio. Return 2614a1a0dbeSGarrett Wollman * values are as for writev(2). 2624a1a0dbeSGarrett Wollman */ 2634a1a0dbeSGarrett Wollman ssize_t 264ba7a1ad7SGarance A Drosehn writel(int strm, ...) 2654a1a0dbeSGarrett Wollman { 2664a1a0dbeSGarrett Wollman va_list ap; 2674a1a0dbeSGarrett Wollman int i, n; 2684a1a0dbeSGarrett Wollman const char *cp; 2694a1a0dbeSGarrett Wollman #define NIOV 12 2704a1a0dbeSGarrett Wollman struct iovec iov[NIOV], *iovp = iov; 2714a1a0dbeSGarrett Wollman ssize_t retval; 2724a1a0dbeSGarrett Wollman 2734a1a0dbeSGarrett Wollman /* first count them */ 274ba7a1ad7SGarance A Drosehn va_start(ap, strm); 2754a1a0dbeSGarrett Wollman n = 0; 2764a1a0dbeSGarrett Wollman do { 2774a1a0dbeSGarrett Wollman cp = va_arg(ap, char *); 2784a1a0dbeSGarrett Wollman n++; 2794a1a0dbeSGarrett Wollman } while (cp); 2804a1a0dbeSGarrett Wollman va_end(ap); 2814a1a0dbeSGarrett Wollman n--; /* correct for count of trailing null */ 2824a1a0dbeSGarrett Wollman 2834a1a0dbeSGarrett Wollman if (n > NIOV) { 2844a1a0dbeSGarrett Wollman iovp = malloc(n * sizeof *iovp); 2854a1a0dbeSGarrett Wollman if (iovp == 0) 2864a1a0dbeSGarrett Wollman return -1; 2874a1a0dbeSGarrett Wollman } 2884a1a0dbeSGarrett Wollman 2894a1a0dbeSGarrett Wollman /* now make up iovec and send */ 290ba7a1ad7SGarance A Drosehn va_start(ap, strm); 2914a1a0dbeSGarrett Wollman for (i = 0; i < n; i++) { 2924a1a0dbeSGarrett Wollman iovp[i].iov_base = va_arg(ap, char *); 2934a1a0dbeSGarrett Wollman iovp[i].iov_len = strlen(iovp[i].iov_base); 2944a1a0dbeSGarrett Wollman } 2954a1a0dbeSGarrett Wollman va_end(ap); 296ba7a1ad7SGarance A Drosehn retval = writev(strm, iovp, n); 2974a1a0dbeSGarrett Wollman if (iovp != iov) 2984a1a0dbeSGarrett Wollman free(iovp); 2994a1a0dbeSGarrett Wollman return retval; 3004a1a0dbeSGarrett Wollman } 301