IPv6 support for lpr.
Reviewed by: freebsd-current (no objection) Obtained from: KAME
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
# $FreeBSD$
|
# $FreeBSD$
|
||||||
|
|
||||||
|
CFLAGS+=-DINET6
|
||||||
CWARNFLAGS= -Wall -Wnested-externs -Wmissing-prototypes -Wno-unused -Wredundant-decls -Wstrict-prototypes
|
CWARNFLAGS= -Wall -Wnested-externs -Wmissing-prototypes -Wno-unused -Wredundant-decls -Wstrict-prototypes
|
||||||
|
|
||||||
.if exists(${.OBJDIR}/../common_source)
|
.if exists(${.OBJDIR}/../common_source)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All this information used to be in global static variables shared
|
* All this information used to be in global static variables shared
|
||||||
@@ -156,14 +157,14 @@ extern char *name; /* program name */
|
|||||||
/* host machine name */
|
/* host machine name */
|
||||||
extern char host[MAXHOSTNAMELEN];
|
extern char host[MAXHOSTNAMELEN];
|
||||||
extern char *from; /* client's machine name */
|
extern char *from; /* client's machine name */
|
||||||
#define MAXIPSTRLEN 32 /* maxlen of an IP-address as a string */
|
extern char from_ip[NI_MAXHOST]; /* client machine's IP address */
|
||||||
extern char from_ip[MAXIPSTRLEN]; /* client machine's IP address */
|
|
||||||
|
|
||||||
extern int requ[]; /* job number of spool entries */
|
extern int requ[]; /* job number of spool entries */
|
||||||
extern int requests; /* # of spool requests */
|
extern int requests; /* # of spool requests */
|
||||||
extern char *user[]; /* users to process */
|
extern char *user[]; /* users to process */
|
||||||
extern int users; /* # of users in user array */
|
extern int users; /* # of users in user array */
|
||||||
extern char *person; /* name of person doing lprm */
|
extern char *person; /* name of person doing lprm */
|
||||||
|
extern u_char family; /* address family */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure used for building a sorted list of control files.
|
* Structure used for building a sorted list of control files.
|
||||||
|
|||||||
@@ -67,7 +67,13 @@ static const char rcsid[] =
|
|||||||
|
|
||||||
char host[MAXHOSTNAMELEN]; /* host machine name */
|
char host[MAXHOSTNAMELEN]; /* host machine name */
|
||||||
char *from = host; /* client's machine name */
|
char *from = host; /* client's machine name */
|
||||||
char from_ip[MAXIPSTRLEN] = ""; /* client machine's IP address */
|
char from_ip[NI_MAXHOST] = ""; /* client machine's IP address */
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
u_char family = PF_UNSPEC;
|
||||||
|
#else
|
||||||
|
u_char family = PF_INET;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern uid_t uid, euid;
|
extern uid_t uid, euid;
|
||||||
|
|
||||||
@@ -79,46 +85,52 @@ extern uid_t uid, euid;
|
|||||||
int
|
int
|
||||||
getport(const struct printer *pp, const char *rhost, int rport)
|
getport(const struct printer *pp, const char *rhost, int rport)
|
||||||
{
|
{
|
||||||
struct hostent *hp;
|
struct addrinfo hints, *res, *ai;
|
||||||
struct servent *sp;
|
|
||||||
struct sockaddr_in sin;
|
|
||||||
int s, timo = 1, lport = IPPORT_RESERVED - 1;
|
int s, timo = 1, lport = IPPORT_RESERVED - 1;
|
||||||
int err;
|
int err, refused = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the host address and port number to connect to.
|
* Get the host address and port number to connect to.
|
||||||
*/
|
*/
|
||||||
if (rhost == NULL)
|
if (rhost == NULL)
|
||||||
fatal(pp, "no remote host to connect to");
|
fatal(pp, "no remote host to connect to");
|
||||||
bzero((char *)&sin, sizeof(sin));
|
memset(&hints, 0, sizeof(hints));
|
||||||
sin.sin_len = sizeof sin;
|
hints.ai_family = family;
|
||||||
sin.sin_family = AF_INET;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
if (inet_aton(rhost, &sin.sin_addr) == 0) {
|
hints.ai_protocol = 0;
|
||||||
hp = gethostbyname2(rhost, AF_INET);
|
err = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
|
||||||
if (hp == NULL)
|
&hints, &res);
|
||||||
fatal(pp, "cannot resolve %s: %s", rhost,
|
if (err)
|
||||||
hstrerror(h_errno));
|
fatal(pp, "%s\n", gai_strerror(err));
|
||||||
/* XXX - should deal with more addresses */
|
if (rport != 0)
|
||||||
sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
|
((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
|
||||||
}
|
|
||||||
if (rport == 0) {
|
|
||||||
sp = getservbyname("printer", "tcp");
|
|
||||||
if (sp == NULL)
|
|
||||||
fatal(pp, "printer/tcp: unknown service");
|
|
||||||
sin.sin_port = sp->s_port;
|
|
||||||
} else
|
|
||||||
sin.sin_port = htons(rport);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try connecting to the server.
|
* Try connecting to the server.
|
||||||
*/
|
*/
|
||||||
|
ai = res;
|
||||||
retry:
|
retry:
|
||||||
seteuid(euid);
|
seteuid(euid);
|
||||||
s = rresvport(&lport);
|
s = rresvport_af(&lport, ai->ai_family);
|
||||||
seteuid(uid);
|
seteuid(uid);
|
||||||
if (s < 0)
|
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);
|
return(-1);
|
||||||
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
}
|
||||||
|
if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||||
err = errno;
|
err = errno;
|
||||||
(void) close(s);
|
(void) close(s);
|
||||||
errno = err;
|
errno = err;
|
||||||
@@ -128,16 +140,28 @@ getport(const struct printer *pp, const char *rhost, int rport)
|
|||||||
* rresvport should guarantee that the chosen port will
|
* rresvport should guarantee that the chosen port will
|
||||||
* never result in an EADDRINUSE).
|
* never result in an EADDRINUSE).
|
||||||
*/
|
*/
|
||||||
if (errno == EADDRINUSE)
|
if (errno == EADDRINUSE) {
|
||||||
goto retry;
|
|
||||||
|
|
||||||
if (errno == ECONNREFUSED && timo <= 16) {
|
|
||||||
sleep(timo);
|
|
||||||
timo *= 2;
|
|
||||||
goto retry;
|
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);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
return(s);
|
return(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,10 +179,10 @@ char *
|
|||||||
checkremote(struct printer *pp)
|
checkremote(struct printer *pp)
|
||||||
{
|
{
|
||||||
char name[MAXHOSTNAMELEN];
|
char name[MAXHOSTNAMELEN];
|
||||||
register struct hostent *hp;
|
struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
|
||||||
char *err;
|
char *err;
|
||||||
struct in_addr *localaddrs;
|
int ncommonaddrs, error;
|
||||||
int i, j, nlocaladdrs, ncommonaddrs;
|
char h1[NI_MAXHOST], h2[NI_MAXHOST];
|
||||||
|
|
||||||
if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
|
if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
|
||||||
pp->remote = 1;
|
pp->remote = 1;
|
||||||
@@ -166,57 +190,63 @@ checkremote(struct printer *pp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pp->remote = 0; /* assume printer is local */
|
pp->remote = 0; /* assume printer is local */
|
||||||
if (pp->remote_host != NULL) {
|
if (pp->remote_host == NULL)
|
||||||
/* get the addresses of the local host */
|
return NULL;
|
||||||
gethostname(name, sizeof(name));
|
|
||||||
name[sizeof(name) - 1] = '\0';
|
|
||||||
hp = gethostbyname2(name, AF_INET);
|
|
||||||
if (hp == (struct hostent *) NULL) {
|
|
||||||
asprintf(&err, "unable to get official name "
|
|
||||||
"for local machine %s: %s",
|
|
||||||
name, hstrerror(h_errno));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
for (i = 0; hp->h_addr_list[i]; i++)
|
|
||||||
;
|
|
||||||
nlocaladdrs = i;
|
|
||||||
localaddrs = malloc(i * sizeof(struct in_addr));
|
|
||||||
if (localaddrs == 0) {
|
|
||||||
asprintf(&err, "malloc %lu bytes failed",
|
|
||||||
(u_long)i * sizeof(struct in_addr));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
for (i = 0; hp->h_addr_list[i]; i++)
|
|
||||||
localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i];
|
|
||||||
|
|
||||||
/* get the official name of RM */
|
/* get the addresses of the local host */
|
||||||
hp = gethostbyname2(pp->remote_host, AF_INET);
|
gethostname(name, sizeof(name));
|
||||||
if (hp == (struct hostent *) NULL) {
|
name[sizeof(name) - 1] = '\0';
|
||||||
asprintf(&err, "unable to get address list for "
|
|
||||||
"remote machine %s: %s",
|
|
||||||
pp->remote_host, hstrerror(h_errno));
|
|
||||||
free(localaddrs);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ncommonaddrs = 0;
|
memset(&hints, 0, sizeof(hints));
|
||||||
for (i = 0; i < nlocaladdrs; i++) {
|
hints.ai_family = family;
|
||||||
for (j = 0; hp->h_addr_list[j]; j++) {
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
char *them = hp->h_addr_list[j];
|
hints.ai_flags = AI_PASSIVE;
|
||||||
if (localaddrs[i].s_addr ==
|
if ((error = getaddrinfo(name, NULL, &hints, &local_res)) != 0) {
|
||||||
(*(struct in_addr *)them).s_addr)
|
asprintf(&err, "unable to get official name "
|
||||||
ncommonaddrs++;
|
"for local machine %s: %s",
|
||||||
}
|
name, gai_strerror(error));
|
||||||
}
|
return err;
|
||||||
|
|
||||||
/*
|
|
||||||
* if the two hosts do not share at least one IP address
|
|
||||||
* then the printer must be remote.
|
|
||||||
*/
|
|
||||||
if (ncommonaddrs == 0)
|
|
||||||
pp->remote = 1;
|
|
||||||
free(localaddrs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 ((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 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
.Nd line printer spooler daemon
|
.Nd line printer spooler daemon
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl dlp
|
.Op Fl dlp46
|
||||||
.Op Ar port#
|
.Op Ar port#
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm Lpd
|
.Nm Lpd
|
||||||
@@ -81,6 +81,12 @@ The
|
|||||||
flag causes
|
flag causes
|
||||||
.Nm
|
.Nm
|
||||||
not to open an Internet listening socket.
|
not to open an Internet listening socket.
|
||||||
|
.It Fl 4
|
||||||
|
Inet only.
|
||||||
|
.It Fl 6
|
||||||
|
Inet6 only.
|
||||||
|
.It Fl 46
|
||||||
|
Inet and inet6 (default).
|
||||||
.It Ar "port#"
|
.It Ar "port#"
|
||||||
The Internet port number used to rendezvous
|
The Internet port number used to rendezvous
|
||||||
with other processes is normally obtained with
|
with other processes is normally obtained with
|
||||||
|
|||||||
+184
-61
@@ -112,12 +112,14 @@ static void reapchild __P((int));
|
|||||||
static void mcleanup __P((int));
|
static void mcleanup __P((int));
|
||||||
static void doit __P((void));
|
static void doit __P((void));
|
||||||
static void startup __P((void));
|
static void startup __P((void));
|
||||||
static void chkhost __P((struct sockaddr_in *));
|
static void chkhost __P((struct sockaddr *));
|
||||||
static int ckqueue __P((struct printer *));
|
static int ckqueue __P((struct printer *));
|
||||||
static void usage __P((void));
|
static void usage __P((void));
|
||||||
/* From rcmd.c: */
|
static int *socksetup __P((int, int));
|
||||||
int __ivaliduser __P((FILE *, u_long, const char *,
|
|
||||||
const char *));
|
/* XXX from libc/net/rcmd.c */
|
||||||
|
extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t,
|
||||||
|
const char *, const char *));
|
||||||
|
|
||||||
uid_t uid, euid;
|
uid_t uid, euid;
|
||||||
|
|
||||||
@@ -126,13 +128,14 @@ main(argc, argv)
|
|||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
int errs, f, funix, finet, fromlen, i, socket_debug;
|
int errs, f, funix, *finet, fromlen, i, options, socket_debug;
|
||||||
fd_set defreadfds;
|
fd_set defreadfds;
|
||||||
struct sockaddr_un un, fromunix;
|
struct sockaddr_un un, fromunix;
|
||||||
struct sockaddr_in sin, frominet;
|
struct sockaddr_storage frominet;
|
||||||
int lfd;
|
int lfd;
|
||||||
sigset_t omask, nmask;
|
sigset_t omask, nmask;
|
||||||
struct servent *sp, serv;
|
struct servent *sp, serv;
|
||||||
|
int inet_flag = 0, inet6_flag = 0;
|
||||||
|
|
||||||
euid = geteuid(); /* these shouldn't be different */
|
euid = geteuid(); /* these shouldn't be different */
|
||||||
uid = getuid();
|
uid = getuid();
|
||||||
@@ -145,7 +148,7 @@ main(argc, argv)
|
|||||||
errx(EX_NOPERM,"must run as root");
|
errx(EX_NOPERM,"must run as root");
|
||||||
|
|
||||||
errs = 0;
|
errs = 0;
|
||||||
while ((i = getopt(argc, argv, "dlp")) != -1)
|
while ((i = getopt(argc, argv, "dlp46")) != -1)
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 'd':
|
case 'd':
|
||||||
socket_debug++;
|
socket_debug++;
|
||||||
@@ -156,9 +159,19 @@ main(argc, argv)
|
|||||||
case 'p':
|
case 'p':
|
||||||
pflag++;
|
pflag++;
|
||||||
break;
|
break;
|
||||||
|
case '4':
|
||||||
|
family = PF_INET;
|
||||||
|
inet_flag++;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
family = PF_INET6;
|
||||||
|
inet6_flag++;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
errs++;
|
errs++;
|
||||||
}
|
}
|
||||||
|
if (inet_flag && inet6_flag)
|
||||||
|
family = PF_UNSPEC;
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (errs)
|
if (errs)
|
||||||
@@ -283,32 +296,17 @@ main(argc, argv)
|
|||||||
FD_ZERO(&defreadfds);
|
FD_ZERO(&defreadfds);
|
||||||
FD_SET(funix, &defreadfds);
|
FD_SET(funix, &defreadfds);
|
||||||
listen(funix, 5);
|
listen(funix, 5);
|
||||||
finet = -1;
|
|
||||||
if (pflag == 0) {
|
if (pflag == 0) {
|
||||||
finet = socket(AF_INET, SOCK_STREAM, 0);
|
options = SO_REUSEADDR;
|
||||||
if (finet >= 0) {
|
if (socket_debug)
|
||||||
i = 1;
|
options |= SO_DEBUG;
|
||||||
if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &i,
|
finet = socksetup(family, options);
|
||||||
sizeof i) < 0) {
|
} else
|
||||||
syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m");
|
finet = NULL; /* pretend we couldn't open TCP socket. */
|
||||||
mcleanup(0);
|
if (finet) {
|
||||||
}
|
for (i = 1; i <= *finet; i++) {
|
||||||
if (socket_debug &&
|
FD_SET(finet[i], &defreadfds);
|
||||||
setsockopt(finet, SOL_SOCKET, SO_DEBUG,
|
listen(finet[i], 5);
|
||||||
&socket_debug, sizeof(socket_debug)) < 0) {
|
|
||||||
syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
|
|
||||||
mcleanup(0);
|
|
||||||
}
|
|
||||||
memset(&sin, 0, sizeof(sin));
|
|
||||||
sin.sin_family = AF_INET;
|
|
||||||
sin.sin_port = sp->s_port;
|
|
||||||
if (bind(finet, (struct sockaddr *)&sin,
|
|
||||||
sizeof(sin)) < 0) {
|
|
||||||
syslog(LOG_ERR, "bind: %m");
|
|
||||||
mcleanup(0);
|
|
||||||
}
|
|
||||||
FD_SET(finet, &defreadfds);
|
|
||||||
listen(finet, 5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -322,7 +320,7 @@ main(argc, argv)
|
|||||||
* XXX - should be redone for multi-protocol
|
* XXX - should be redone for multi-protocol
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int domain, nfds, s;
|
int domain = -1, nfds, s = -1;
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
|
|
||||||
FD_COPY(&defreadfds, &readfds);
|
FD_COPY(&defreadfds, &readfds);
|
||||||
@@ -338,14 +336,15 @@ main(argc, argv)
|
|||||||
domain = AF_UNIX, fromlen = sizeof(fromunix);
|
domain = AF_UNIX, fromlen = sizeof(fromunix);
|
||||||
s = accept(funix,
|
s = accept(funix,
|
||||||
(struct sockaddr *)&fromunix, &fromlen);
|
(struct sockaddr *)&fromunix, &fromlen);
|
||||||
} else if (pflag == 0) /* if (FD_ISSET(finet, &readfds)) */ {
|
} else {
|
||||||
domain = AF_INET, fromlen = sizeof(frominet);
|
for (i = 1; i <= *finet; i++)
|
||||||
s = accept(finet,
|
if (FD_ISSET(finet[i], &readfds)) {
|
||||||
(struct sockaddr *)&frominet, &fromlen);
|
domain = AF_INET;
|
||||||
if (frominet.sin_port == htons(20)) {
|
fromlen = sizeof(frominet);
|
||||||
close(s);
|
s = accept(finet[i],
|
||||||
continue;
|
(struct sockaddr *)&frominet,
|
||||||
}
|
&fromlen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
@@ -359,14 +358,16 @@ main(argc, argv)
|
|||||||
signal(SIGQUIT, SIG_IGN);
|
signal(SIGQUIT, SIG_IGN);
|
||||||
signal(SIGTERM, SIG_IGN);
|
signal(SIGTERM, SIG_IGN);
|
||||||
(void) close(funix);
|
(void) close(funix);
|
||||||
if (pflag == 0) {
|
if (pflag == 0 && finet) {
|
||||||
(void) close(finet);
|
for (i = 1; i <= *finet; i++)
|
||||||
|
(void)close(finet[i]);
|
||||||
}
|
}
|
||||||
dup2(s, 1);
|
dup2(s, 1);
|
||||||
(void) close(s);
|
(void) close(s);
|
||||||
if (domain == AF_INET) {
|
if (domain == AF_INET) {
|
||||||
|
/* for both AF_INET and AF_INET6 */
|
||||||
from_remote = 1;
|
from_remote = 1;
|
||||||
chkhost(&frominet);
|
chkhost((struct sockaddr *)&frominet);
|
||||||
} else
|
} else
|
||||||
from_remote = 0;
|
from_remote = 0;
|
||||||
doit();
|
doit();
|
||||||
@@ -606,35 +607,75 @@ ckqueue(pp)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
chkhost(f)
|
chkhost(f)
|
||||||
struct sockaddr_in *f;
|
struct sockaddr *f;
|
||||||
{
|
{
|
||||||
register struct hostent *hp;
|
struct addrinfo hints, *res, *r;
|
||||||
register FILE *hostf;
|
register FILE *hostf;
|
||||||
int first = 1;
|
int first = 1;
|
||||||
int good = 0;
|
int good = 0;
|
||||||
|
char host[NI_MAXHOST], ip[NI_MAXHOST];
|
||||||
|
char serv[NI_MAXSERV];
|
||||||
|
int error, addrlen;
|
||||||
|
caddr_t addr;
|
||||||
|
|
||||||
|
error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
|
||||||
|
NI_NUMERICSERV);
|
||||||
|
if (error || atoi(serv) >= IPPORT_RESERVED)
|
||||||
|
fatal(0, "Malformed from address");
|
||||||
|
|
||||||
/* Need real hostname for temporary filenames */
|
/* Need real hostname for temporary filenames */
|
||||||
hp = gethostbyaddr((char *)&f->sin_addr,
|
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
|
||||||
sizeof(struct in_addr), f->sin_family);
|
NI_NAMEREQD);
|
||||||
if (hp == NULL)
|
if (error) {
|
||||||
fatal(0, "Host name for your address (%s) unknown",
|
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
|
||||||
inet_ntoa(f->sin_addr));
|
NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||||
|
if (error)
|
||||||
|
fatal(0, "Host name for your address unknown");
|
||||||
|
else
|
||||||
|
fatal(0, "Host name for your address (%s) unknown",
|
||||||
|
host);
|
||||||
|
}
|
||||||
|
|
||||||
(void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1);
|
(void)strncpy(fromb, host, sizeof(fromb) - 1);
|
||||||
fromb[sizeof(fromb) - 1] = '\0';
|
fromb[sizeof(fromb) - 1] = '\0';
|
||||||
from = fromb;
|
from = fromb;
|
||||||
strncpy(from_ip, inet_ntoa(f->sin_addr), MAXIPSTRLEN);
|
|
||||||
|
/* Need address in stringform for comparison (no DNS lookup here) */
|
||||||
|
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
|
||||||
|
NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||||
|
if (error)
|
||||||
|
fatal(0, "Cannot print address");
|
||||||
|
strncpy(from_ip, host, NI_MAXHOST);
|
||||||
from_ip[sizeof(from_ip) - 1] = '\0';
|
from_ip[sizeof(from_ip) - 1] = '\0';
|
||||||
|
|
||||||
|
/* Reject numeric addresses */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = family;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
|
||||||
|
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||||
|
if (getaddrinfo(fromb, NULL, &hints, &res) == 0) {
|
||||||
|
freeaddrinfo(res);
|
||||||
|
fatal(0, "reverse lookup results in non-FQDN %s", fromb);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for spoof, ala rlogind */
|
/* Check for spoof, ala rlogind */
|
||||||
hp = gethostbyname(fromb);
|
memset(&hints, 0, sizeof(hints));
|
||||||
if (!hp)
|
hints.ai_family = family;
|
||||||
fatal(0, "hostname for your address (%s) unknown", from_ip);
|
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
|
||||||
for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
|
error = getaddrinfo(fromb, NULL, &hints, &res);
|
||||||
if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
|
if (error) {
|
||||||
sizeof(f->sin_addr)))
|
fatal(0, "hostname for your address (%s) unknown: %s", from_ip,
|
||||||
|
gai_strerror(error));
|
||||||
|
}
|
||||||
|
good = 0;
|
||||||
|
for (r = res; good == 0 && r; r = r->ai_next) {
|
||||||
|
error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip),
|
||||||
|
NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||||
|
if (!error && !strcmp(from_ip, ip))
|
||||||
good = 1;
|
good = 1;
|
||||||
}
|
}
|
||||||
|
if (res)
|
||||||
|
freeaddrinfo(res);
|
||||||
if (good == 0)
|
if (good == 0)
|
||||||
fatal(0, "address for your hostname (%s) not matched",
|
fatal(0, "address for your hostname (%s) not matched",
|
||||||
from_ip);
|
from_ip);
|
||||||
@@ -642,8 +683,7 @@ chkhost(f)
|
|||||||
hostf = fopen(_PATH_HOSTSEQUIV, "r");
|
hostf = fopen(_PATH_HOSTSEQUIV, "r");
|
||||||
again:
|
again:
|
||||||
if (hostf) {
|
if (hostf) {
|
||||||
if (__ivaliduser(hostf, f->sin_addr.s_addr,
|
if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
|
||||||
DUMMY, DUMMY) == 0) {
|
|
||||||
(void) fclose(hostf);
|
(void) fclose(hostf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -664,3 +704,86 @@ usage()
|
|||||||
fprintf(stderr, "usage: lpd [-dlp] [port#]\n");
|
fprintf(stderr, "usage: lpd [-dlp] [port#]\n");
|
||||||
exit(EX_USAGE);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* setup server socket for specified address family */
|
||||||
|
/* if af is PF_UNSPEC more than one socket may be returned */
|
||||||
|
/* the returned list is dynamically allocated, so caller needs to free it */
|
||||||
|
static int *
|
||||||
|
socksetup(af, options)
|
||||||
|
int af, options;
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res, *r;
|
||||||
|
int error, maxs, *s, *socks;
|
||||||
|
const int on = 1;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
hints.ai_family = af;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
error = getaddrinfo(NULL, "printer", &hints, &res);
|
||||||
|
if (error) {
|
||||||
|
syslog(LOG_ERR, "%s", gai_strerror(error));
|
||||||
|
mcleanup(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count max number of sockets we may open */
|
||||||
|
for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
|
||||||
|
;
|
||||||
|
socks = malloc((maxs + 1) * sizeof(int));
|
||||||
|
if (!socks) {
|
||||||
|
syslog(LOG_ERR, "couldn't allocate memory for sockets");
|
||||||
|
mcleanup(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*socks = 0; /* num of sockets counter at start of array */
|
||||||
|
s = socks + 1;
|
||||||
|
for (r = res; r; r = r->ai_next) {
|
||||||
|
*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
|
||||||
|
if (*s < 0) {
|
||||||
|
syslog(LOG_DEBUG, "socket(): %m");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (options & SO_REUSEADDR)
|
||||||
|
if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on,
|
||||||
|
sizeof(on)) < 0) {
|
||||||
|
syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m");
|
||||||
|
close(*s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (options & SO_DEBUG)
|
||||||
|
if (setsockopt(*s, SOL_SOCKET, SO_DEBUG,
|
||||||
|
&on, sizeof(on)) < 0) {
|
||||||
|
syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
|
||||||
|
close(*s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef IPV6_BINDV6ONLY
|
||||||
|
if (r->ai_family == AF_INET6) {
|
||||||
|
if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
|
||||||
|
&on, sizeof(on)) < 0) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"setsockopt (IPV6_BINDV6ONLY): %m");
|
||||||
|
close(*s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
|
||||||
|
syslog(LOG_DEBUG, "bind(): %m");
|
||||||
|
close(*s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*socks)++;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
if (*socks == 0) {
|
||||||
|
syslog(LOG_ERR, "Couldn't bind to any socket");
|
||||||
|
free(socks);
|
||||||
|
mcleanup(0);
|
||||||
|
}
|
||||||
|
return(socks);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user