#include <sys/cdefs.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp.h>
#include <rpcsvc/yppasswd.h>
#include <rpcsvc/ypxfrd.h>
#include <sys/types.h>
#include <limits.h>
#include <db.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <paths.h>
#include <errno.h>
#include <sys/param.h>
#include "yp_extern.h"
#ifdef TCP_WRAPPER
#include "tcpd.h"
#endif
static const char *yp_procs[] = {
"ypoldproc_null",
"ypoldproc_domain",
"ypoldproc_domain_nonack",
"ypoldproc_match",
"ypoldproc_first",
"ypoldproc_next",
"ypoldproc_poll",
"ypoldproc_push",
"ypoldproc_get",
"badproc1",
"badproc2",
"badproc3",
"ypproc_null",
"ypproc_domain",
"ypproc_domain_nonack",
"ypproc_match",
"ypproc_first",
"ypproc_next",
"ypproc_xfr",
"ypproc_clear",
"ypproc_all",
"ypproc_master",
"ypproc_order",
"ypproc_maplist"
};
struct securenet {
struct in_addr net;
struct in_addr mask;
struct securenet *next;
};
static struct securenet *securenets;
#define LINEBUFSZ 1024
#ifdef TCP_WRAPPER
int hosts_ctl(char *, char *, char *, char *);
#endif
void
load_securenets(void)
{
FILE *fp;
char path[MAXPATHLEN + 2];
char linebuf[1024 + 2];
struct securenet *tmp;
while (securenets) {
tmp = securenets->next;
free(securenets);
securenets = tmp;
}
snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir);
if ((fp = fopen(path, "r")) == NULL) {
if (errno == ENOENT) {
securenets = malloc(sizeof(struct securenet));
securenets->net.s_addr = INADDR_ANY;
securenets->mask.s_addr = INADDR_ANY;
securenets->next = NULL;
return;
} else {
yp_error("fopen(%s) failed: %s", path, strerror(errno));
exit(1);
}
}
securenets = NULL;
while (fgets(linebuf, LINEBUFSZ, fp)) {
char addr1[20], addr2[20];
if ((linebuf[0] == '#')
|| (strspn(linebuf, " \t\r\n") == strlen(linebuf)))
continue;
if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) {
yp_error("badly formatted securenets entry: %s",
linebuf);
continue;
}
tmp = malloc(sizeof(struct securenet));
if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) {
yp_error("badly formatted securenets entry: %s", addr1);
free(tmp);
continue;
}
if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) {
yp_error("badly formatted securenets entry: %s", addr2);
free(tmp);
continue;
}
tmp->next = securenets;
securenets = tmp;
}
fclose(fp);
}
#ifdef DB_CACHE
int
yp_access(const char *map, const char *domain, const struct svc_req *rqstp)
#else
int
yp_access(const char *map, const struct svc_req *rqstp)
#endif
{
struct sockaddr_in *rqhost;
int status_securenets = 0;
#ifdef TCP_WRAPPER
int status_tcpwrap;
#endif
static unsigned long oldaddr = 0;
struct securenet *tmp;
const char *yp_procedure = NULL;
char procbuf[50];
if (rqstp->rq_prog != YPPASSWDPROG && rqstp->rq_prog != YPPROG) {
snprintf(procbuf, sizeof(procbuf), "#%lu/#%lu",
(unsigned long)rqstp->rq_prog,
(unsigned long)rqstp->rq_proc);
yp_procedure = (char *)&procbuf;
} else {
yp_procedure = rqstp->rq_prog == YPPASSWDPROG ?
"yppasswdprog_update" :
yp_procs[rqstp->rq_proc + (12 * (rqstp->rq_vers - 1))];
}
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug) {
yp_error("procedure %s called from %s:%d", yp_procedure,
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
if (map != NULL)
yp_error("client is referencing map \"%s\".", map);
}
if (map != NULL) {
if (strchr(map, '/')) {
yp_error("embedded slash in map name \"%s\" -- \
possible spoof attempt from %s:%d",
map, inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
return(1);
}
#ifdef DB_CACHE
if ((yp_testflag((char *)map, (char *)domain, YP_SECURE) ||
#else
if ((strstr(map, "master.passwd.") || strstr(map, "shadow.") ||
#endif
(rqstp->rq_prog == YPPROG &&
rqstp->rq_proc == YPPROC_XFR) ||
(rqstp->rq_prog == YPXFRD_FREEBSD_PROG &&
rqstp->rq_proc == YPXFRD_GETMAP)) &&
ntohs(rqhost->sin_port) >= IPPORT_RESERVED) {
yp_error("access to %s denied -- client %s:%d \
not privileged", map, inet_ntoa(rqhost->sin_addr), ntohs(rqhost->sin_port));
return(1);
}
}
#ifdef TCP_WRAPPER
status_tcpwrap = hosts_ctl("ypserv", STRING_UNKNOWN,
inet_ntoa(rqhost->sin_addr), "");
#endif
tmp = securenets;
while (tmp) {
if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr)
| tmp->net.s_addr) == rqhost->sin_addr.s_addr) {
status_securenets = 1;
break;
}
tmp = tmp->next;
}
#ifdef TCP_WRAPPER
if (status_securenets == 0 || status_tcpwrap == 0) {
#else
if (status_securenets == 0) {
#endif
if (rqhost->sin_addr.s_addr != oldaddr) {
yp_error("connect from %s:%d to procedure %s refused",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port),
yp_procedure);
oldaddr = rqhost->sin_addr.s_addr;
}
return(1);
}
return(0);
}
int
yp_validdomain(const char *domain)
{
struct stat statbuf;
char dompath[MAXPATHLEN + 2];
if (domain == NULL || strstr(domain, "binding") ||
!strcmp(domain, ".") || !strcmp(domain, "..") ||
strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN)
return(1);
snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain);
if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
return(1);
return(0);
}