1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * From: @(#)common.c 8.5 (Berkeley) 4/28/95 39 */ 40 41 #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/param.h> 45 #include <sys/socket.h> 46 #include <sys/stat.h> 47 #include <sys/time.h> 48 #include <sys/uio.h> 49 50 #include <netinet/in.h> 51 #include <arpa/inet.h> 52 #include <netdb.h> 53 54 #include <dirent.h> /* required for lp.h, not used here */ 55 #include <errno.h> 56 #include <stdarg.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include "lp.h" 63 #include "lp.local.h" 64 #include "pathnames.h" 65 66 /* 67 * 'local_host' is always the hostname of the machine which is running 68 * lpr (lpd, whatever), while 'from_host' either points at 'local_host' 69 * or points at a different buffer when receiving a job from a remote 70 * machine (and that buffer has the hostname of that remote machine). 71 */ 72 char local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */ 73 const char *from_host = local_host; /* client's machine name */ 74 const char *from_ip = ""; /* client machine's IP address */ 75 76 #ifdef INET6 77 u_char family = PF_UNSPEC; 78 #else 79 u_char family = PF_INET; 80 #endif 81 82 extern uid_t uid, euid; 83 84 /* 85 * Create a TCP connection to host "rhost" at port "rport". 86 * If rport == 0, then use the printer service port. 87 * Most of this code comes from rcmd.c. 88 */ 89 int 90 getport(const struct printer *pp, const char *rhost, int rport) 91 { 92 struct addrinfo hints, *res, *ai; 93 int s, timo = 1, lport = IPPORT_RESERVED - 1; 94 int err, refused = 0; 95 96 /* 97 * Get the host address and port number to connect to. 98 */ 99 if (rhost == NULL) 100 fatal(pp, "no remote host to connect to"); 101 memset(&hints, 0, sizeof(hints)); 102 hints.ai_family = family; 103 hints.ai_socktype = SOCK_STREAM; 104 hints.ai_protocol = 0; 105 err = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL), 106 &hints, &res); 107 if (err) 108 fatal(pp, "%s\n", gai_strerror(err)); 109 if (rport != 0) 110 ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport); 111 112 /* 113 * Try connecting to the server. 114 */ 115 ai = res; 116 retry: 117 seteuid(euid); 118 s = rresvport_af(&lport, ai->ai_family); 119 seteuid(uid); 120 if (s < 0) { 121 if (errno != EAGAIN) { 122 if (ai->ai_next) { 123 ai = ai->ai_next; 124 goto retry; 125 } 126 if (refused && timo <= 16) { 127 sleep(timo); 128 timo *= 2; 129 refused = 0; 130 ai = res; 131 goto retry; 132 } 133 } 134 freeaddrinfo(res); 135 return(-1); 136 } 137 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { 138 err = errno; 139 (void) close(s); 140 errno = err; 141 /* 142 * This used to decrement lport, but the current semantics 143 * of rresvport do not provide such a function (in fact, 144 * rresvport should guarantee that the chosen port will 145 * never result in an EADDRINUSE). 146 */ 147 if (errno == EADDRINUSE) { 148 goto retry; 149 } 150 151 if (errno == ECONNREFUSED) 152 refused++; 153 154 if (ai->ai_next != NULL) { 155 ai = ai->ai_next; 156 goto retry; 157 } 158 if (refused && timo <= 16) { 159 sleep(timo); 160 timo *= 2; 161 refused = 0; 162 ai = res; 163 goto retry; 164 } 165 freeaddrinfo(res); 166 return(-1); 167 } 168 freeaddrinfo(res); 169 return(s); 170 } 171 172 /* 173 * Figure out whether the local machine is the same 174 * as the remote machine (RM) entry (if it exists). 175 * We do this by counting the intersection of our 176 * address list and theirs. This is better than the 177 * old method (comparing the canonical names), as it 178 * allows load-sharing between multiple print servers. 179 * The return value is an error message which must be 180 * free()d. 181 */ 182 char * 183 checkremote(struct printer *pp) 184 { 185 char lclhost[MAXHOSTNAMELEN]; 186 struct addrinfo hints, *local_res, *remote_res, *lr, *rr; 187 char *err; 188 int ncommonaddrs, error; 189 char h1[NI_MAXHOST], h2[NI_MAXHOST]; 190 191 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ 192 pp->remote = 1; 193 return NULL; 194 } 195 196 pp->remote = 0; /* assume printer is local */ 197 if (pp->remote_host == NULL) 198 return NULL; 199 200 /* get the addresses of the local host */ 201 gethostname(lclhost, sizeof(lclhost)); 202 lclhost[sizeof(lclhost) - 1] = '\0'; 203 204 memset(&hints, 0, sizeof(hints)); 205 hints.ai_family = family; 206 hints.ai_socktype = SOCK_STREAM; 207 hints.ai_flags = AI_PASSIVE; 208 if ((error = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) { 209 asprintf(&err, "unable to get official name " 210 "for local machine %s: %s", 211 lclhost, gai_strerror(error)); 212 return err; 213 } 214 215 /* get the official name of RM */ 216 memset(&hints, 0, sizeof(hints)); 217 hints.ai_family = family; 218 hints.ai_socktype = SOCK_STREAM; 219 hints.ai_flags = AI_PASSIVE; 220 if ((error = getaddrinfo(pp->remote_host, NULL, 221 &hints, &remote_res)) != 0) { 222 asprintf(&err, "unable to get address list for " 223 "remote machine %s: %s", 224 pp->remote_host, gai_strerror(error)); 225 freeaddrinfo(local_res); 226 return err; 227 } 228 229 ncommonaddrs = 0; 230 for (lr = local_res; lr; lr = lr->ai_next) { 231 h1[0] = '\0'; 232 if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1), 233 NULL, 0, NI_NUMERICHOST) != 0) 234 continue; 235 for (rr = remote_res; rr; rr = rr->ai_next) { 236 h2[0] = '\0'; 237 if (getnameinfo(rr->ai_addr, rr->ai_addrlen, 238 h2, sizeof(h2), NULL, 0, 239 NI_NUMERICHOST) != 0) 240 continue; 241 if (strcmp(h1, h2) == 0) 242 ncommonaddrs++; 243 } 244 } 245 246 /* 247 * if the two hosts do not share at least one IP address 248 * then the printer must be remote. 249 */ 250 if (ncommonaddrs == 0) 251 pp->remote = 1; 252 freeaddrinfo(local_res); 253 freeaddrinfo(remote_res); 254 return NULL; 255 } 256 257 /* 258 * This isn't really network-related, but it's used here to write 259 * multi-part strings onto sockets without using stdio. Return 260 * values are as for writev(2). 261 */ 262 ssize_t 263 writel(int strm, ...) 264 { 265 va_list ap; 266 int i, n; 267 const char *cp; 268 #define NIOV 12 269 struct iovec iov[NIOV], *iovp = iov; 270 ssize_t retval; 271 272 /* first count them */ 273 va_start(ap, strm); 274 n = 0; 275 do { 276 cp = va_arg(ap, char *); 277 n++; 278 } while (cp); 279 va_end(ap); 280 n--; /* correct for count of trailing null */ 281 282 if (n > NIOV) { 283 iovp = malloc(n * sizeof *iovp); 284 if (iovp == 0) 285 return -1; 286 } 287 288 /* now make up iovec and send */ 289 va_start(ap, strm); 290 for (i = 0; i < n; i++) { 291 iovp[i].iov_base = va_arg(ap, char *); 292 iovp[i].iov_len = strlen(iovp[i].iov_base); 293 } 294 va_end(ap); 295 retval = writev(strm, iovp, n); 296 if (iovp != iov) 297 free(iovp); 298 return retval; 299 } 300