131492Swollman/* 231492Swollman * Copyright (c) 1983, 1993 331492Swollman * The Regents of the University of California. All rights reserved. 431492Swollman * (c) UNIX System Laboratories, Inc. 531492Swollman * All or some portions of this file are derived from material licensed 631492Swollman * to the University of California by American Telephone and Telegraph 731492Swollman * Co. or Unix System Laboratories, Inc. and are reproduced herein with 831492Swollman * the permission of UNIX System Laboratories, Inc. 931492Swollman * 1031492Swollman * Redistribution and use in source and binary forms, with or without 1131492Swollman * modification, are permitted provided that the following conditions 1231492Swollman * are met: 1331492Swollman * 1. Redistributions of source code must retain the above copyright 1431492Swollman * notice, this list of conditions and the following disclaimer. 1531492Swollman * 2. Redistributions in binary form must reproduce the above copyright 1631492Swollman * notice, this list of conditions and the following disclaimer in the 1731492Swollman * documentation and/or other materials provided with the distribution. 1831492Swollman * 3. All advertising materials mentioning features or use of this software 1931492Swollman * must display the following acknowledgement: 2031492Swollman * This product includes software developed by the University of 2131492Swollman * California, Berkeley and its contributors. 2231492Swollman * 4. Neither the name of the University nor the names of its contributors 2331492Swollman * may be used to endorse or promote products derived from this software 2431492Swollman * without specific prior written permission. 2531492Swollman * 2631492Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2731492Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2831492Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2931492Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3031492Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3131492Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3231492Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3331492Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3431492Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3531492Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3631492Swollman * SUCH DAMAGE. 3731492Swollman * 3831492Swollman * From: @(#)common.c 8.5 (Berkeley) 4/28/95 3931492Swollman */ 4031492Swollman 41117541Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 42117541Sgad__FBSDID("$FreeBSD$"); 4331492Swollman 4431492Swollman#include <sys/param.h> 4531492Swollman#include <sys/socket.h> 4631492Swollman#include <sys/stat.h> 4731492Swollman#include <sys/time.h> 4831492Swollman#include <sys/uio.h> 4931492Swollman 5031492Swollman#include <netinet/in.h> 5131492Swollman#include <arpa/inet.h> 5231492Swollman#include <netdb.h> 5331492Swollman 5431492Swollman#include <dirent.h> /* required for lp.h, not used here */ 55241852Seadler#include <err.h> 5631492Swollman#include <errno.h> 5731492Swollman#include <stdarg.h> 5831492Swollman#include <stdio.h> 5931492Swollman#include <stdlib.h> 6031492Swollman#include <string.h> 6131492Swollman#include <unistd.h> 6231492Swollman 6331492Swollman#include "lp.h" 6431492Swollman#include "lp.local.h" 6531492Swollman#include "pathnames.h" 6631492Swollman 6778300Sgad/* 6878300Sgad * 'local_host' is always the hostname of the machine which is running 6978300Sgad * lpr (lpd, whatever), while 'from_host' either points at 'local_host' 7078300Sgad * or points at a different buffer when receiving a job from a remote 7178300Sgad * machine (and that buffer has the hostname of that remote machine). 7278300Sgad */ 7378300Sgadchar local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */ 7478300Sgadconst char *from_host = local_host; /* client's machine name */ 7578300Sgadconst char *from_ip = ""; /* client machine's IP address */ 7631492Swollman 7770098Sume#ifdef INET6 7870098Sumeu_char family = PF_UNSPEC; 7970098Sume#else 8070098Sumeu_char family = PF_INET; 8170098Sume#endif 8270098Sume 8331492Swollman/* 8431492Swollman * Create a TCP connection to host "rhost" at port "rport". 8531492Swollman * If rport == 0, then use the printer service port. 8631492Swollman * Most of this code comes from rcmd.c. 8731492Swollman */ 8831492Swollmanint 8931492Swollmangetport(const struct printer *pp, const char *rhost, int rport) 9031492Swollman{ 9170098Sume struct addrinfo hints, *res, *ai; 9231492Swollman int s, timo = 1, lport = IPPORT_RESERVED - 1; 93241852Seadler int error, refused = 0; 9431492Swollman 9531492Swollman /* 9631492Swollman * Get the host address and port number to connect to. 9731492Swollman */ 9831492Swollman if (rhost == NULL) 9931492Swollman fatal(pp, "no remote host to connect to"); 10070098Sume memset(&hints, 0, sizeof(hints)); 10170098Sume hints.ai_family = family; 10270098Sume hints.ai_socktype = SOCK_STREAM; 10370098Sume hints.ai_protocol = 0; 104241852Seadler error = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL), 10570098Sume &hints, &res); 106241852Seadler if (error) 107241852Seadler fatal(pp, "%s\n", gai_strerror(error)); 10870098Sume if (rport != 0) 10970098Sume ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport); 11031492Swollman 11131492Swollman /* 11231492Swollman * Try connecting to the server. 11331492Swollman */ 11470098Sume ai = res; 11531492Swollmanretry: 116241852Seadler PRIV_START 11770098Sume s = rresvport_af(&lport, ai->ai_family); 118241852Seadler PRIV_END 11970098Sume if (s < 0) { 12070098Sume if (errno != EAGAIN) { 12170098Sume if (ai->ai_next) { 12270098Sume ai = ai->ai_next; 12370098Sume goto retry; 12470098Sume } 12570098Sume if (refused && timo <= 16) { 12670098Sume sleep(timo); 12770098Sume timo *= 2; 12870098Sume refused = 0; 12970098Sume ai = res; 13070098Sume goto retry; 13170098Sume } 13270098Sume } 13370098Sume freeaddrinfo(res); 13431492Swollman return(-1); 13570098Sume } 13670098Sume if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { 137241852Seadler error = errno; 13831492Swollman (void) close(s); 139241852Seadler errno = error; 14031492Swollman /* 14131492Swollman * This used to decrement lport, but the current semantics 14231492Swollman * of rresvport do not provide such a function (in fact, 14331492Swollman * rresvport should guarantee that the chosen port will 14431492Swollman * never result in an EADDRINUSE). 14531492Swollman */ 14670098Sume if (errno == EADDRINUSE) { 14731492Swollman goto retry; 14870098Sume } 14931492Swollman 15070098Sume if (errno == ECONNREFUSED) 15170098Sume refused++; 15270098Sume 15370098Sume if (ai->ai_next != NULL) { 15470098Sume ai = ai->ai_next; 15570098Sume goto retry; 15670098Sume } 15770098Sume if (refused && timo <= 16) { 15831492Swollman sleep(timo); 15931492Swollman timo *= 2; 16070098Sume refused = 0; 16170098Sume ai = res; 16231492Swollman goto retry; 16331492Swollman } 16470098Sume freeaddrinfo(res); 16531492Swollman return(-1); 16631492Swollman } 16770098Sume freeaddrinfo(res); 16831492Swollman return(s); 16931492Swollman} 17031492Swollman 17131492Swollman/* 17231492Swollman * Figure out whether the local machine is the same 17331492Swollman * as the remote machine (RM) entry (if it exists). 17431492Swollman * We do this by counting the intersection of our 17531492Swollman * address list and theirs. This is better than the 17631492Swollman * old method (comparing the canonical names), as it 17731492Swollman * allows load-sharing between multiple print servers. 17831492Swollman * The return value is an error message which must be 17931492Swollman * free()d. 18031492Swollman */ 18131492Swollmanchar * 18231492Swollmancheckremote(struct printer *pp) 18331492Swollman{ 18478146Sgad char lclhost[MAXHOSTNAMELEN]; 18570098Sume struct addrinfo hints, *local_res, *remote_res, *lr, *rr; 186241852Seadler char *error; 187241852Seadler int ncommonaddrs, errno; 18870098Sume char h1[NI_MAXHOST], h2[NI_MAXHOST]; 18931492Swollman 19046110Sjkh if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ 19146110Sjkh pp->remote = 1; 19246110Sjkh return NULL; 19346110Sjkh } 19446110Sjkh 19531492Swollman pp->remote = 0; /* assume printer is local */ 19670098Sume if (pp->remote_host == NULL) 19770098Sume return NULL; 19831492Swollman 19970098Sume /* get the addresses of the local host */ 20078146Sgad gethostname(lclhost, sizeof(lclhost)); 20178146Sgad lclhost[sizeof(lclhost) - 1] = '\0'; 20231492Swollman 20370098Sume memset(&hints, 0, sizeof(hints)); 20470098Sume hints.ai_family = family; 20570098Sume hints.ai_socktype = SOCK_STREAM; 20670098Sume hints.ai_flags = AI_PASSIVE; 207241852Seadler if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) { 208241852Seadler asprintf(&error, "unable to get official name " 20970098Sume "for local machine %s: %s", 210241852Seadler lclhost, gai_strerror(errno)); 211241852Seadler return error; 21270098Sume } 21370098Sume 21470098Sume /* get the official name of RM */ 21570098Sume memset(&hints, 0, sizeof(hints)); 21670098Sume hints.ai_family = family; 21770098Sume hints.ai_socktype = SOCK_STREAM; 21870098Sume hints.ai_flags = AI_PASSIVE; 219241852Seadler if ((errno = getaddrinfo(pp->remote_host, NULL, 22070098Sume &hints, &remote_res)) != 0) { 221241852Seadler asprintf(&error, "unable to get address list for " 22270098Sume "remote machine %s: %s", 223241852Seadler pp->remote_host, gai_strerror(errno)); 22470098Sume freeaddrinfo(local_res); 225241852Seadler return error; 22670098Sume } 22770098Sume 22870098Sume ncommonaddrs = 0; 22970098Sume for (lr = local_res; lr; lr = lr->ai_next) { 23070098Sume h1[0] = '\0'; 23170098Sume if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1), 232146188Sume NULL, 0, NI_NUMERICHOST) != 0) 23370098Sume continue; 23470098Sume for (rr = remote_res; rr; rr = rr->ai_next) { 23570098Sume h2[0] = '\0'; 23670098Sume if (getnameinfo(rr->ai_addr, rr->ai_addrlen, 23770098Sume h2, sizeof(h2), NULL, 0, 238146188Sume NI_NUMERICHOST) != 0) 23970098Sume continue; 24070098Sume if (strcmp(h1, h2) == 0) 24170098Sume ncommonaddrs++; 24231492Swollman } 24370098Sume } 24431492Swollman 24570098Sume /* 24670098Sume * if the two hosts do not share at least one IP address 24770098Sume * then the printer must be remote. 24870098Sume */ 24970098Sume if (ncommonaddrs == 0) 25070098Sume pp->remote = 1; 25170098Sume freeaddrinfo(local_res); 25270098Sume freeaddrinfo(remote_res); 25331492Swollman return NULL; 25431492Swollman} 25531492Swollman 25631492Swollman/* 25731492Swollman * This isn't really network-related, but it's used here to write 25831492Swollman * multi-part strings onto sockets without using stdio. Return 25931492Swollman * values are as for writev(2). 26031492Swollman */ 26131492Swollmanssize_t 26278146Sgadwritel(int strm, ...) 26331492Swollman{ 26431492Swollman va_list ap; 26531492Swollman int i, n; 26631492Swollman const char *cp; 26731492Swollman#define NIOV 12 26831492Swollman struct iovec iov[NIOV], *iovp = iov; 26931492Swollman ssize_t retval; 27031492Swollman 27131492Swollman /* first count them */ 27278146Sgad va_start(ap, strm); 27331492Swollman n = 0; 27431492Swollman do { 27531492Swollman cp = va_arg(ap, char *); 27631492Swollman n++; 27731492Swollman } while (cp); 27831492Swollman va_end(ap); 27931492Swollman n--; /* correct for count of trailing null */ 28031492Swollman 28131492Swollman if (n > NIOV) { 28231492Swollman iovp = malloc(n * sizeof *iovp); 28331492Swollman if (iovp == 0) 28431492Swollman return -1; 28531492Swollman } 28631492Swollman 28731492Swollman /* now make up iovec and send */ 28878146Sgad va_start(ap, strm); 28931492Swollman for (i = 0; i < n; i++) { 29031492Swollman iovp[i].iov_base = va_arg(ap, char *); 29131492Swollman iovp[i].iov_len = strlen(iovp[i].iov_base); 29231492Swollman } 29331492Swollman va_end(ap); 29478146Sgad retval = writev(strm, iovp, n); 29531492Swollman if (iovp != iov) 29631492Swollman free(iovp); 29731492Swollman return retval; 29831492Swollman} 299