/*
*
* yp.c
*
* YP call responses and related functions
*
* Author: Landon Fuller <landonf@go2net.com>
*
* Copyright (c) 2000-2001 InfoSpace, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by InfoSpace, Inc.
* and its contributors.
* 4. Neither the name of InfoSpace, Inc nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../autoconf.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <lber.h>
#include <ldap.h>
#include "yp.h"
#include "../include/config.h"
#include "../include/transit.h"
#include "../include/access.h"
#include "../include/servconf.h"
#include "../include/log.h"
#include "../include/util.h"
#include "../include/modules.h"
#include "../include/yp.h"
int children = 0;
/*
* NIS v2 Support
*/
ypstat yp_select_map(const char *map, const char *domain)
{
struct ypmaplist *current = prefs.yp_maplist;
if(yp_validdomain(domain))
{
return (YP_NODOM);
}
while(current)
{
if(!strcmp(current->map, map))
{
return (YP_TRUE);
}
current = current->next;
}
return (YP_NOMAP);
}
void * ypproc_null_2_svc (void *dummy, struct svc_req *rqstp)
{
static bool_t result;
if (yp_access(NULL, (struct svc_req *) rqstp))
return (NULL);
result = YP_TRUE;
return (&result);
}
bool_t * ypproc_domain_2_svc (domainname *domain, struct svc_req *rqstp)
{
static bool_t result;
if (yp_access(NULL, (struct svc_req *) rqstp))
return (NULL);
if(*domain == NULL || yp_validdomain(*domain))
result = YP_FALSE;
else
result = YP_TRUE;
return (&result);
}
bool_t * ypproc_domain_nonack_2_svc (domainname *domain, struct svc_req *rqstp)
{
static bool_t result;
if (yp_access(NULL, (struct svc_req *) rqstp))
return (NULL);
if(*domain == NULL || yp_validdomain(*domain))
result = YP_FALSE;
else
result = YP_TRUE;
return (&result);
}
ypresp_val * ypproc_match_2_svc (ypreq_key *key, struct svc_req *rqstp)
{
static ypresp_val result;
struct ypmoduledata *moduledata;
if(result.val.valdat_len != 0)
{
free(result.val.valdat_val);
result.val.valdat_len = 0;
}
if (yp_access(key->map, (struct svc_req *) rqstp))
{
result.stat = YP_YPERR;
return (&result);
}
if (key->domain == NULL || key->map == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
if ((result.stat = yp_select_map(key->map, key->domain)) != YP_TRUE)
{
return (&result);
}
moduledata = yp_get_module((char *) key->map);
if(!moduledata)
{
warn("No module for map: %s\n", key->map);
result.stat = YP_YPERR;
return (&result);
}
result.stat = moduledata->yp_getbykey(&key->key, (mapname *) key->map, &result.val);
return (&result);
}
#ifdef FREEBSD
ypresp_key_val * ypproc_first_2_svc (ypreq_nokey *nokey, struct svc_req *rqstp)
#else
ypresp_key_val * ypproc_first_2_svc (ypreq_key *nokey, struct svc_req *rqstp)
#endif
{
static ypresp_key_val result;
struct ypmoduledata *moduledata;
if(result.val.valdat_len != 0)
{
free(result.val.valdat_val);
result.val.valdat_len = 0;
}
if(result.key.keydat_len != 0)
{
free(result.key.keydat_val);
result.key.keydat_len = 0;
}
if (yp_access(nokey->map, (struct svc_req *) rqstp))
{
result.stat = YP_YPERR;
return (&result);
}
if (nokey->domain == NULL || nokey->map == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
if ((result.stat = yp_select_map(nokey->map, nokey->domain)) != YP_TRUE)
{
return (&result);
}
moduledata = yp_get_module((char *) nokey->map);
if(!moduledata)
{
warn("No module for map: %s\n", nokey->map);
result.stat = YP_YPERR;
return (&result);
}
result.stat = moduledata->yp_firstbykey(&result.key, (mapname *) nokey->map, &result.val);
return (&result);
}
ypresp_key_val * ypproc_next_2_svc (ypreq_key *key, struct svc_req *rqstp)
{
static ypresp_key_val result;
struct ypmoduledata *moduledata;
if(result.val.valdat_len != 0)
{
free(result.val.valdat_val);
result.val.valdat_len = 0;
}
if(result.key.keydat_len != 0)
{
free(result.key.keydat_val);
result.key.keydat_len = 0;
}
if (yp_access(key->map, (struct svc_req *) rqstp))
{
result.stat = YP_YPERR;
return (&result);
}
if (key->domain == NULL || key->map == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
if ((result.stat = yp_select_map(key->map, key->domain)) != YP_TRUE)
{
return (&result);
}
moduledata = yp_get_module((char *) key->map);
if(!moduledata)
{
warn("No module for map: %s\n", key->map);
result.stat = YP_YPERR;
return (&result);
}
result.key.keydat_val = key->key.keydat_val;
result.key.keydat_len = key->key.keydat_len;
/*
* XXX Remember - result.key.keydat_len must be set to zero if you do not replace
* result.key.keydat_val with your own malloc'd string!
*/
result.stat = moduledata->yp_nextbykey(&result.key, (mapname *) key->map, &result.val);
return(&result);
}
ypresp_xfr * ypproc_xfr_2_svc (ypreq_xfr *xfr, struct svc_req *rqstp)
{
static ypresp_xfr result;
error("ypproc_xfr_2\n");
result.transid = xfr->transid;
if (yp_access(xfr->map_parms.map, (struct svc_req *) rqstp))
return (NULL);
if (yp_access(xfr->map_parms.map, (struct svc_req *) rqstp))
{
result.xfrstat = YP_YPERR;
return (&result);
}
if (xfr->map_parms.domain == NULL || xfr->map_parms.map == NULL)
{
result.xfrstat = YP_BADARGS;
return (&result);
}
if ((result.xfrstat = yp_select_map(xfr->map_parms.domain, xfr->map_parms.map)) != YP_TRUE)
{
return (&result);
}
/* We don't support ypxfrs yet.
* In Bill Paul's BSD ypserv, he does a svc_sendreply, then has a ypxfr_callback
* routine. His reasoning for this follows:
* Add a ypxfr_callback() function that we can use to signal failure to
* yppush(8) in the event that we can't fork()/exec() ypxfr(8). yppush
* only checks the return status from YPPROC_XFR enough to determine
* that the RPC succeded: it relies on its callback service to figure
* out whether or not the transfer actually worked.
* (from CVS comments of Revision 1.3 of ypserv)
*
* I include this so that I do not forget this important bit of information.
*/
result.transid = xfr->transid;
result.xfrstat = YPXFR_REFUSED;
return (&result);
}
void * ypproc_clear_2_svc (void *dummy, struct svc_req *rqstp)
{
static bool_t result = 0;
struct ypmodulelist *module = prefs.yp_modulelist;
if (yp_access(NULL, (struct svc_req *) rqstp))
return (NULL);
while (module)
{
module->yp_moduledata->yp_clear();
module = module->next;
}
return (&result);
}
/*
* Custom XDR routine for serializing results of ypproc_all: keep
* reading from the data source and spew until we run out of records
* or encounter an error. Idea borrowed from Bill Paul's BSD ypserv.
*/
static bool_t xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *result)
{
struct ypmoduledata *moduledata;
mapname *map;
/* XXX We use the result stat pointer to hold a pointer to module data. Evil hack */
/* XXX We also use the valdat structure to hold the map name. Also an evil hack */
moduledata = (struct ypmoduledata *) result->ypresp_all_u.val.key.keydat_val;
map = (mapname *) result->ypresp_all_u.val.val.valdat_val;
while (1)
{
/* Get a record */
if((result->ypresp_all_u.val.stat = moduledata->yp_nextbykey(&result->ypresp_all_u.val.key, map, &result->ypresp_all_u.val.val)) == YP_TRUE)
{
result->more = TRUE;
} else {
result->more = FALSE;
}
/* Serialize */
if (!xdr_ypresp_all(xdrs, result))
return (FALSE);
if (result->more == FALSE)
return (TRUE);
}
}
ypresp_all * ypproc_all_2_svc (ypreq_nokey *nokey, struct svc_req *rqstp)
{
static ypresp_all result;
struct ypmoduledata *moduledata;
result.more = TRUE;
result.ypresp_all_u.val.key.keydat_len = 0;
result.ypresp_all_u.val.key.keydat_val = "";
if (yp_access(nokey->map, (struct svc_req *) rqstp))
{
result.ypresp_all_u.val.stat = YP_YPERR;
return (&result);
}
if (nokey->domain == NULL || nokey->map == NULL)
{
result.ypresp_all_u.val.stat = YP_BADARGS;
return (&result);
}
if ((result.ypresp_all_u.val.stat = yp_select_map(nokey->map, nokey->domain)) != YP_TRUE)
{
return (&result);
}
moduledata = yp_get_module((char *) nokey->map);
if(!moduledata)
{
warn("No module for map: %s\n", nokey->map);
result.ypresp_all_u.val.stat = YP_YPERR;
return (&result);
}
if (children >= MAX_CHILDREN)
{
result.ypresp_all_u.val.stat = YP_YPERR;
return (&result);
}
switch(fork())
{
case 0:
break;
case -1:
error("ypproc_all fork(): %s", strerror(errno));
result.ypresp_all_u.val.stat = YP_YPERR;
return (&result);
break;
default:
children++;
return (NULL);
break;
}
/* XXX
* Feed the moduledata struct in via result.ypresp_all_u.val.key.keydat_val
* Feed the map name in via result.ypresp_all_u.val.val.valdal_val
* This is an evil hack */
result.ypresp_all_u.val.key.keydat_val = (char *) moduledata;
result.ypresp_all_u.val.val.valdat_val = (char *) nokey->map;
svc_sendreply(rqstp->rq_xprt, (xdrproc_t) xdr_my_ypresp_all, (char *)&result);
_exit(0);
}
ypresp_master * ypproc_master_2_svc (ypreq_nokey *nokey, struct svc_req *rqstp)
{
static ypresp_master result;
if (yp_access(nokey->map, (struct svc_req *) rqstp))
return (NULL);
/* Return the prefs.master as master. */
if (nokey->domain == NULL || nokey->map == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
result.peer = prefs.master;
result.stat = YP_TRUE;
return (&result);
}
ypresp_order * ypproc_order_2_svc (ypreq_nokey *nokey, struct svc_req *rqstp)
{
static ypresp_order result;
if (yp_access(nokey->map, (struct svc_req *) rqstp))
return (NULL);
if(nokey->domain == NULL || nokey->map == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
/* we always return that NIS is updated. How are we to tell (yet)
* In the future, we'll be able to tell. And get smarter. */
result.ordernum = time(NULL);
result.stat = YP_TRUE;
return (&result);
}
void yp_maplist_free (ypmaplist *yp_maplist)
{
register ypmaplist *next;
while(yp_maplist)
{
next = yp_maplist->next;
free (yp_maplist->map);
free (yp_maplist);
yp_maplist = next;
}
return;
}
struct ypmaplist *yp_maplist_create(char *mapstrings)
{
char *cp;
struct ypmaplist *current = NULL;
struct ypmaplist *head = NULL;
cp = strtok((char *) mapstrings, WHITESPACE);
if(!*cp)
return(NULL);
while(cp)
{
current = safe_malloc(sizeof(struct ypmaplist));
current->map = safe_strdup(cp);
current->next = head;
head = current;
cp = strtok(NULL, WHITESPACE);
}
return (head);
}
ypresp_maplist * ypproc_maplist_2_svc (domainname *domain, struct svc_req *rqstp)
{
static ypresp_maplist result = {0, NULL};
if (yp_access(NULL, (struct svc_req *) rqstp))
return (NULL);
if (domain == NULL)
{
result.stat = YP_BADARGS;
return (&result);
}
if (yp_validdomain(*domain))
{
result.stat = YP_NODOM;
return (&result);
}
/* Return the yp_maplist generated by servconf.c */
result.maps = prefs.yp_maplist;
result.stat = YP_TRUE;
return (&result);
}
#ifdef NISV1
/*
* NIS v1 Support
*/
void * ypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
{
return(ypproc_null_2_svc(argp, rqstp));
}
bool_t * ypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
{
return(ypproc_domain_2_svc(argp, rqstp));
}
bool_t * ypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
{
return (ypproc_domain_nonack_2_svc(argp, rqstp));
}
/*
* the 'match' procedure sends a response of type YPRESP_VAL
*/
ypresponse * ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
ypresp_val *v2_result;
result.yp_resptype = YPRESP_VAL;
result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
if (argp->yp_reqtype != YPREQ_KEY) {
result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
return(&result);
}
v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
if (v2_result == NULL)
return(NULL);
bcopy((char *)v2_result,
(char *)&result.ypresponse_u.yp_resp_valtype,
sizeof(ypresp_val));
return (&result);
}
/*
* the 'first' procedure sends a response of type YPRESP_KEY_VAL
*/
ypresponse * ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
ypresp_key_val *v2_result;
result.yp_resptype = YPRESP_KEY_VAL;
result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
if (argp->yp_reqtype != YPREQ_NOKEY) {
result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
return(&result);
}
v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
rqstp);
if (v2_result == NULL)
return(NULL);
bcopy((char *)v2_result,
(char *)&result.ypresponse_u.yp_resp_key_valtype,
sizeof(ypresp_key_val));
return (&result);
}
/*
* the 'next' procedure sends a response of type YPRESP_KEY_VAL
*/
ypresponse * ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
ypresp_key_val *v2_result;
result.yp_resptype = YPRESP_KEY_VAL;
result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
if (argp->yp_reqtype != YPREQ_KEY) {
result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
return(&result);
}
v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
if (v2_result == NULL)
return(NULL);
bcopy((char *)v2_result,
(char *)&result.ypresponse_u.yp_resp_key_valtype,
sizeof(ypresp_key_val));
return (&result);
}
/*
* the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
*/
ypresponse * ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
ypresp_master *v2_result1;
ypresp_order *v2_result2;
result.yp_resptype = YPRESP_MAP_PARMS;
result.ypresponse_u.yp_resp_map_parmstype.domain =
argp->yprequest_u.yp_req_nokeytype.domain;
result.ypresponse_u.yp_resp_map_parmstype.map =
argp->yprequest_u.yp_req_nokeytype.map;
/*
* Hmm... there is no 'status' value in the
* yp_resp_map_parmstype structure, so I have to
* guess at what to do to indicate a failure.
* I hope this is right.
*/
result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
result.ypresponse_u.yp_resp_map_parmstype.peer = "";
if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
return(&result);
}
v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
rqstp);
if (v2_result1 == NULL)
return(NULL);
if (v2_result1->stat != YP_TRUE) {
return(&result);
}
v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
rqstp);
if (v2_result2 == NULL)
return(NULL);
if (v2_result2->stat != YP_TRUE) {
return(&result);
}
result.ypresponse_u.yp_resp_map_parmstype.peer =
v2_result1->peer;
result.ypresponse_u.yp_resp_map_parmstype.ordernum =
v2_result2->ordernum;
return (&result);
}
ypresponse * ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
/*
* Not implemented.
*/
return (&result);
}
ypresponse * ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
/*
* Not implemented.
*/
return (&result);
}
ypresponse * ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
{
static ypresponse result;
/*
* Not implemented.
*/
return (&result);
}
#endif
#ifndef YPSERV_ONLY
/* Empty symbols for Linux and Solaris' generated ypbind / ypproc RPC calls */
void * yppushproc_null_1_svc(void *argp, struct svc_req *dummy) {return NULL;}
#ifdef SOLARIS
yppushresp_xfr * yppushproc_xfrresp_1_svc(void *argp, struct svc_req *dummy) {return NULL;}
#else
void * yppushproc_xfrresp_1_svc(yppushresp_xfr *argp, struct svc_req *dummy) {return NULL;}
#endif
void * ypbindproc_null_2_svc(void *argp, struct svc_req *dummy) {return NULL;}
ypbind_resp * ypbindproc_domain_2_svc(domainname *argp, struct svc_req *dummy) {return NULL;}
void * ypbindproc_setdom_2_svc(ypbind_setdom *argp, struct svc_req *dummy) {return NULL;}
#endif
#ifdef SOLARIS
bool_t xdr_ypxfrstat (XDR *xdrs, ypxfrstat *objp)
{
return (xdr_enum (xdrs, (enum_t *) objp));
}
bool_t xdr_domainname (XDR *xdrs, domainname *objp)
{
return (xdr_string (xdrs, objp, YPMAXDOMAIN));
}
bool_t xdr_ypresp_all (XDR *xdrs, struct ypresp_all *objp)
{
if (!xdr_bool(xdrs, &objp->more))
return FALSE;
switch (objp->more) {
case TRUE:
return xdr_ypresp_key_val(xdrs, &objp->ypresp_all_u.val);
case FALSE:
return (TRUE);
default:
return (FALSE);
}
/* NOT REACHED */
}
bool_t xdr_ypresp_xfr (XDR *xdrs, ypresp_xfr *objp)
{
if (!xdr_u_int (xdrs, &objp->transid))
return (FALSE);
if (!xdr_ypxfrstat (xdrs, &objp->xfrstat))
return (FALSE);
return (TRUE);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1