IPv6 support, using rcmd-family funciton added.

NetBSD PR: 9050
From: Feico Dillema
This commit is contained in:
itojun 2000-01-27 05:39:50 +00:00
parent 5b1aaa939e
commit 33ba3a0f18
3 changed files with 205 additions and 116 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: common.c,v 1.16 1999/12/05 22:10:57 jdolecek Exp $ */
/* $NetBSD: common.c,v 1.17 2000/01/27 05:39:50 itojun Exp $ */
/*
* Copyright (c) 1983, 1993
@ -43,7 +43,7 @@
#if 0
static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: common.c,v 1.16 1999/12/05 22:10:57 jdolecek Exp $");
__RCSID("$NetBSD: common.c,v 1.17 2000/01/27 05:39:50 itojun Exp $");
#endif
#endif /* not lint */
@ -128,60 +128,54 @@ getport(rhost, rport)
char *rhost;
int rport;
{
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;
struct addrinfo hints, *res, *r;
u_int timo = 1;
int s, lport = IPPORT_RESERVED - 1;
int err;
int error;
/*
* Get the host address and port number to connect to.
*/
if (rhost == NULL)
fatal("no remote host to connect to");
memset(&sin, 0, sizeof(sin));
if (inet_aton(rhost, &sin.sin_addr) == 1)
sin.sin_family = AF_INET;
else {
hp = gethostbyname(rhost);
if (hp == NULL)
fatal("unknown host %s", rhost);
memmove(&sin.sin_addr, hp->h_addr, (size_t)hp->h_length);
sin.sin_family = hp->h_addrtype;
}
if (rport == 0) {
sp = getservbyname("printer", "tcp");
if (sp == NULL)
fatal("printer/tcp: unknown service");
sin.sin_port = sp->s_port;
} else
sin.sin_port = htons(rport);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(rhost, "printer", &hints, &res);
if (error)
fatal("printer/tcp: %s", gai_strerror(error));
/*
* Try connecting to the server.
*/
s = -1;
for (r = res; r; r = r->ai_next) {
retry:
seteuid(euid);
s = rresvport(&lport);
seteuid(uid);
if (s < 0)
return(-1);
if (connect(s, (const struct sockaddr *)&sin, sizeof(sin)) < 0) {
err = errno;
(void)close(s);
errno = err;
if (errno == EADDRINUSE) {
lport--;
goto retry;
}
if (errno == ECONNREFUSED && timo <= 16) {
sleep(timo);
timo *= 2;
goto retry;
}
return(-1);
seteuid(euid);
s = rresvport_af(&lport, r->ai_family);
seteuid(uid);
if (s < 0)
return(-1);
if (connect(s, r->ai_addr, r->ai_addrlen) < 0) {
error = errno;
(void)close(s);
s = -1;
errno = error;
if (errno == EADDRINUSE) {
lport--;
goto retry;
}
if (errno == ECONNREFUSED && timo <= 16) {
sleep(timo);
timo *= 2;
goto retry;
}
continue;
} else
break;
}
if (res)
freeaddrinfo(res);
return(s);
}
@ -299,45 +293,63 @@ compar(p1, p2)
/*
* Figure out whether the local machine is the same
* as the remote machine (RM) entry (if it exists).
*
* XXX not really the right way to determine.
*/
char *
checkremote()
{
char hname[MAXHOSTNAMELEN + 1];
struct hostent *hp;
char hname[NI_MAXHOST];
struct addrinfo hints, *res;
static char errbuf[128];
int error;
remote = 0; /* assume printer is local */
if (RM != NULL) {
/* get the official name of the local host */
gethostname(hname, sizeof(hname));
hname[sizeof(hname)-1] = '\0';
hp = gethostbyname(hname);
if (hp == (struct hostent *) NULL) {
(void)snprintf(errbuf, sizeof(errbuf),
"unable to get official name for local machine %s",
hname);
return errbuf;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
error = getaddrinfo(hname, NULL, &hints, &res);
if (error) {
(void)snprintf(errbuf, sizeof(errbuf),
"unable to get official name for local machine %s: "
"%s", hname, gai_strerror(error));
return errbuf;
} else {
(void)strncpy(hname, hp->h_name, sizeof(hname) - 1);
(void)strncpy(hname, res->ai_canonname,
sizeof(hname) - 1);
hname[sizeof(hname) - 1] = '\0';
}
freeaddrinfo(res);
/* get the official name of RM */
hp = gethostbyname(RM);
if (hp == (struct hostent *) NULL) {
(void)snprintf(errbuf, sizeof(errbuf),
"unable to get official name for remote machine %s",
RM);
return errbuf;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
error = getaddrinfo(RM, NULL, &hints, &res);
if (error) {
(void)snprintf(errbuf, sizeof(errbuf),
"unable to get official name for local machine %s: "
"%s", RM, gai_strerror(error));
return errbuf;
}
/*
* if the two hosts are not the same,
* then the printer must be remote.
*/
if (strcasecmp(hname, hp->h_name) != 0)
if (strcasecmp(hname, res->ai_canonname) != 0)
remote = 1;
freeaddrinfo(res);
}
return NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.7 1997/10/05 15:12:12 mrg Exp $ */
/* $NetBSD: extern.h,v 1.8 2000/01/27 05:39:50 itojun Exp $ */
/*
* Copyright (c) 1989, 1993
@ -64,4 +64,6 @@ void sttyclearlflags __P((struct termios *tp, int flags));
void sttysetlflags __P((struct termios *tp, int flags));
/* XXX from libc/net/rcmd.c */
int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
struct sockaddr;
int __ivaliduser_sa __P((FILE *, struct sockaddr *, const char *,
const char *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: lpd.c,v 1.19 1999/12/23 02:10:07 mjl Exp $ */
/* $NetBSD: lpd.c,v 1.20 2000/01/27 05:39:50 itojun Exp $ */
/*
* Copyright (c) 1983, 1993, 1994
@ -45,7 +45,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\
#if 0
static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
#else
__RCSID("$NetBSD: lpd.c,v 1.19 1999/12/23 02:10:07 mjl Exp $");
__RCSID("$NetBSD: lpd.c,v 1.20 2000/01/27 05:39:50 itojun Exp $");
#endif
#endif /* not lint */
@ -116,9 +116,10 @@ static void reapchild __P((int));
static void mcleanup __P((int));
static void doit __P((void));
static void startup __P((void));
static void chkhost __P((struct sockaddr_in *));
static void chkhost __P((struct sockaddr *));
static int ckqueue __P((char *));
static void usage __P((void));
static int *socksetup __P((int, int));
uid_t uid, euid;
int child_count;
@ -128,10 +129,10 @@ main(argc, argv)
int argc;
char **argv;
{
int f, funix, finet, options, fromlen;
int f, funix, *finet, options, fromlen;
fd_set defreadfds;
struct sockaddr_un un, fromunix;
struct sockaddr_in sin, frominet;
struct sockaddr_storage frominet;
int omask, lfd, errs, i;
int child_max = 32; /* more then enough to hose the system */
@ -242,31 +243,15 @@ main(argc, argv)
FD_SET(funix, &defreadfds);
listen(funix, 5);
if (!sflag)
finet = socket(AF_INET, SOCK_STREAM, 0);
finet = socksetup(PF_UNSPEC, options);
else
finet = -1; /* pretend we couldn't open TCP socket. */
if (finet >= 0) {
struct servent *sp;
finet = NULL; /* pretend we couldn't open TCP socket. */
if (options & SO_DEBUG)
if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
mcleanup(0);
}
sp = getservbyname("printer", "tcp");
if (sp == NULL) {
syslog(LOG_ERR, "printer/tcp: unknown service");
mcleanup(0);
if (finet) {
for (i = 1; i <= *finet; i++) {
FD_SET(finet[i], &defreadfds);
listen(finet[i], 5);
}
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);
}
/*
* Main loop: accept, do a request, continue.
@ -302,10 +287,12 @@ main(argc, argv)
domain = AF_LOCAL, fromlen = sizeof(fromunix);
s = accept(funix,
(struct sockaddr *)&fromunix, &fromlen);
} else /* if (FD_ISSET(finet, &readfds)) */ {
domain = AF_INET, fromlen = sizeof(frominet);
s = accept(finet,
(struct sockaddr *)&frominet, &fromlen);
} else {
for (i = 1; i <= *finet; i++)
if (FD_ISSET(finet[i], &readfds)) {
domain = AF_INET, fromlen = sizeof(frominet);
s = accept(finet[i], (struct sockaddr *)&frominet, &fromlen);
}
}
if (s < 0) {
if (errno != EINTR)
@ -321,13 +308,15 @@ main(argc, argv)
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
(void)close(funix);
if (!sflag)
(void)close(finet);
if (!sflag && finet)
for (i = 1; i <= *finet; i++)
(void)close(finet[i]);
dup2(s, 1);
(void)close(s);
if (domain == AF_INET) {
/* for both AF_INET and AF_INET6 */
from_remote = 1;
chkhost(&frominet);
chkhost((struct sockaddr *)&frominet);
} else
from_remote = 0;
doit();
@ -372,7 +361,7 @@ int requ[MAXREQUESTS]; /* job number of spool entries */
int requests; /* # of spool requests */
char *person; /* name of person doing lprm */
char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */
char fromb[NI_MAXHOST]; /* buffer for client's machine name */
char cbuf[BUFSIZ]; /* command line buffer */
char *cmdnames[] = {
"null",
@ -564,46 +553,67 @@ ckqueue(cap)
*/
static void
chkhost(f)
struct sockaddr_in *f;
struct sockaddr *f;
{
struct hostent *hp;
struct addrinfo hints, *res, *r;
FILE *hostf;
int first = 1, good = 0;
char host[NI_MAXHOST], ip[NI_MAXHOST];
char serv[NI_MAXSERV];
int error;
f->sin_port = ntohs(f->sin_port);
if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
NI_NUMERICSERV);
if (error || atoi(serv) >= IPPORT_RESERVED)
fatal("Malformed from address");
/* Need real hostname for temporary filenames */
hp = gethostbyaddr((char *)&f->sin_addr,
sizeof(struct in_addr), f->sin_family);
if (hp == NULL)
fatal("Host name for your address (%s) unknown",
inet_ntoa(f->sin_addr));
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
NI_NAMEREQD);
if (error) {
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
NI_NUMERICHOST);
if (error)
fatal("Host name for your address unknown");
else
fatal("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';
from = fromb;
/* need address in stringform for comparison (no DNS lookup here) */
error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
NI_NUMERICHOST);
if (error)
fatal("Cannot print address");
/* Check for spoof, ala rlogind */
hp = gethostbyname(fromb);
if (!hp)
fatal("hostname for your address (%s) unknown",
inet_ntoa(f->sin_addr));
for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
if (!memcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
sizeof(f->sin_addr)))
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
error = getaddrinfo(fromb, NULL, &hints, &res);
if (error) {
fatal("hostname for your address (%s) unknown: %s", host,
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);
if (!error && !strcmp(host, ip))
good = 1;
}
if (res)
freeaddrinfo(res);
if (good == 0)
fatal("address for your hostname (%s) not matched",
inet_ntoa(f->sin_addr));
fatal("address for your hostname (%s) not matched", host);
setproctitle("serving %s", from);
hostf = fopen(_PATH_HOSTSEQUIV, "r");
again:
if (hostf) {
if (__ivaliduser(hostf, f->sin_addr.s_addr,
DUMMY, DUMMY) == 0) {
if (__ivaliduser_sa(hostf, f, DUMMY, DUMMY) == 0) {
(void)fclose(hostf);
return;
}
@ -626,3 +636,68 @@ usage()
fprintf(stderr, "usage: %s [-d] [-l]\n", __progname);
exit(1);
}
/* 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 */
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, (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_DEBUG)
if (setsockopt(*s, SOL_SOCKET, SO_DEBUG,
&on, sizeof(on)) < 0) {
syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
close (*s);
continue;
}
if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
syslog(LOG_DEBUG, "bind(): %m");
close (*s);
continue;
}
*socks = *socks + 1;
s++;
}
if (res)
freeaddrinfo(res);
if (*socks == 0) {
syslog(LOG_ERR, "Couldn't bind to any socket");
free(socks);
mcleanup(0);
}
return(socks);
}