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 /* host machine name */ 69 char host[MAXHOSTNAMELEN]; 70 char *from = host; /* client's machine name */ 71 72 extern uid_t uid, euid; 73 74 /* 75 * Create a TCP connection to host "rhost" at port "rport". 76 * If rport == 0, then use the printer service port. 77 * Most of this code comes from rcmd.c. 78 */ 79 int 80 getport(const struct printer *pp, const char *rhost, int rport) 81 { 82 struct hostent *hp; 83 struct servent *sp; 84 struct sockaddr_in sin; 85 int s, timo = 1, lport = IPPORT_RESERVED - 1; 86 int err; 87 88 /* 89 * Get the host address and port number to connect to. 90 */ 91 if (rhost == NULL) 92 fatal(pp, "no remote host to connect to"); 93 bzero((char *)&sin, sizeof(sin)); 94 sin.sin_len = sizeof sin; 95 sin.sin_family = AF_INET; 96 if (inet_aton(rhost, &sin.sin_addr) == 0) { 97 hp = gethostbyname2(rhost, AF_INET); 98 if (hp == NULL) 99 fatal(pp, "cannot resolve %s: %s", rhost, 100 hstrerror(h_errno)); 101 /* XXX - should deal with more addresses */ 102 sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0]; 103 } 104 if (rport == 0) { 105 sp = getservbyname("printer", "tcp"); 106 if (sp == NULL) 107 fatal(pp, "printer/tcp: unknown service"); 108 sin.sin_port = sp->s_port; 109 } else 110 sin.sin_port = htons(rport); 111 112 /* 113 * Try connecting to the server. 114 */ 115 retry: 116 seteuid(euid); 117 s = rresvport(&lport); 118 seteuid(uid); 119 if (s < 0) 120 return(-1); 121 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 122 err = errno; 123 (void) close(s); 124 errno = err; 125 /* 126 * This used to decrement lport, but the current semantics 127 * of rresvport do not provide such a function (in fact, 128 * rresvport should guarantee that the chosen port will 129 * never result in an EADDRINUSE). 130 */ 131 if (errno == EADDRINUSE) 132 goto retry; 133 134 if (errno == ECONNREFUSED && timo <= 16) { 135 sleep(timo); 136 timo *= 2; 137 goto retry; 138 } 139 return(-1); 140 } 141 return(s); 142 } 143 144 /* 145 * Figure out whether the local machine is the same 146 * as the remote machine (RM) entry (if it exists). 147 * We do this by counting the intersection of our 148 * address list and theirs. This is better than the 149 * old method (comparing the canonical names), as it 150 * allows load-sharing between multiple print servers. 151 * The return value is an error message which must be 152 * free()d. 153 */ 154 char * 155 checkremote(struct printer *pp) 156 { 157 char name[MAXHOSTNAMELEN]; 158 register struct hostent *hp; 159 char *err; 160 struct in_addr *localaddrs; 161 int i, j, nlocaladdrs, ncommonaddrs; 162 163 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ 164 pp->remote = 1; 165 return NULL; 166 } 167 168 pp->remote = 0; /* assume printer is local */ 169 if (pp->remote_host != NULL) { 170 /* get the addresses of the local host */ 171 gethostname(name, sizeof(name)); 172 name[sizeof(name) - 1] = '\0'; 173 hp = gethostbyname2(name, AF_INET); 174 if (hp == (struct hostent *) NULL) { 175 asprintf(&err, "unable to get official name " 176 "for local machine %s: %s", 177 name, hstrerror(h_errno)); 178 return err; 179 } 180 for (i = 0; hp->h_addr_list[i]; i++) 181 ; 182 nlocaladdrs = i; 183 localaddrs = malloc(i * sizeof(struct in_addr)); 184 if (localaddrs == 0) { 185 asprintf(&err, "malloc %lu bytes failed", 186 (u_long)i * sizeof(struct in_addr)); 187 return err; 188 } 189 for (i = 0; hp->h_addr_list[i]; i++) 190 localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i]; 191 192 /* get the official name of RM */ 193 hp = gethostbyname2(pp->remote_host, AF_INET); 194 if (hp == (struct hostent *) NULL) { 195 asprintf(&err, "unable to get address list for " 196 "remote machine %s: %s", 197 pp->remote_host, hstrerror(h_errno)); 198 free(localaddrs); 199 return err; 200 } 201 202 ncommonaddrs = 0; 203 for (i = 0; i < nlocaladdrs; i++) { 204 for (j = 0; hp->h_addr_list[j]; j++) { 205 char *them = hp->h_addr_list[j]; 206 if (localaddrs[i].s_addr == 207 (*(struct in_addr *)them).s_addr) 208 ncommonaddrs++; 209 } 210 } 211 212 /* 213 * if the two hosts do not share at least one IP address 214 * then the printer must be remote. 215 */ 216 if (ncommonaddrs == 0) 217 pp->remote = 1; 218 free(localaddrs); 219 } 220 return NULL; 221 } 222 223 /* 224 * This isn't really network-related, but it's used here to write 225 * multi-part strings onto sockets without using stdio. Return 226 * values are as for writev(2). 227 */ 228 ssize_t 229 writel(int s, ...) 230 { 231 va_list ap; 232 int i, n; 233 const char *cp; 234 #define NIOV 12 235 struct iovec iov[NIOV], *iovp = iov; 236 ssize_t retval; 237 238 /* first count them */ 239 va_start(ap, s); 240 n = 0; 241 do { 242 cp = va_arg(ap, char *); 243 n++; 244 } while (cp); 245 va_end(ap); 246 n--; /* correct for count of trailing null */ 247 248 if (n > NIOV) { 249 iovp = malloc(n * sizeof *iovp); 250 if (iovp == 0) 251 return -1; 252 } 253 254 /* now make up iovec and send */ 255 va_start(ap, s); 256 for (i = 0; i < n; i++) { 257 iovp[i].iov_base = va_arg(ap, char *); 258 iovp[i].iov_len = strlen(iovp[i].iov_base); 259 } 260 va_end(ap); 261 retval = writev(s, iovp, n); 262 if (iovp != iov) 263 free(iovp); 264 return retval; 265 } 266