summaryrefslogtreecommitdiffstats
path: root/usr.sbin/lpr/common_source/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/lpr/common_source/net.c')
-rw-r--r--usr.sbin/lpr/common_source/net.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/usr.sbin/lpr/common_source/net.c b/usr.sbin/lpr/common_source/net.c
new file mode 100644
index 0000000..ab6fa16
--- /dev/null
+++ b/usr.sbin/lpr/common_source/net.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: @(#)common.c 8.5 (Berkeley) 4/28/95
+ */
+
+#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <dirent.h> /* required for lp.h, not used here */
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * 'local_host' is always the hostname of the machine which is running
+ * lpr (lpd, whatever), while 'from_host' either points at 'local_host'
+ * or points at a different buffer when receiving a job from a remote
+ * machine (and that buffer has the hostname of that remote machine).
+ */
+char local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */
+const char *from_host = local_host; /* client's machine name */
+const char *from_ip = ""; /* client machine's IP address */
+
+#ifdef INET6
+u_char family = PF_UNSPEC;
+#else
+u_char family = PF_INET;
+#endif
+
+/*
+ * Create a TCP connection to host "rhost" at port "rport".
+ * If rport == 0, then use the printer service port.
+ * Most of this code comes from rcmd.c.
+ */
+int
+getport(const struct printer *pp, const char *rhost, int rport)
+{
+ struct addrinfo hints, *res, *ai;
+ int s, timo = 1, lport = IPPORT_RESERVED - 1;
+ int error, refused = 0;
+
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (rhost == NULL)
+ fatal(pp, "no remote host to connect to");
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
+ &hints, &res);
+ if (error)
+ fatal(pp, "%s\n", gai_strerror(error));
+ if (rport != 0)
+ ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
+
+ /*
+ * Try connecting to the server.
+ */
+ ai = res;
+retry:
+ PRIV_START
+ s = rresvport_af(&lport, ai->ai_family);
+ PRIV_END
+ if (s < 0) {
+ if (errno != EAGAIN) {
+ if (ai->ai_next) {
+ ai = ai->ai_next;
+ goto retry;
+ }
+ if (refused && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ refused = 0;
+ ai = res;
+ goto retry;
+ }
+ }
+ freeaddrinfo(res);
+ return(-1);
+ }
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+ error = errno;
+ (void) close(s);
+ errno = error;
+ /*
+ * This used to decrement lport, but the current semantics
+ * of rresvport do not provide such a function (in fact,
+ * rresvport should guarantee that the chosen port will
+ * never result in an EADDRINUSE).
+ */
+ if (errno == EADDRINUSE) {
+ goto retry;
+ }
+
+ if (errno == ECONNREFUSED)
+ refused++;
+
+ if (ai->ai_next != NULL) {
+ ai = ai->ai_next;
+ goto retry;
+ }
+ if (refused && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ refused = 0;
+ ai = res;
+ goto retry;
+ }
+ freeaddrinfo(res);
+ return(-1);
+ }
+ freeaddrinfo(res);
+ return(s);
+}
+
+/*
+ * Figure out whether the local machine is the same
+ * as the remote machine (RM) entry (if it exists).
+ * We do this by counting the intersection of our
+ * address list and theirs. This is better than the
+ * old method (comparing the canonical names), as it
+ * allows load-sharing between multiple print servers.
+ * The return value is an error message which must be
+ * free()d.
+ */
+char *
+checkremote(struct printer *pp)
+{
+ char lclhost[MAXHOSTNAMELEN];
+ struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
+ char *error;
+ int ncommonaddrs, errno;
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+
+ if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
+ pp->remote = 1;
+ return NULL;
+ }
+
+ pp->remote = 0; /* assume printer is local */
+ if (pp->remote_host == NULL)
+ return NULL;
+
+ /* get the addresses of the local host */
+ gethostname(lclhost, sizeof(lclhost));
+ lclhost[sizeof(lclhost) - 1] = '\0';
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
+ asprintf(&error, "unable to get official name "
+ "for local machine %s: %s",
+ lclhost, gai_strerror(errno));
+ return error;
+ }
+
+ /* get the official name of RM */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ if ((errno = getaddrinfo(pp->remote_host, NULL,
+ &hints, &remote_res)) != 0) {
+ asprintf(&error, "unable to get address list for "
+ "remote machine %s: %s",
+ pp->remote_host, gai_strerror(errno));
+ freeaddrinfo(local_res);
+ return error;
+ }
+
+ ncommonaddrs = 0;
+ for (lr = local_res; lr; lr = lr->ai_next) {
+ h1[0] = '\0';
+ if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1),
+ NULL, 0, NI_NUMERICHOST) != 0)
+ continue;
+ for (rr = remote_res; rr; rr = rr->ai_next) {
+ h2[0] = '\0';
+ if (getnameinfo(rr->ai_addr, rr->ai_addrlen,
+ h2, sizeof(h2), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ continue;
+ if (strcmp(h1, h2) == 0)
+ ncommonaddrs++;
+ }
+ }
+
+ /*
+ * if the two hosts do not share at least one IP address
+ * then the printer must be remote.
+ */
+ if (ncommonaddrs == 0)
+ pp->remote = 1;
+ freeaddrinfo(local_res);
+ freeaddrinfo(remote_res);
+ return NULL;
+}
+
+/*
+ * This isn't really network-related, but it's used here to write
+ * multi-part strings onto sockets without using stdio. Return
+ * values are as for writev(2).
+ */
+ssize_t
+writel(int strm, ...)
+{
+ va_list ap;
+ int i, n;
+ const char *cp;
+#define NIOV 12
+ struct iovec iov[NIOV], *iovp = iov;
+ ssize_t retval;
+
+ /* first count them */
+ va_start(ap, strm);
+ n = 0;
+ do {
+ cp = va_arg(ap, char *);
+ n++;
+ } while (cp);
+ va_end(ap);
+ n--; /* correct for count of trailing null */
+
+ if (n > NIOV) {
+ iovp = malloc(n * sizeof *iovp);
+ if (iovp == 0)
+ return -1;
+ }
+
+ /* now make up iovec and send */
+ va_start(ap, strm);
+ for (i = 0; i < n; i++) {
+ iovp[i].iov_base = va_arg(ap, char *);
+ iovp[i].iov_len = strlen(iovp[i].iov_base);
+ }
+ va_end(ap);
+ retval = writev(strm, iovp, n);
+ if (iovp != iov)
+ free(iovp);
+ return retval;
+}
OpenPOWER on IntegriCloud