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