ypxfrd_server.c revision c458f227b16aaf458bd67c4e8b9510d6be09f668
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Portions Copyright 2005 Juergen Keil */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ndbm.h>
#include <rpc/rpc.h>
#include <rpc/svc.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <syslog.h>
#include "ypxfrd.h"
#include "ypsym.h"
#include "ypdefs.h"
/*
* Because this code hacks into DBM underneath its API it can't use the N2L
* shim in it's normal way. It thus includes shim.h instead of shim_hooks.h
* and has knowledge of shim internals. While copying the DBM files it does
* not lock them. This reflects the behavior of the pre N2L code.
*/
#include "shim.h"
#include "yptol.h"
#if (defined(vax) || defined(i386))
#define DOSWAB 1
#endif
USE_YP_SECURE
/* per connection stuff */
struct mycon {
map_ctrl *map;
int lblk;
int firstd;
datum key;
};
bool_t xdr_myfyl(XDR *xdrs, struct mycon *objp);
bool_t xdr_pages(XDR *xdrs, struct mycon *m);
bool_t xdr_dirs(XDR *xdrs, struct mycon *m);
int mygetdir(char *block, int *no, struct mycon *m);
int mygetpage(char *block, int *pageno, struct mycon *m);
datum mydbm_topkey(DBM *db, datum okey);
datum dbm_do_nextkey();
datum shim_dbm_do_nextkey();
extern void get_secure_nets(char *);
extern int check_secure_net_ti(struct netbuf *, char *);
extern int _main(int, char **);
int
main(int argc, char **argv)
{
int connmaxrec = RPC_MAXDATASIZE;
/* load up the securenet file */
get_secure_nets(argv[0]);
/*
* Set non-blocking mode and maximum record size for
* connection oriented RPC transports.
*/
if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
syslog(LOG_INFO|LOG_DAEMON,
"unable to set maximum RPC record size");
}
/* Initialize file locking etc. */
if (!init_lock_system(TRUE))
/* An detailed error will already have been logged */
exit(-1);
return (_main(argc, argv));
}
/*
* In yptol mode we may start a cache update thread within a child process.
* It is thus important that child processes do not exit, killing any such
* threads, before the thread has completed. They must thus call this version
* of the exit() function.
*/
void
yptol_exit(int status)
{
if (yptol_mode) {
thr_join(0, NULL, NULL);
}
exit(status);
}
dbmfyl *
getdbm_1_svc(hosereq *argp, struct svc_req *rqstp)
{
static dbmfyl result;
char path[MAXNAMLEN + 1];
SVCXPRT *xprt;
int pid;
int res;
struct mycon m;
char *ypname = "ypxfrd";
struct netbuf *nbuf;
sa_family_t af;
in_port_t port;
xprt = rqstp->rq_xprt;
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
/*
* Build up path name. If we are working in N2L mode also conv
* to the new N2L style mapname.
*
* Do not allow any path as a domain name or map name.
*/
if ((strchr(argp->domain, '/') != NULL) ||
(strchr(argp->map, '/') != NULL) ||
(!ypmkfilename(argp->domain, argp->map, (char *)&path))) {
res = GETDBM_ERROR;
if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
(caddr_t)&res)) {
svcerr_systemerr(rqstp->rq_xprt);
}
return (NULL);
}
pid = fork1();
if (pid < 0) {
perror("fork");
res = GETDBM_ERROR;
if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
(caddr_t)&res)) {
svcerr_systemerr(rqstp->rq_xprt);
}
return (NULL);
}
if (pid != 0)
return (NULL);
m.map = (map_ctrl *)shim_dbm_open(path, 0, 0);
if (m.map == NULL) {
perror(path);
res = GETDBM_ERROR;
if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
(caddr_t)&res)) {
svcerr_systemerr(rqstp->rq_xprt);
}
yptol_exit(0);
return (NULL);
}
/* Do the security thing */
if ((nbuf = svc_getrpccaller(xprt)) == 0) {
res = GETDBM_ERROR;
if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
svcerr_systemerr(xprt);
}
shim_dbm_close((DBM *)m.map);
yptol_exit(0);
return (NULL);
}
if (!check_secure_net_ti(nbuf, ypname)) {
res = GETDBM_ERROR;
if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
svcerr_systemerr(xprt);
}
shim_dbm_close((DBM *)m.map);
yptol_exit(1);
return (NULL);
}
af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
port = (af == AF_INET6) ?
((struct sockaddr_in6 *)nbuf->buf)->sin6_port :
((struct sockaddr_in *)nbuf->buf)->sin_port;
if ((af == AF_INET || af == AF_INET6) &&
(ntohs(port) > IPPORT_RESERVED)) {
datum key, val;
key.dptr = yp_secure;
key.dsize = yp_secure_sz;
val = shim_dbm_fetch((DBM *)m.map, key);
if (val.dptr != NULL) {
res = GETDBM_ERROR;
if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
svcerr_systemerr(xprt);
}
shim_dbm_close((DBM *)m.map);
yptol_exit(1);
return (NULL);
}
}
/* OK, we're through */
m.key = shim_dbm_firstkey((DBM *)m.map);
m.lblk = -1;
m.firstd = 0;
if (!svc_sendreply(rqstp->rq_xprt, xdr_myfyl, (caddr_t)&m)) {
svcerr_systemerr(rqstp->rq_xprt);
}
shim_dbm_close((DBM *)m.map);
yptol_exit(0);
return (&result);
}
bool_t
xdr_myfyl(XDR *xdrs, struct mycon *objp)
{
int ans = OK;
if (!xdr_answer(xdrs, (answer *) &ans))
return (FALSE);
if (!xdr_pages(xdrs, objp))
return (FALSE);
if (!xdr_dirs(xdrs, objp))
return (FALSE);
return (TRUE);
}
bool_t
xdr_pages(XDR *xdrs, struct mycon *m)
{
static struct pag res;
bool_t false = FALSE;
bool_t true = TRUE;
#ifdef DOSWAB
short *s;
int i;
int cnt;
#endif
res.status = mygetpage(res.pag_u.ok.blkdat, &(res.pag_u.ok.blkno), m);
#ifdef DOSWAB
if (res.status == OK) {
s = (short *)res.pag_u.ok.blkdat;
cnt = s[0];
for (i = 0; i <= cnt; i++)
s[i] = ntohs(s[i]);
}
#endif
if (!xdr_pag(xdrs, &res))
return (FALSE);
while (res.status == OK) {
if (!xdr_bool(xdrs, &true))
return (FALSE);
res.status = mygetpage(res.pag_u.ok.blkdat,
&(res.pag_u.ok.blkno), m);
#ifdef DOSWAB
if (res.status == OK) {
s = (short *)res.pag_u.ok.blkdat;
cnt = s[0];
for (i = 0; i <= cnt; i++)
s[i] = ntohs(s[i]);
}
#endif
if (!xdr_pag(xdrs, &res))
return (FALSE);
}
return (xdr_bool(xdrs, &false));
}
int
mygetdir(char *block, int *no, struct mycon *m)
{
int status;
int len;
if (m->firstd == 0) {
lseek(m->map->entries->dbm_dirf, 0, 0);
m->firstd = 1;
} else
m->firstd++;
len = read(m->map->entries->dbm_dirf, block, DBLKSIZ);
*no = (m->firstd) - 1;
status = OK;
/*
* printf("dir block %d\n", (m->firstd) - 1);
*/
if (len < 0) {
perror("read directory");
status = GETDBM_ERROR;
} else if (len == 0) {
status = GETDBM_EOF;
/*
* printf("dir EOF\n");
*/
}
return (status);
}
bool_t
xdr_dirs(XDR *xdrs, struct mycon *m)
{
static struct dir res;
bool_t false = FALSE;
bool_t true = TRUE;
res.status = mygetdir(res.dir_u.ok.blkdat, &(res.dir_u.ok.blkno), m);
if (!xdr_dir(xdrs, &res))
return (FALSE);
while (res.status == OK) {
if (!xdr_bool(xdrs, &true))
return (FALSE);
res.status = mygetdir(res.dir_u.ok.blkdat,
&(res.dir_u.ok.blkno), m);
if (!xdr_dir(xdrs, &res))
return (FALSE);
}
return (xdr_bool(xdrs, &false));
}
int
mygetpage(char *block, int *pageno, struct mycon *m)
{
for (; m->key.dptr;
m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key)) {
if (m->map->entries->dbm_pagbno != m->lblk) {
/*
* printf("block=%d lblk=%d\n",
* m->map->entries->dbm_pagbno,
* m->lblk);
*/
m->lblk = m->map->entries->dbm_pagbno;
*pageno = m->lblk;
memmove(block, m->map->entries->dbm_pagbuf, PBLKSIZ);
/* advance key on first try */
m->key = mydbm_topkey(m->map->entries, m->key);
m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key);
return (OK);
}
}
/*
* printf("EOF\n");
*/
return (GETDBM_EOF);
}
datum
mydbm_topkey(DBM *db, datum okey)
{
datum ans;
datum tmp;
register char *buf;
int n;
register short *sp;
register t;
datum item;
register m;
register char *p1, *p2;
buf = db->dbm_pagbuf;
sp = (short *)buf;
/* find the maximum key in cmpdatum order */
if ((unsigned)0 >= sp[0]) {
return (okey);
} else {
ans.dptr = buf + sp[1];
ans.dsize = PBLKSIZ - sp[1];
}
for (n = 2; ; n += 2) {
if ((unsigned)n >= sp[0]) {
if (ans.dptr == NULL) {
return (okey);
} else {
return (ans);
}
} else {
t = PBLKSIZ;
if (n > 0)
t = sp[n];
tmp.dptr = buf + sp[n + 1];
tmp.dsize = t - sp[n + 1];
}
m = tmp.dsize;
if (m != ans.dsize) {
if ((m - ans.dsize) < 0)
ans = tmp;
} else if (m == 0) {
} else {
p1 = tmp.dptr;
p2 = ans.dptr;
do
if (*p1++ != *p2++) {
if ((*--p1 - *--p2) < 0)
ans = tmp;
break;
}
while (--m);
}
}
}