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 #ifndef lint 42 static const char rcsid[] = 43 "$FreeBSD$"; 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/socket.h> 48 #include <sys/stat.h> 49 #include <sys/time.h> 50 #include <sys/uio.h> 51 52 #include <netinet/in.h> 53 #include <arpa/inet.h> 54 #include <netdb.h> 55 56 #include <dirent.h> /* required for lp.h, not used here */ 57 #include <errno.h> 58 #include <stdarg.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "lp.h" 65 #include "lp.local.h" 66 #include "pathnames.h" 67 68 char host[MAXHOSTNAMELEN]; /* host machine name */ 69 char *from = host; /* client's machine name */ 70 char from_ip[NI_MAXHOST] = ""; /* client machine's IP address */ 71 72 #ifdef INET6 73 u_char family = PF_UNSPEC; 74 #else 75 u_char family = PF_INET; 76 #endif 77 78 extern uid_t uid, euid; 79 80 /* 81 * Create a TCP connection to host "rhost" at port "rport". 82 * If rport == 0, then use the printer service port. 83 * Most of this code comes from rcmd.c. 84 */ 85 int 86 getport(const struct printer *pp, const char *rhost, int rport) 87 { 88 struct addrinfo hints, *res, *ai; 89 int s, timo = 1, lport = IPPORT_RESERVED - 1; 90 int err, refused = 0; 91 92 /* 93 * Get the host address and port number to connect to. 94 */ 95 if (rhost == NULL) 96 fatal(pp, "no remote host to connect to"); 97 memset(&hints, 0, sizeof(hints)); 98 hints.ai_family = family; 99 hints.ai_socktype = SOCK_STREAM; 100 hints.ai_protocol = 0; 101 err = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL), 102 &hints, &res); 103 if (err) 104 fatal(pp, "%s\n", gai_strerror(err)); 105 if (rport != 0) 106 ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport); 107 108 /* 109 * Try connecting to the server. 110 */ 111 ai = res; 112 retry: 113 seteuid(euid); 114 s = rresvport_af(&lport, ai->ai_family); 115 seteuid(uid); 116 if (s < 0) { 117 if (errno != EAGAIN) { 118 if (ai->ai_next) { 119 ai = ai->ai_next; 120 goto retry; 121 } 122 if (refused && timo <= 16) { 123 sleep(timo); 124 timo *= 2; 125 refused = 0; 126 ai = res; 127 goto retry; 128 } 129 } 130 freeaddrinfo(res); 131 return(-1); 132 } 133 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { 134 err = errno; 135 (void) close(s); 136 errno = err; 137 /* 138 * This used to decrement lport, but the current semantics 139 * of rresvport do not provide such a function (in fact, 140 * rresvport should guarantee that the chosen port will 141 * never result in an EADDRINUSE). 142 */ 143 if (errno == EADDRINUSE) { 144 goto retry; 145 } 146 147 if (errno == ECONNREFUSED) 148 refused++; 149 150 if (ai->ai_next != NULL) { 151 ai = ai->ai_next; 152 goto retry; 153 } 154 if (refused && timo <= 16) { 155 sleep(timo); 156 timo *= 2; 157 refused = 0; 158 ai = res; 159 goto retry; 160 } 161 freeaddrinfo(res); 162 return(-1); 163 } 164 freeaddrinfo(res); 165 return(s); 166 } 167 168 /* 169 * Figure out whether the local machine is the same 170 * as the remote machine (RM) entry (if it exists). 171 * We do this by counting the intersection of our 172 * address list and theirs. This is better than the 173 * old method (comparing the canonical names), as it 174 * allows load-sharing between multiple print servers. 175 * The return value is an error message which must be 176 * free()d. 177 */ 178 char * 179 checkremote(struct printer *pp) 180 { 181 char name[MAXHOSTNAMELEN]; 182 struct addrinfo hints, *local_res, *remote_res, *lr, *rr; 183 char *err; 184 int ncommonaddrs, error; 185 char h1[NI_MAXHOST], h2[NI_MAXHOST]; 186 187 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ 188 pp->remote = 1; 189 return NULL; 190 } 191 192 pp->remote = 0; /* assume printer is local */ 193 if (pp->remote_host == NULL) 194 return NULL; 195 196 /* get the addresses of the local host */ 197 gethostname(name, sizeof(name)); 198 name[sizeof(name) - 1] = '\0'; 199 200 memset(&hints, 0, sizeof(hints)); 201 hints.ai_family = family; 202 hints.ai_socktype = SOCK_STREAM; 203 hints.ai_flags = AI_PASSIVE; 204 if ((error = getaddrinfo(name, NULL, &hints, &local_res)) != 0) { 205 asprintf(&err, "unable to get official name " 206 "for local machine %s: %s", 207 name, gai_strerror(error)); 208 return err; 209 } 210 211 /* get the official name of RM */ 212 memset(&hints, 0, sizeof(hints)); 213 hints.ai_family = family; 214 hints.ai_socktype = SOCK_STREAM; 215 hints.ai_flags = AI_PASSIVE; 216 if ((error = getaddrinfo(pp->remote_host, NULL, 217 &hints, &remote_res)) != 0) { 218 asprintf(&err, "unable to get address list for " 219 "remote machine %s: %s", 220 pp->remote_host, gai_strerror(error)); 221 freeaddrinfo(local_res); 222 return err; 223 } 224 225 ncommonaddrs = 0; 226 for (lr = local_res; lr; lr = lr->ai_next) { 227 h1[0] = '\0'; 228 if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1), 229 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0) 230 continue; 231 for (rr = remote_res; rr; rr = rr->ai_next) { 232 h2[0] = '\0'; 233 if (getnameinfo(rr->ai_addr, rr->ai_addrlen, 234 h2, sizeof(h2), NULL, 0, 235 NI_NUMERICHOST | NI_WITHSCOPEID) != 0) 236 continue; 237 if (strcmp(h1, h2) == 0) 238 ncommonaddrs++; 239 } 240 } 241 242 /* 243 * if the two hosts do not share at least one IP address 244 * then the printer must be remote. 245 */ 246 if (ncommonaddrs == 0) 247 pp->remote = 1; 248 freeaddrinfo(local_res); 249 freeaddrinfo(remote_res); 250 return NULL; 251 } 252 253 /* 254 * This isn't really network-related, but it's used here to write 255 * multi-part strings onto sockets without using stdio. Return 256 * values are as for writev(2). 257 */ 258 ssize_t 259 writel(int s, ...) 260 { 261 va_list ap; 262 int i, n; 263 const char *cp; 264 #define NIOV 12 265 struct iovec iov[NIOV], *iovp = iov; 266 ssize_t retval; 267 268 /* first count them */ 269 va_start(ap, s); 270 n = 0; 271 do { 272 cp = va_arg(ap, char *); 273 n++; 274 } while (cp); 275 va_end(ap); 276 n--; /* correct for count of trailing null */ 277 278 if (n > NIOV) { 279 iovp = malloc(n * sizeof *iovp); 280 if (iovp == 0) 281 return -1; 282 } 283 284 /* now make up iovec and send */ 285 va_start(ap, s); 286 for (i = 0; i < n; i++) { 287 iovp[i].iov_base = va_arg(ap, char *); 288 iovp[i].iov_len = strlen(iovp[i].iov_base); 289 } 290 va_end(ap); 291 retval = writev(s, iovp, n); 292 if (iovp != iov) 293 free(iovp); 294 return retval; 295 } 296