/* * 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 #include #include #include #include #include #include #include #include #include #include #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); } } }