freebsd-dev/gnu/usr.sbin/ypserv/server.c
1995-05-30 05:05:38 +00:00

1342 lines
27 KiB
C

/*
** server.c YP server routines.
**
** Copyright (c) 1993 Signum Support AB, Sweden
**
** This file is part of the NYS YP Server.
**
** The NYS YP Server is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
** published by the Free Software Foundation; either version 2 of the
** License, or (at your option) any later version.
**
** The NYS YP Server is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with the NYS YP Server; see the file COPYING. If
** not, write to the Free Software Foundation, Inc., 675 Mass Ave,
** Cambridge, MA 02139, USA.
**
** Author: Peter Eriksson <pen@signum.se>
** Ported to FreeBSD and hacked all to pieces
** by Bill Paul <wpaul@ctr.columbia.edu>
**
** $Id: server.c,v 1.5 1995/05/03 14:36:12 wpaul Exp $
**
*/
#include "system.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <limits.h>
#include <db.h>
#include <unistd.h>
#include <sys/stat.h>
#include <rpc/rpc.h>
#include "yp.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#define PERM_SECURE (S_IRUSR|S_IWUSR)
HASHINFO openinfo = {
4096, /* bsize */
32, /* ffactor */
256, /* nelem */
2048 * 1024, /* cachesize */
NULL, /* hash */
0, /* lorder */
};
#if TCP_WRAPPER
#include "tcpd.h"
int allow_severity=LOG_INFO;
int deny_severity=LOG_WARNING;
#endif
void verr __P((const char *, _BSD_VA_LIST_));
void Perror __P((const char *, ...));
extern char *dnsname();
extern char *dnsaddr();
extern char *_gethostbydnsaddr();
extern char *progname;
extern int errno;
int debug_flag = 0;
int dns_flag = 0;
void verr(fmt, ap)
const char *fmt;
_BSD_VA_LIST_ ap;
{
if (debug_flag)
vfprintf(stderr, fmt, ap);
else
vsyslog(LOG_NOTICE, fmt, ap);
}
void
#ifdef __STDC__
Perror(const char *fmt, ...)
#else
Perror(fmt, va_list)
const char *fmt;
va_dcl
#endif
{
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
verr(fmt,ap);
va_end(ap);
}
/*
** Return 1 if request comes from an authorized host
**
** XXX This function should implement the "securenets" functionality
*/
static int is_valid_host(struct sockaddr_in *sin)
{
#if TCP_WRAPPER
extern int hosts_ctl(char *, char *, char *, char *);
int status;
static long oldaddr=0; /* so we dont log multiple times */
static int oldstatus=-1;
char *h=NULL;
#ifdef TRYRESOLVE
struct hostent *hp;
hp = _gethostbydnsaddr((char *) &sin->sin_addr.s_addr,
sizeof (sin->sin_addr.s_addr), AF_INET);
h = (hp && hp->h_name) ? hp->h_name : NULL;
#endif
#ifndef FROM_UNKNOWN
#define FROM_UNKNOWN STRING_UNKNOWN
#endif
status = hosts_ctl(progname,
h?h:FROM_UNKNOWN,
inet_ntoa(sin->sin_addr),
"");
if (sin->sin_addr.s_addr != oldaddr || status != oldstatus ) {
syslog(status?allow_severity:deny_severity,
"%sconnect from %s\n",status?"":"refused ",
h?h:inet_ntoa(sin->sin_addr));
oldaddr=sin->sin_addr.s_addr;
oldstatus=status;
}
return status;
#else
return 1;
#endif
}
void *ypproc_null_2_svc(void *dummy,
struct svc_req *rqstp)
{
static int foo;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (!is_valid_host(rqhost))
return NULL;
if (debug_flag)
Perror("ypproc_null() [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
return (void *) &foo;
}
/*
** Return 1 if the name is a valid domain name served by us, else 0.
*/
static int is_valid_domain(const char *domain)
{
struct stat sbuf;
if (domain == NULL ||
strcmp(domain, "binding") == 0 ||
strcmp(domain, "..") == 0 ||
strcmp(domain, ".") == 0 ||
strchr(domain, '/'))
return 0;
if (stat(domain, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
return 0;
return 1;
}
bool_t *ypproc_domain_2_svc(domainname *name,
struct svc_req *rqstp)
{
static bool_t result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
Perror("ypproc_domain(\"%s\") [From: %s:%d]\n",
*name,
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
if (is_valid_domain(*name))
result = TRUE;
else
result = FALSE;
if (debug_flag)
Perror("\t-> %s.\n",
(result == TRUE ? "Ok" : "Not served by us"));
return &result;
}
bool_t *ypproc_domain_nonack_2_svc(domainname *name,
struct svc_req *rqstp)
{
static bool_t result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
Perror("ypproc_domain_nonack(\"%s\") [From: %s:%d]\n",
*name,
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
if (!is_valid_domain(*name))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid domain)\n");
/* Bail out and don't return any RPC value */
return NULL;
}
if (debug_flag)
Perror("\t-> OK.\n");
result = TRUE;
return &result;
}
/*
** Open a DB database
*/
static DB *open_database(const char *domain,
const char *map)
{
DB *dbp;
char buf[1025];
if (map[0] == '.' || strchr(map, '/'))
return 0;
strcpy(buf, domain);
strcat(buf, "/");
strcat(buf, map);
dbp = dbopen(buf,O_RDONLY|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
if (debug_flag > 1 && dbp == NULL)
Perror("dbopen(): ",strerror(errno));
return dbp;
}
#define F_ALL 0x01
#define F_NEXT 0x02
/*
** Get a record from a DB database.
** This looks ugly because it emulates the behavior of the original
** GDBM-based routines. Blech.
*/
int read_database(DB *dbp,
const DBT *ikey,
DBT *okey,
DBT *dval,
int flags)
{
int first_flag = 0;
DBT nkey, ckey, dummyval;
if (ikey == NULL || ikey->data == NULL)
{
(dbp->seq)(dbp,&ckey,&dummyval,R_FIRST);
first_flag = 1;
}
else
{
if ((flags & F_NEXT))
{
/*
** This crap would be unnecessary if R_CURSOR actually worked.
*/
(dbp->seq)(dbp,&ckey,&dummyval,R_FIRST);
while(strncmp((char *)ikey->data,ckey.data,(int)ikey->size) ||
ikey->size != ckey.size)
(dbp->seq)(dbp,&ckey,&dummyval,R_NEXT);
if ((dbp->seq)(dbp,&ckey,&dummyval,R_NEXT))
ckey.data = NULL;
free(dummyval.data);
}
else
ckey = *ikey;
}
if (ckey.data == NULL)
{
return (flags & F_NEXT) ? YP_NOMORE : YP_NOKEY;
}
while (1)
{
if ((dbp->get)(dbp,&ckey,dval,0))
{
/* Free key, unless it comes from the caller! */
if (ikey == NULL || ckey.data != ikey->data)
free(ckey.data);
if (ikey && ikey->data != NULL)
{
return YP_NOKEY;
}
else
if (first_flag)
return YP_BADDB;
else
return YP_FALSE;
}
if ((flags & F_ALL) || strncmp(ckey.data, "YP_", 3) != 0)
{
if (okey)
*okey = ckey;
else if (ikey == NULL || ikey->data != ckey.data)
free(ckey.data);
return YP_TRUE;
}
/* Free old value */
free(dval->data);
if ((dbp->seq)(dbp,&nkey,&dummyval,R_NEXT))
nkey.data = NULL;
free(dummyval.data);
/* Free old key, unless it comes from the caller! */
if (ikey == NULL || ckey.data != ikey->data)
free(ckey.data);
if (ckey.data == NULL || nkey.data == NULL)
return YP_NOMORE;
ckey = nkey;
}
}
/*
** Get the DateTimeModified value for a certain map database
*/
static unsigned long get_dtm(const char *domain,
const char *map)
{
struct stat sbuf;
char buf[1025];
strcpy(buf, domain);
strcat(buf, "/");
strcat(buf, map);
if (stat(buf, &sbuf) < 0)
return 0;
else
return (unsigned long) sbuf.st_mtime;
}
/*
** YP function "MATCH" implementation
*/
ypresp_val *ypproc_match_2_svc(ypreq_key *key,
struct svc_req *rqstp)
{
static ypresp_val result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_match(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\t\tdomainname = \"%s\"\n",
key->domain);
Perror("\t\tmapname = \"%s\"\n",
key->map);
Perror("\t\tkeydat = \"%.*s\"\n",
(int) key->key.keydat_len,
key->key.keydat_val);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(key->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.stat = YP_YPERR;
return &result;
}
result.val.valdat_len = 0;
if (result.val.valdat_val)
{
free(result.val.valdat_val);
result.val.valdat_val = NULL;
}
if (key->domain[0] == '\0' || key->map[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(key->domain))
result.stat = YP_NODOM;
else
{
DBT rdat, qdat;
DB *dbp = open_database(key->domain, key->map);
if (dbp == NULL)
result.stat = YP_NOMAP;
else
{
qdat.size = key->key.keydat_len;
qdat.data = key->key.keydat_val;
result.stat = read_database(dbp, &qdat, NULL, &rdat, F_ALL);
if (result.stat == YP_TRUE)
{
result.val.valdat_len = rdat.size;
result.val.valdat_val = rdat.data;
}
(void)(dbp->close)(dbp);
}
}
if (debug_flag)
{
if (result.stat == YP_TRUE)
Perror("\t-> Value = \"%.*s\"\n",
(int) result.val.valdat_len,
result.val.valdat_val);
else
Perror("\t-> Error #%d\n", result.stat);
}
/*
** Do the jive thing if we didn't find the host in the YP map
** and we have enabled the magic DNS lookup stuff.
**
** XXX Perhaps this should be done in a sub-process for performance
** reasons. Later.
*/
if (result.stat != YP_TRUE && strstr(key->map, "hosts") && dns_flag)
{
char *cp = NULL;
key->key.keydat_val[key->key.keydat_len] = '\0';
if (debug_flag)
Perror("Doing DNS lookup of %s\n", key->key.keydat_val);
if (strcmp(key->map, "hosts.byname") == 0)
cp = dnsname(key->key.keydat_val);
else if (strcmp(key->map, "hosts.byaddr") == 0)
cp = dnsaddr(key->key.keydat_val);
if (cp)
{
if (debug_flag)
Perror("\t-> OK (%s)\n", cp);
result.val.valdat_len = strlen(cp);
result.val.valdat_val = cp;
result.stat = YP_TRUE;
}
else
{
if (debug_flag)
{
Perror("\t-> Not Found\n");
Perror("DNS lookup: %s",strerror(errno));
}
result.stat = YP_NOKEY;
}
}
return &result;
}
ypresp_key_val *ypproc_first_2_svc(ypreq_nokey *key,
struct svc_req *rqstp)
{
static ypresp_key_val result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_first(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\tdomainname = \"%s\"\n", key->domain);
Perror("\tmapname = \"%s\"\n", key->map);
#if 0
Perror("\tkeydat = \"%.*s\"\n",
(int) key->key.keydat_len,
key->key.keydat_val);
#endif
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(key->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.stat = YP_YPERR;
return &result;
}
result.key.keydat_len = 0;
if (result.key.keydat_val)
{
free(result.key.keydat_val);
result.key.keydat_val = NULL;
}
result.val.valdat_len = 0;
if (result.val.valdat_val)
{
free(result.val.valdat_val);
result.val.valdat_val = NULL;
}
if (key->map[0] == '\0' || key->domain[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(key->domain))
result.stat = YP_NODOM;
else
{
DBT dkey, dval;
DB *dbp = open_database(key->domain, key->map);
if (dbp == NULL)
result.stat = YP_NOMAP;
else
{
result.stat = read_database(dbp, NULL, &dkey, &dval, 0);
if (result.stat == YP_TRUE)
{
result.key.keydat_len = dkey.size;
result.key.keydat_val = dkey.data;
result.val.valdat_len = dval.size;
result.val.valdat_val = dval.data;
}
(void)(dbp->close)(dbp);
}
}
if (debug_flag)
{
if (result.stat == YP_TRUE)
Perror("\t-> Key = \"%.*s\", Value = \"%.*s\"\n",
(int) result.key.keydat_len,
result.key.keydat_val,
(int) result.val.valdat_len,
result.val.valdat_val);
else
Perror("\t-> Error #%d\n", result.stat);
}
return &result;
}
ypresp_key_val *ypproc_next_2_svc(ypreq_key *key,
struct svc_req *rqstp)
{
static ypresp_key_val result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_next(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\tdomainname = \"%s\"\n", key->domain);
Perror("\tmapname = \"%s\"\n", key->map);
Perror("\tkeydat = \"%.*s\"\n",
(int) key->key.keydat_len,
key->key.keydat_val);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(key->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.stat = YP_YPERR;
return &result;
}
result.key.keydat_len = 0;
if (result.key.keydat_val)
{
free(result.key.keydat_val);
result.key.keydat_val = NULL;
}
result.val.valdat_len = 0;
if (result.val.valdat_val)
{
free(result.val.valdat_val);
result.val.valdat_val = NULL;
}
if (key->map[0] == '\0' || key->domain[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(key->domain))
result.stat = YP_NODOM;
else
{
DBT dkey, dval, okey;
DB *dbp = open_database(key->domain, key->map);
if (dbp == NULL)
result.stat = YP_NOMAP;
else
{
dkey.size = key->key.keydat_len;
dkey.data = key->key.keydat_val;
result.stat = read_database(dbp, &dkey, &okey, &dval, F_NEXT);
if (result.stat == YP_TRUE)
{
result.key.keydat_len = okey.size;
result.key.keydat_val = okey.data;
result.val.valdat_len = dval.size;
result.val.valdat_val = dval.data;
}
(void)(dbp->close)(dbp);
}
}
if (debug_flag)
{
if (result.stat == YP_TRUE)
Perror("\t-> Key = \"%.*s\", Value = \"%.*s\"\n",
(int) result.key.keydat_len,
result.key.keydat_val,
(int) result.val.valdat_len,
result.val.valdat_val);
else
Perror("\t-> Error #%d\n", result.stat);
}
return &result;
}
static void print_ypmap_parms(const struct ypmap_parms *pp)
{
Perror("\t\tdomain = \"%s\"\n", pp->domain);
Perror("\t\tmap = \"%s\"\n", pp->map);
Perror("\t\tordernum = %u\n", pp->ordernum);
Perror("\t\tpeer = \"%s\"\n", pp->peer);
}
/*
** Clean up after ypxfr child processes signal their termination.
*/
void reapchild(sig)
int sig;
{
int st;
wait3(&st, WNOHANG, NULL);
}
/*
** Stole the ypxfr implementation from the yps package.
*/
ypresp_xfr *ypproc_xfr_2_svc(ypreq_xfr *xfr,
struct svc_req *rqstp)
{
static ypresp_xfr result;
struct sockaddr_in *rqhost;
char ypxfr_command[MAXPATHLEN];
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_xfr_2_svc(): [From: %s:%d]\n\tmap_parms:\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
print_ypmap_parms(&xfr->map_parms);
Perror("\t\ttransid = %u\n", xfr->transid);
Perror("\t\tprog = %u\n", xfr->prog);
Perror("\t\tport = %u\n", xfr->port);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request originates on a non-privileged port (< 1024),
** refuse it. We really only need to guard the master.passwd.*
** maps, but what the hell.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (ntohs(rqhost->sin_port) > 1023)
{
result.xfrstat = YPXFR_REFUSED;
return &result;
}
switch(fork())
{
case 0:
{
char g[11], t[11], p[11];
sprintf (ypxfr_command, "%s/ypxfr", INSTDIR);
sprintf (t, "%u", xfr->transid);
sprintf (g, "%u", xfr->prog);
sprintf (p, "%u", xfr->port);
execl(ypxfr_command, "ypxfr", "-d", xfr->map_parms.domain, "-h",
xfr->map_parms.peer, "-f", "-C", t, g,
inet_ntoa(rqhost->sin_addr), p, xfr->map_parms.map, NULL);
Perror("ypxfr execl(): %s",strerror(errno));
exit(0);
}
case -1:
Perror("fork(): %s",strerror(errno));
result.xfrstat = YPXFR_XFRERR;
default:
{
signal(SIGCHLD, reapchild);
result.xfrstat = YPXFR_SUCC;
break;
}
}
result.transid = xfr->transid;
return &result;
}
void *ypproc_clear_2_svc(void *dummy,
struct svc_req *rqstp)
{
static int foo;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
Perror("ypproc_clear_2_svc() [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
return (void *) &foo;
}
static int ypall_close(void *data)
{
DB *locptr;
if (debug_flag && data == NULL)
{
Perror("ypall_close() called with NULL pointer.\n");
return 0;
}
locptr = (DB *)data;
(void)(locptr->close)(locptr);
return 0;
}
static int ypall_encode(ypresp_key_val *val,
void *data)
{
DBT dkey, dval, okey;
dkey.data = val->key.keydat_val;
dkey.size = val->key.keydat_len;
val->stat = read_database((DB *) data, &dkey, &okey, &dval, F_NEXT);
if (val->stat == YP_TRUE)
{
val->key.keydat_val = okey.data;
val->key.keydat_len = okey.size;
val->val.valdat_val = dval.data;
val->val.valdat_len = dval.size;
}
return val->stat;
}
ypresp_all *ypproc_all_2_svc(ypreq_nokey *nokey,
struct svc_req *rqstp)
{
static ypresp_all result;
extern __xdr_ypall_cb_t __xdr_ypall_cb;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_all_2_svc(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\t\tdomain = \"%s\"\n", nokey->domain);
Perror("\t\tmap = \"%s\"\n", nokey->map);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
__xdr_ypall_cb.u.encode = NULL;
__xdr_ypall_cb.u.close = NULL;
__xdr_ypall_cb.data = NULL;
result.more = TRUE;
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(nokey->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.ypresp_all_u.val.stat = YP_YPERR;
return &result;
}
if (nokey->map[0] == '\0' || nokey->domain[0] == '\0')
result.ypresp_all_u.val.stat = YP_BADARGS;
else if (!is_valid_domain(nokey->domain))
result.ypresp_all_u.val.stat = YP_NODOM;
else
{
DBT dkey, dval;
DB *dbp = open_database(nokey->domain, nokey->map);
if (dbp == NULL)
result.ypresp_all_u.val.stat = YP_NOMAP;
else
{
result.ypresp_all_u.val.stat = read_database(dbp,
NULL,
&dkey,
&dval,
0);
if (result.ypresp_all_u.val.stat == YP_TRUE)
{
result.ypresp_all_u.val.key.keydat_len = dkey.size;
result.ypresp_all_u.val.key.keydat_val = dkey.data;
result.ypresp_all_u.val.val.valdat_len = dval.size;
result.ypresp_all_u.val.val.valdat_val = dval.data;
__xdr_ypall_cb.u.encode = ypall_encode;
__xdr_ypall_cb.u.close = ypall_close;
__xdr_ypall_cb.data = (void *) dbp;
return &result;
}
(void)(dbp->close)(dbp);
}
}
return &result;
}
ypresp_master *ypproc_master_2_svc(ypreq_nokey *nokey,
struct svc_req *rqstp)
{
static ypresp_master result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_master_2_svc(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\t\tdomain = \"%s\"\n", nokey->domain);
Perror("\t\tmap = \"%s\"\n", nokey->map);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(nokey->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.stat = YP_YPERR;
return &result;
}
if (result.peer)
{
free(result.peer);
result.peer = NULL;
}
if (nokey->domain[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(nokey->domain))
result.stat = YP_NODOM;
else
{
DB *dbp = open_database(nokey->domain, nokey->map);
if (dbp == NULL)
result.stat = YP_NOMAP;
else
{
DBT key, val;
key.size = sizeof("YP_MASTER_NAME")-1;
key.data = "YP_MASTER_NAME";
if ((dbp->get)(dbp,&key,&val,0))
val.data = NULL;
if (val.data == NULL)
{
/* No YP_MASTER_NAME record in map? Assume we are Master */
static char hostbuf[1025];
gethostname((char *)&hostbuf, sizeof(hostbuf)-1);
Perror("Hostname: [%s]",hostbuf);
result.peer = strdup(hostbuf);
}
else
{
*(((char *)val.data)+val.size) = '\0';
result.peer = val.data;
}
result.stat = YP_TRUE;
(void)(dbp->close)(dbp);
}
}
if (result.peer == NULL)
result.peer = strdup("");
if (debug_flag)
Perror("\t-> Peer = \"%s\"\n", result.peer);
return &result;
}
ypresp_order *ypproc_order_2_svc(ypreq_nokey *nokey,
struct svc_req *rqstp)
{
static ypresp_order result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_order_2_svc(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\t\tdomain = \"%s\"\n", nokey->domain);
Perror("\t\tmap = \"%s\"\n", nokey->map);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
/*
** If this request deals with master.passwd.* and it didn't
** originate on a privileged port (< 1024), return a YP_YPERR.
** This is our half-assed way of preventing non-root users
** on NIS clients from getting at the real password map. Bah.
*/
if (strstr(nokey->map, "master.passwd") != NULL &&
ntohs(rqhost->sin_port) > 1023)
{
result.stat = YP_YPERR;
return &result;
}
result.ordernum = 0;
if (nokey->domain[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(nokey->domain))
result.stat = YP_NODOM;
else
{
DB *dbp = open_database(nokey->domain, nokey->map);
if (dbp == NULL)
result.stat = YP_NOMAP;
else
{
DBT key, val;
key.size = sizeof("YP_LAST_MODIFIED")-1;
key.data = "YP_LAST_MODIFIED";
(dbp->get)(dbp,&key,&val,0);
if (val.data == NULL)
{
/* No YP_LAST_MODIFIED record in map? Use DTM timestamp.. */
result.ordernum = get_dtm(nokey->domain, nokey->map);
}
else
{
result.ordernum = atoi(val.data);
free(val.data);
}
result.stat = YP_TRUE;
(void)(dbp->close)(dbp);
}
}
if (debug_flag)
Perror("-> Order # %d\n", result.ordernum);
return &result;
}
static void free_maplist(ypmaplist *mlp)
{
ypmaplist *next;
while (mlp != NULL)
{
next = mlp->next;
free(mlp->map);
free(mlp);
mlp = next;
}
}
static int add_maplist(ypmaplist **mlhp,
char *map)
{
ypmaplist *mlp;
if (!strncmp(map, ".", strlen(map)) || !strncmp(map, "..", strlen(map)))
return 0;
mlp = malloc(sizeof(*mlp));
if (mlp == NULL)
return -1;
mlp->map = strdup(map);
if (mlp->map == NULL)
{
free(mlp);
return -1;
}
mlp->next = *mlhp;
*mlhp = mlp;
return 0;
}
ypresp_maplist *ypproc_maplist_2_svc(domainname *name,
struct svc_req *rqstp)
{
static ypresp_maplist result;
struct sockaddr_in *rqhost;
rqhost = svc_getcaller(rqstp->rq_xprt);
if (debug_flag)
{
Perror("ypproc_maplist_2_svc(): [From: %s:%d]\n",
inet_ntoa(rqhost->sin_addr),
ntohs(rqhost->sin_port));
Perror("\t\tdomain = \"%s\"\n", *name);
}
if (!is_valid_host(rqhost))
{
if (debug_flag)
Perror("\t-> Ignored (not a valid source host)\n");
return NULL;
}
if (result.maps)
free_maplist(result.maps);
result.maps = NULL;
if ((*name)[0] == '\0')
result.stat = YP_BADARGS;
else if (!is_valid_domain(*name))
result.stat = YP_NODOM;
else
{
DIR *dp;
char dirname[MAXPATHLEN];
sprintf(dirname,"./%s",*name);
dp = opendir(dirname);
if (dp == NULL)
{
if (debug_flag)
{
Perror("%s: opendir: %s", progname,strerror(errno));
}
result.stat = YP_BADDB;
}
else
{
struct dirent *dep;
while ((dep = readdir(dp)) != NULL)
if (add_maplist(&result.maps, dep->d_name) < 0)
{
result.stat = YP_YPERR;
break;
}
closedir(dp);
result.stat = YP_TRUE;
}
}
if (debug_flag)
{
if (result.stat == YP_TRUE)
{
ypmaplist *p;
p = result.maps;
Perror("-> ");
while (p->next)
{
Perror("%s,", p->map);
p = p->next;
}
putc('\n', stderr);
}
else
Perror("\t-> Error #%d\n", result.stat);
}
return &result;
}