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 "$Id$"; 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 pp->remote = 0; /* assume printer is local */ 164 if (pp->remote_host != NULL) { 165 /* get the addresses of the local host */ 166 gethostname(name, sizeof(name)); 167 name[sizeof(name) - 1] = '\0'; 168 hp = gethostbyname2(name, AF_INET); 169 if (hp == (struct hostent *) NULL) { 170 asprintf(&err, "unable to get official name " 171 "for local machine %s: %s", 172 name, hstrerror(h_errno)); 173 return err; 174 } 175 for (i = 0; hp->h_addr_list[i]; i++) 176 ; 177 nlocaladdrs = i; 178 localaddrs = malloc(i * sizeof(struct in_addr)); 179 if (localaddrs == 0) { 180 asprintf(&err, "malloc %lu bytes failed", 181 (u_long)i * sizeof(struct in_addr)); 182 return err; 183 } 184 for (i = 0; hp->h_addr_list[i]; i++) 185 localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i]; 186 187 /* get the official name of RM */ 188 hp = gethostbyname2(pp->remote_host, AF_INET); 189 if (hp == (struct hostent *) NULL) { 190 asprintf(&err, "unable to get address list for " 191 "remote machine %s: %s", 192 pp->remote_host, hstrerror(h_errno)); 193 free(localaddrs); 194 return err; 195 } 196 197 ncommonaddrs = 0; 198 for (i = 0; i < nlocaladdrs; i++) { 199 for (j = 0; hp->h_addr_list[j]; j++) { 200 char *them = hp->h_addr_list[j]; 201 if (localaddrs[i].s_addr == 202 (*(struct in_addr *)them).s_addr) 203 ncommonaddrs++; 204 } 205 } 206 207 /* 208 * if the two hosts do not share at least one IP address 209 * then the printer must be remote. 210 */ 211 if (ncommonaddrs == 0) 212 pp->remote = 1; 213 free(localaddrs); 214 } 215 return NULL; 216 } 217 218 /* 219 * This isn't really network-related, but it's used here to write 220 * multi-part strings onto sockets without using stdio. Return 221 * values are as for writev(2). 222 */ 223 ssize_t 224 writel(int s, ...) 225 { 226 va_list ap; 227 int i, n; 228 const char *cp; 229 #define NIOV 12 230 struct iovec iov[NIOV], *iovp = iov; 231 ssize_t retval; 232 233 /* first count them */ 234 va_start(ap, s); 235 n = 0; 236 do { 237 cp = va_arg(ap, char *); 238 n++; 239 } while (cp); 240 va_end(ap); 241 n--; /* correct for count of trailing null */ 242 243 if (n > NIOV) { 244 iovp = malloc(n * sizeof *iovp); 245 if (iovp == 0) 246 return -1; 247 } 248 249 /* now make up iovec and send */ 250 va_start(ap, s); 251 for (i = 0; i < n; i++) { 252 iovp[i].iov_base = va_arg(ap, char *); 253 iovp[i].iov_len = strlen(iovp[i].iov_base); 254 } 255 va_end(ap); 256 retval = writev(s, iovp, n); 257 if (iovp != iov) 258 free(iovp); 259 return retval; 260 } 261