/* * * yp.c * * YP call responses and related functions * * Author: Landon Fuller * * 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 #include #include #include #include #include #include #include #include #include #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