#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>
#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"
char local_host[MAXHOSTNAMELEN];
const char *from_host = local_host;
const char *from_ip = "";
#ifdef INET6
u_char family = PF_UNSPEC;
#else
u_char family = PF_INET;
#endif
extern uid_t uid, euid;
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 err, refused = 0;
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;
err = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
&hints, &res);
if (err)
fatal(pp, "%s\n", gai_strerror(err));
if (rport != 0)
((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
ai = res;
retry:
seteuid(euid);
s = rresvport_af(&lport, ai->ai_family);
seteuid(uid);
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) {
err = errno;
close(s);
errno = err;
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);
}
char *
checkremote(struct printer *pp)
{
char lclhost[MAXHOSTNAMELEN];
struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
char *err;
int ncommonaddrs, error;
char h1[NI_MAXHOST], h2[NI_MAXHOST];
if (!pp->rp_matches_local) {
pp->remote = 1;
return NULL;
}
pp->remote = 0;
if (pp->remote_host == NULL)
return NULL;
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 ((error = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
asprintf(&err, "unable to get official name "
"for local machine %s: %s",
lclhost, gai_strerror(error));
return err;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((error = getaddrinfo(pp->remote_host, NULL,
&hints, &remote_res)) != 0) {
asprintf(&err, "unable to get address list for "
"remote machine %s: %s",
pp->remote_host, gai_strerror(error));
freeaddrinfo(local_res);
return err;
}
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 | NI_WITHSCOPEID) != 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 | NI_WITHSCOPEID) != 0)
continue;
if (strcmp(h1, h2) == 0)
ncommonaddrs++;
}
}
if (ncommonaddrs == 0)
pp->remote = 1;
freeaddrinfo(local_res);
freeaddrinfo(remote_res);
return NULL;
}
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;
va_start(ap, strm);
n = 0;
do {
cp = va_arg(ap, char *);
n++;
} while (cp);
va_end(ap);
n--;
if (n > NIOV) {
iovp = malloc(n * sizeof *iovp);
if (iovp == NULL)
return -1;
}
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;
}