Index: head/include/rpcsvc/yp.x =================================================================== --- head/include/rpcsvc/yp.x (revision 350956) +++ head/include/rpcsvc/yp.x (revision 350957) @@ -1,379 +1,379 @@ /* @(#)yp.x 2.1 88/08/01 4.0 RPCSRC */ /*- * Copyright (c) 2010, Oracle America, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of the "Oracle America, 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 * COPYRIGHT HOLDER 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. */ /* * Protocol description file for the Yellow Pages Service */ #ifndef RPC_HDR %#include %__FBSDID("$FreeBSD$"); #endif -const YPMAXRECORD = 1024; +const YPMAXRECORD = 16777216; const YPMAXDOMAIN = 64; const YPMAXMAP = 64; const YPMAXPEER = 64; enum ypstat { YP_TRUE = 1, YP_NOMORE = 2, YP_FALSE = 0, YP_NOMAP = -1, YP_NODOM = -2, YP_NOKEY = -3, YP_BADOP = -4, YP_BADDB = -5, YP_YPERR = -6, YP_BADARGS = -7, YP_VERS = -8 }; enum ypxfrstat { YPXFR_SUCC = 1, YPXFR_AGE = 2, YPXFR_NOMAP = -1, YPXFR_NODOM = -2, YPXFR_RSRC = -3, YPXFR_RPC = -4, YPXFR_MADDR = -5, YPXFR_YPERR = -6, YPXFR_BADARGS = -7, YPXFR_DBM = -8, YPXFR_FILE = -9, YPXFR_SKEW = -10, YPXFR_CLEAR = -11, YPXFR_FORCE = -12, YPXFR_XFRERR = -13, YPXFR_REFUSED = -14 }; typedef string domainname; typedef string mapname; typedef string peername; typedef opaque keydat; typedef opaque valdat; struct ypmap_parms { domainname domain; mapname map; unsigned int ordernum; peername peer; }; struct ypreq_key { domainname domain; mapname map; keydat key; }; struct ypreq_nokey { domainname domain; mapname map; }; struct ypreq_xfr { ypmap_parms map_parms; unsigned int transid; unsigned int prog; unsigned int port; }; struct ypresp_val { ypstat stat; valdat val; }; struct ypresp_key_val { ypstat stat; #ifdef STUPID_SUN_BUG /* These are backwards */ keydat key; valdat val; #else valdat val; keydat key; #endif }; struct ypresp_master { ypstat stat; peername peer; }; struct ypresp_order { ypstat stat; unsigned int ordernum; }; union ypresp_all switch (bool more) { case TRUE: ypresp_key_val val; case FALSE: void; }; struct ypresp_xfr { unsigned int transid; ypxfrstat xfrstat; }; struct ypmaplist { mapname map; ypmaplist *next; }; struct ypresp_maplist { ypstat stat; ypmaplist *maps; }; enum yppush_status { YPPUSH_SUCC = 1, /* Success */ YPPUSH_AGE = 2, /* Master's version not newer */ YPPUSH_NOMAP = -1, /* Can't find server for map */ YPPUSH_NODOM = -2, /* Domain not supported */ YPPUSH_RSRC = -3, /* Local resource alloc failure */ YPPUSH_RPC = -4, /* RPC failure talking to server */ YPPUSH_MADDR = -5, /* Can't get master address */ YPPUSH_YPERR = -6, /* YP server/map db error */ YPPUSH_BADARGS = -7, /* Request arguments bad */ YPPUSH_DBM = -8, /* Local dbm operation failed */ YPPUSH_FILE = -9, /* Local file I/O operation failed */ YPPUSH_SKEW = -10, /* Map version skew during transfer */ YPPUSH_CLEAR = -11, /* Can't send "Clear" req to local ypserv */ YPPUSH_FORCE = -12, /* No local order number in map use -f flag. */ YPPUSH_XFRERR = -13, /* ypxfr error */ YPPUSH_REFUSED = -14 /* Transfer request refused by ypserv */ }; struct yppushresp_xfr { unsigned transid; yppush_status status; }; /* * Response structure and overall result status codes. Success and failure * represent two separate response message types. */ enum ypbind_resptype { YPBIND_SUCC_VAL = 1, YPBIND_FAIL_VAL = 2 }; struct ypbind_binding { opaque ypbind_binding_addr[4]; /* In network order */ opaque ypbind_binding_port[2]; /* In network order */ }; union ypbind_resp switch (ypbind_resptype ypbind_status) { case YPBIND_FAIL_VAL: unsigned ypbind_error; case YPBIND_SUCC_VAL: ypbind_binding ypbind_bindinfo; }; /* Detailed failure reason codes for response field ypbind_error*/ const YPBIND_ERR_ERR = 1; /* Internal error */ const YPBIND_ERR_NOSERV = 2; /* No bound server for passed domain */ const YPBIND_ERR_RESC = 3; /* System resource allocation failure */ /* * Request data structure for ypbind "Set domain" procedure. */ struct ypbind_setdom { domainname ypsetdom_domain; ypbind_binding ypsetdom_binding; unsigned ypsetdom_vers; }; /* * NIS v1 support for backwards compatibility */ enum ypreqtype { YPREQ_KEY = 1, YPREQ_NOKEY = 2, YPREQ_MAP_PARMS = 3 }; enum ypresptype { YPRESP_VAL = 1, YPRESP_KEY_VAL = 2, YPRESP_MAP_PARMS = 3 }; union yprequest switch (ypreqtype yp_reqtype) { case YPREQ_KEY: ypreq_key yp_req_keytype; case YPREQ_NOKEY: ypreq_nokey yp_req_nokeytype; case YPREQ_MAP_PARMS: ypmap_parms yp_req_map_parmstype; }; union ypresponse switch (ypresptype yp_resptype) { case YPRESP_VAL: ypresp_val yp_resp_valtype; case YPRESP_KEY_VAL: ypresp_key_val yp_resp_key_valtype; case YPRESP_MAP_PARMS: ypmap_parms yp_resp_map_parmstype; }; #if !defined(YPBIND_ONLY) && !defined(YPPUSH_ONLY) /* * YP access protocol */ program YPPROG { /* * NIS v1 support for backwards compatibility */ version YPOLDVERS { void YPOLDPROC_NULL(void) = 0; bool YPOLDPROC_DOMAIN(domainname) = 1; bool YPOLDPROC_DOMAIN_NONACK(domainname) = 2; ypresponse YPOLDPROC_MATCH(yprequest) = 3; ypresponse YPOLDPROC_FIRST(yprequest) = 4; ypresponse YPOLDPROC_NEXT(yprequest) = 5; ypresponse YPOLDPROC_POLL(yprequest) = 6; ypresponse YPOLDPROC_PUSH(yprequest) = 7; ypresponse YPOLDPROC_PULL(yprequest) = 8; ypresponse YPOLDPROC_GET(yprequest) = 9; } = 1; version YPVERS { void YPPROC_NULL(void) = 0; bool YPPROC_DOMAIN(domainname) = 1; bool YPPROC_DOMAIN_NONACK(domainname) = 2; ypresp_val YPPROC_MATCH(ypreq_key) = 3; ypresp_key_val #ifdef STUPID_SUN_BUG /* should be ypreq_nokey */ YPPROC_FIRST(ypreq_key) = 4; #else YPPROC_FIRST(ypreq_nokey) = 4; #endif ypresp_key_val YPPROC_NEXT(ypreq_key) = 5; ypresp_xfr YPPROC_XFR(ypreq_xfr) = 6; void YPPROC_CLEAR(void) = 7; ypresp_all YPPROC_ALL(ypreq_nokey) = 8; ypresp_master YPPROC_MASTER(ypreq_nokey) = 9; ypresp_order YPPROC_ORDER(ypreq_nokey) = 10; ypresp_maplist YPPROC_MAPLIST(domainname) = 11; } = 2; } = 100004; #endif #if !defined(YPSERV_ONLY) && !defined(YPBIND_ONLY) /* * YPPUSHPROC_XFRRESP is the callback routine for result of YPPROC_XFR */ program YPPUSH_XFRRESPPROG { version YPPUSH_XFRRESPVERS { void YPPUSHPROC_NULL(void) = 0; #ifdef STUPID_SUN_BUG /* argument and return value are backwards */ yppushresp_xfr YPPUSHPROC_XFRRESP(void) = 1; #else void YPPUSHPROC_XFRRESP(yppushresp_xfr) = 1; #endif } = 1; } = 0x40000000; /* transient: could be anything up to 0x5fffffff */ #endif #if !defined(YPSERV_ONLY) && !defined(YPPUSH_ONLY) /* * YP binding protocol */ program YPBINDPROG { version YPBINDVERS { void YPBINDPROC_NULL(void) = 0; ypbind_resp YPBINDPROC_DOMAIN(domainname) = 1; void YPBINDPROC_SETDOM(ypbind_setdom) = 2; } = 2; } = 100007; #endif Index: head/include/rpcsvc/yp_prot.h =================================================================== --- head/include/rpcsvc/yp_prot.h (revision 350956) +++ head/include/rpcsvc/yp_prot.h (revision 350957) @@ -1,331 +1,331 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992/3 Theo de Raadt * 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. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _RPCSVC_YP_PROT_H_ #define _RPCSVC_YP_PROT_H_ /* * YPSERV PROTOCOL: * * ypserv supports the following procedures: * * YPPROC_NULL takes (void), returns (void). * called to check if server is alive. * YPPROC_DOMAIN takes (char *), returns (bool_t). * true if ypserv serves the named domain. * YPPROC_DOMAIN_NOACK takes (char *), returns (bool_t). * true if ypserv serves the named domain. * used for broadcasts, does not ack if ypserv * doesn't handle named domain. * YPPROC_MATCH takes (struct ypreq_key), returns (struct ypresp_val) * does a lookup. * YPPROC_FIRST takes (struct ypreq_nokey) returns (ypresp_key_val). * gets the first key/datum from the map. * YPPROC_NEXT takes (struct ypreq_key) returns (ypresp_key_val). * gets the next key/datum from the map. * YPPROC_XFR takes (struct ypreq_xfr), returns (void). * tells ypserv to check if there is a new version of * the map. * YPPROC_CLEAR takes (void), returns (void). * tells ypserv to flush it's file cache, so that * newly transferred files will get read. * YPPROC_ALL takes (struct ypreq_nokey), returns (bool_t and * struct ypresp_key_val). * returns an array of data, with the bool_t being * false on the last datum. read the source, it's * convoluted. * YPPROC_MASTER takes (struct ypreq_nokey), returns (ypresp_master). * YPPROC_ORDER takes (struct ypreq_nokey), returns (ypresp_order). * YPPROC_MAPLIST takes (char *), returns (struct ypmaplist *). */ #ifndef BOOL_DEFINED typedef u_int bool; #define BOOL_DEFINED #endif /* Program and version symbols, magic numbers */ #define YPPROG ((u_long)100004) #define YPVERS ((u_long)2) #define YPVERS_ORIG ((u_long)1) -#define YPMAXRECORD ((u_long)1024) +#define YPMAXRECORD ((u_long)16 * 1024 * 1024) #define YPMAXDOMAIN ((u_long)64) #define YPMAXMAP ((u_long)64) #define YPMAXPEER ((u_long)256) /* * I don't know if anything of sun's depends on this, or if they * simply defined it so that their own code wouldn't try to send * packets over the ethernet MTU. This YP code doesn't use it. */ #define YPMSGSZ 1600 #ifndef DATUM typedef struct { char *dptr; int dsize; } datum; #define DATUM #endif struct ypmap_parms { char *domain; char *map; u_int ordernum; char *owner; }; struct ypreq_key { char *domain; char *map; datum keydat; }; struct ypreq_nokey { char *domain; char *map; }; struct ypreq_xfr { struct ypmap_parms map_parms; u_int transid; u_int proto; u_int port; }; #define ypxfr_domain map_parms.domain #define ypxfr_map map_parms.map #define ypxfr_ordernum map_parms.ordernum #define ypxfr_owner map_parms.owner struct ypresp_val { u_int status; datum valdat; }; struct ypresp_key_val { u_int status; datum keydat; datum valdat; }; struct ypresp_master { u_int status; char *master; }; struct ypresp_order { u_int status; u_int ordernum; }; struct ypmaplist { char *ypml_name; struct ypmaplist *ypml_next; }; struct ypresp_maplist { u_int status; struct ypmaplist *list; }; /* ypserv procedure numbers */ #define YPPROC_NULL ((u_long)0) #define YPPROC_DOMAIN ((u_long)1) #define YPPROC_DOMAIN_NONACK ((u_long)2) #define YPPROC_MATCH ((u_long)3) #define YPPROC_FIRST ((u_long)4) #define YPPROC_NEXT ((u_long)5) #define YPPROC_XFR ((u_long)6) #define YPPROC_CLEAR ((u_long)7) #define YPPROC_ALL ((u_long)8) #define YPPROC_MASTER ((u_long)9) #define YPPROC_ORDER ((u_long)10) #define YPPROC_MAPLIST ((u_long)11) /* ypserv procedure return status values */ #define YP_TRUE ((long)1) /* general purpose success code */ #define YP_NOMORE ((long)2) /* no more entries in map */ #define YP_FALSE ((long)0) /* general purpose failure code */ #define YP_NOMAP ((long)-1) /* no such map in domain */ #define YP_NODOM ((long)-2) /* domain not supported */ #define YP_NOKEY ((long)-3) /* no such key in map */ #define YP_BADOP ((long)-4) /* invalid operation */ #define YP_BADDB ((long)-5) /* server data base is bad */ #define YP_YPERR ((long)-6) /* YP server error */ #define YP_BADARGS ((long)-7) /* request arguments bad */ #define YP_VERS ((long)-8) /* YP server version mismatch */ /* * Sun's header file says: * "Domain binding data structure, used by ypclnt package and ypserv modules. * Users of the ypclnt package (or of this protocol) don't HAVE to know about * it, but it must be available to users because _yp_dobind is a public * interface." * * This is totally bogus! Nowhere else does Sun state that _yp_dobind() is * a public interface, and I don't know any reason anyone would want to call * it. But, just in case anyone does actually expect it to be available.. * we provide this.. exactly as Sun wants it. */ struct dom_binding { struct dom_binding *dom_pnext; char dom_domain[YPMAXDOMAIN + 1]; struct sockaddr_in dom_server_addr; u_short dom_server_port; int dom_socket; CLIENT *dom_client; u_short dom_local_port; long dom_vers; }; /* * YPBIND PROTOCOL: * * ypbind supports the following procedures: * * YPBINDPROC_NULL takes (void), returns (void). * to check if ypbind is running. * YPBINDPROC_DOMAIN takes (char *), returns (struct ypbind_resp). * requests that ypbind start to serve the * named domain (if it doesn't already) * YPBINDPROC_SETDOM takes (struct ypbind_setdom), returns (void). * used by ypset. */ #define YPBINDPROG ((u_long)100007) #define YPBINDVERS ((u_long)2) #define YPBINDVERS_ORIG ((u_long)1) /* ypbind procedure numbers */ #define YPBINDPROC_NULL ((u_long)0) #define YPBINDPROC_DOMAIN ((u_long)1) #define YPBINDPROC_SETDOM ((u_long)2) /* error code in ypbind_resp.ypbind_status */ enum ypbind_resptype { YPBIND_SUCC_VAL = 1, YPBIND_FAIL_VAL = 2 }; /* network order, of course */ struct ypbind_binding { struct in_addr ypbind_binding_addr; u_short ypbind_binding_port; }; struct ypbind_resp { enum ypbind_resptype ypbind_status; union { u_int ypbind_error; struct ypbind_binding ypbind_bindinfo; } ypbind_respbody; }; /* error code in ypbind_resp.ypbind_respbody.ypbind_error */ #define YPBIND_ERR_ERR 1 /* internal error */ #define YPBIND_ERR_NOSERV 2 /* no bound server for passed domain */ #define YPBIND_ERR_RESC 3 /* system resource allocation failure */ /* * Request data structure for ypbind "Set domain" procedure. */ struct ypbind_setdom { char ypsetdom_domain[YPMAXDOMAIN + 1]; struct ypbind_binding ypsetdom_binding; u_int ypsetdom_vers; }; #define ypsetdom_addr ypsetdom_binding.ypbind_binding_addr #define ypsetdom_port ypsetdom_binding.ypbind_binding_port /* * YPPUSH PROTOCOL: * * Sun says: * "Protocol between clients (ypxfr, only) and yppush * yppush speaks a protocol in the transient range, which * is supplied to ypxfr as a command-line parameter when it * is activated by ypserv." * * This protocol is not implemented, naturally, because this YP * implementation only does the client side. */ #define YPPUSHVERS ((u_long)1) #define YPPUSHVERS_ORIG ((u_long)1) /* yppush procedure numbers */ #define YPPUSHPROC_NULL ((u_long)0) #define YPPUSHPROC_XFRRESP ((u_long)1) struct yppushresp_xfr { u_int transid; u_int status; }; /* yppush status value in yppushresp_xfr.status */ #define YPPUSH_SUCC ((long)1) /* Success */ #define YPPUSH_AGE ((long)2) /* Master's version not newer */ #define YPPUSH_NOMAP ((long)-1) /* Can't find server for map */ #define YPPUSH_NODOM ((long)-2) /* Domain not supported */ #define YPPUSH_RSRC ((long)-3) /* Local resource alloc failure */ #define YPPUSH_RPC ((long)-4) /* RPC failure talking to server */ #define YPPUSH_MADDR ((long)-5) /* Can't get master address */ #define YPPUSH_YPERR ((long)-6) /* YP server/map db error */ #define YPPUSH_BADARGS ((long)-7) /* Request arguments bad */ #define YPPUSH_DBM ((long)-8) /* Local dbm operation failed */ #define YPPUSH_FILE ((long)-9) /* Local file I/O operation failed */ #define YPPUSH_SKEW ((long)-10) /* Map version skew during transfer */ #define YPPUSH_CLEAR ((long)-11) /* Can't send "Clear" req to local ypserv */ #define YPPUSH_FORCE ((long)-12) /* No local order number in map - use -f */ #define YPPUSH_XFRERR ((long)-13) /* ypxfr error */ #define YPPUSH_REFUSED ((long)-14) /* Transfer request refused by ypserv */ struct inaddr; __BEGIN_DECLS bool_t xdr_datum(XDR *, datum *); bool_t xdr_ypreq_key(XDR *, struct ypreq_key *); bool_t xdr_ypreq_nokey(XDR *, struct ypreq_nokey *); bool_t xdr_ypreq_xfr(XDR *, struct ypreq_xfr *); bool_t xdr_ypresp_val(XDR *, struct ypresp_val *); bool_t xdr_ypresp_key_val(XDR *, struct ypresp_key_val *); bool_t xdr_ypbind_resp(XDR *, struct ypbind_resp *); bool_t xdr_ypbind_setdom(XDR *, struct ypbind_setdom *); bool_t xdr_yp_inaddr(XDR *, struct inaddr *); bool_t xdr_ypmap_parms(XDR *, struct ypmap_parms *); bool_t xdr_yppushresp_xfr(XDR *, struct yppushresp_xfr *); bool_t xdr_ypresp_order(XDR *, struct ypresp_order *); bool_t xdr_ypresp_master(XDR *, struct ypresp_master *); bool_t xdr_ypresp_maplist(XDR *, struct ypresp_maplist *); __END_DECLS #endif /* _RPCSVC_YP_PROT_H_ */ Index: head/include/rpcsvc/ypxfrd.x =================================================================== --- head/include/rpcsvc/ypxfrd.x (revision 350956) +++ head/include/rpcsvc/ypxfrd.x (revision 350957) @@ -1,169 +1,169 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . 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 Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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. */ /* * This protocol definition file describes a file transfer * system used to very quickly move NIS maps from one host to * another. This is similar to what Sun does with their ypxfrd * protocol, but it must be stressed that this protocol is _NOT_ * compatible with Sun's. There are a couple of reasons for this: * * 1) Sun's protocol is proprietary. The protocol definition is * not freely available in any of the SunRPC source distributions, * even though the NIS v2 protocol is. * * 2) The idea here is to transfer entire raw files rather than * sending just the records. Sun uses ndbm for its NIS map files, * while FreeBSD uses Berkeley DB. Both are hash databases, but the * formats are incompatible, making it impossible for them to * use each others' files. Even if FreeBSD adopted ndbm for its * database format, FreeBSD/i386 is a little-endian OS and * SunOS/SPARC is big-endian; ndbm is byte-order sensitive and * not very smart about it, which means an attempt to read a * database on a little-endian box that was created on a big-endian * box (or vice-versa) can cause the ndbm code to eat itself. * Luckily, Berkeley DB is able to deal with this situation in * a more graceful manner. * * While the protocol is incompatible, the idea is the same: we just open * up a TCP pipe to the client and transfer the raw map database * from the master server to the slave. This is many times faster than * the standard yppush/ypxfr transfer method since it saves us from * having to recreate the map databases via the DB library each time. * For example: creating a passwd database with 30,000 entries with yp_mkdb * can take a couple of minutes, but to just copy the file takes only a few * seconds. */ #ifndef RPC_HDR %#include %__FBSDID("$FreeBSD$"); #endif /* XXX cribbed from yp.x */ -const _YPMAXRECORD = 1024; +const _YPMAXRECORD = 16777216; const _YPMAXDOMAIN = 64; const _YPMAXMAP = 64; const _YPMAXPEER = 64; /* Suggested default -- not necessarily the one used. */ const YPXFRBLOCK = 32767; /* * Possible return codes from the remote server. */ enum xfrstat { XFR_REQUEST_OK = 1, /* Transfer request granted */ XFR_DENIED = 2, /* Transfer request denied */ XFR_NOFILE = 3, /* Requested map file doesn't exist */ XFR_ACCESS = 4, /* File exists, but I couldn't access it */ XFR_BADDB = 5, /* File is not a hash database */ XFR_READ_OK = 6, /* Block read successfully */ XFR_READ_ERR = 7, /* Read error during transfer */ XFR_DONE = 8, /* Transfer completed */ XFR_DB_ENDIAN_MISMATCH = 9, /* Database byte order mismatch */ XFR_DB_TYPE_MISMATCH = 10 /* Database type mismatch */ }; /* * Database type specifications. The client can use this to ask * the server for a particular type of database or just take whatever * the server has to offer. */ enum xfr_db_type { XFR_DB_ASCII = 1, /* Flat ASCII text */ XFR_DB_BSD_HASH = 2, /* Berkeley DB, hash method */ XFR_DB_BSD_BTREE = 3, /* Berkeley DB, btree method */ XFR_DB_BSD_RECNO = 4, /* Berkeley DB, recno method */ XFR_DB_BSD_MPOOL = 5, /* Berkeley DB, mpool method */ XFR_DB_BSD_NDBM = 6, /* Berkeley DB, hash, ndbm compat */ XFR_DB_GNU_GDBM = 7, /* GNU GDBM */ XFR_DB_DBM = 8, /* Old, deprecated dbm format */ XFR_DB_NDBM = 9, /* ndbm format (used by Sun's NISv2) */ XFR_DB_OPAQUE = 10, /* Mystery format -- just pass along */ XFR_DB_ANY = 11, /* I'll take any format you've got */ XFR_DB_UNKNOWN = 12 /* Unknown format */ }; /* * Machine byte order specification. This allows the client to check * that it's copying a map database from a machine of similar byte sex. * This is necessary for handling database libraries that are fatally * byte order sensitive. * * The XFR_ENDIAN_ANY type is for use with the Berkeley DB database * formats; Berkeley DB is smart enough to make up for byte order * differences, so byte sex isn't important. */ enum xfr_byte_order { XFR_ENDIAN_BIG = 1, /* We want big endian */ XFR_ENDIAN_LITTLE = 2, /* We want little endian */ XFR_ENDIAN_ANY = 3 /* We'll take whatever you got */ }; typedef string xfrdomain<_YPMAXDOMAIN>; typedef string xfrmap<_YPMAXMAP>; typedef string xfrmap_filename<_YPMAXMAP>; /* actual name of map file */ /* * Ask the remote ypxfrd for a map using this structure. * Note: we supply both a map name and a map file name. These are not * the same thing. In the case of ndbm, maps are stored in two files: * map.bykey.pag and may.bykey.dir. We may also have to deal with * file extensions (on the off chance that the remote server is supporting * multiple DB formats). To handle this, we tell the remote server both * what map we want and, in the case of ndbm, whether we want the .dir * or the .pag part. This name should not be a fully qualified path: * it's up to the remote server to decide which directories to look in. */ struct ypxfr_mapname { xfrmap xfrmap; xfrdomain xfrdomain; xfrmap_filename xfrmap_filename; xfr_db_type xfr_db_type; xfr_byte_order xfr_byte_order; }; /* Read response using this structure. */ union xfr switch (bool ok) { case TRUE: opaque xfrblock_buf<>; case FALSE: xfrstat xfrstat; }; program YPXFRD_FREEBSD_PROG { version YPXFRD_FREEBSD_VERS { union xfr YPXFRD_GETMAP(ypxfr_mapname) = 1; } = 1; } = 600100069; /* 100069 + 60000000 -- 100069 is the Sun ypxfrd prog number */ Index: head/lib/libc/net/gethostbynis.c =================================================================== --- head/lib/libc/net/gethostbynis.c (revision 350956) +++ head/lib/libc/net/gethostbynis.c (revision 350957) @@ -1,299 +1,300 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994, Garrett Wollman * * 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. * * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX */ #ifdef YP #include #include #include #endif #include "netdb_private.h" #ifdef YP static int _gethostbynis(const char *name, char *map, int af, struct hostent *he, struct hostent_data *hed) { char *p, *bp, *ep; char *cp, **q; char *result; int resultlen, size, addrok = 0; - char ypbuf[YPMAXRECORD + 2]; + char *ypbuf; res_state statp; statp = __res_state(); switch(af) { case AF_INET: size = NS_INADDRSZ; break; case AF_INET6: size = NS_IN6ADDRSZ; break; default: errno = EAFNOSUPPORT; RES_SET_H_ERRNO(statp, NETDB_INTERNAL); return (-1); } if (hed->yp_domain == (char *)NULL) if (yp_get_default_domain (&hed->yp_domain)) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); return (-1); } if (yp_match(hed->yp_domain, map, name, strlen(name), &result, &resultlen)) { RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); return (-1); } /* avoid potential memory leak */ - bcopy((char *)result, (char *)&ypbuf, resultlen); + ypbuf = alloca(resultlen + 2); + bcopy(result, ypbuf, resultlen); ypbuf[resultlen] = '\0'; free(result); - result = (char *)&ypbuf; + result = ypbuf; if ((cp = strchr(result, '\n'))) *cp = '\0'; cp = strpbrk(result, " \t"); *cp++ = '\0'; he->h_addr_list = hed->h_addr_ptrs; he->h_addr = (char *)hed->host_addr; switch (af) { case AF_INET: addrok = inet_aton(result, (struct in_addr *)hed->host_addr); if (addrok != 1) break; if (statp->options & RES_USE_INET6) { _map_v4v6_address((char *)hed->host_addr, (char *)hed->host_addr); af = AF_INET6; size = NS_IN6ADDRSZ; } break; case AF_INET6: addrok = inet_pton(af, result, hed->host_addr); break; } if (addrok != 1) { RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); return (-1); } he->h_addr_list[1] = NULL; he->h_length = size; he->h_addrtype = af; while (*cp == ' ' || *cp == '\t') cp++; bp = hed->hostbuf; ep = hed->hostbuf + sizeof hed->hostbuf; he->h_name = bp; q = he->h_aliases = hed->host_aliases; p = strpbrk(cp, " \t"); if (p != NULL) *p++ = '\0'; size = strlen(cp) + 1; if (ep - bp < size) { RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } strlcpy(bp, cp, ep - bp); bp += size; cp = p; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } if (q >= &hed->host_aliases[_MAXALIASES - 1]) break; p = strpbrk(cp, " \t"); if (p != NULL) *p++ = '\0'; size = strlen(cp) + 1; if (ep - bp < size) break; strlcpy(bp, cp, ep - bp); *q++ = bp; bp += size; cp = p; } *q = NULL; return (0); } static int _gethostbynisname_r(const char *name, int af, struct hostent *he, struct hostent_data *hed) { char *map; switch (af) { case AF_INET: map = "hosts.byname"; break; default: map = "ipnodes.byname"; break; } return (_gethostbynis(name, map, af, he, hed)); } static int _gethostbynisaddr_r(const void *addr, socklen_t len, int af, struct hostent *he, struct hostent_data *hed) { char *map; char numaddr[46]; switch (af) { case AF_INET: map = "hosts.byaddr"; break; default: map = "ipnodes.byaddr"; break; } if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL) return (-1); return (_gethostbynis(numaddr, map, af, he, hed)); } #endif /* YP */ int _nis_gethostbyname(void *rval, void *cb_data, va_list ap) { #ifdef YP const char *name; int af; char *buffer; size_t buflen; int *errnop, *h_errnop; struct hostent *hptr, he; struct hostent_data *hed; res_state statp; name = va_arg(ap, const char *); af = va_arg(ap, int); hptr = va_arg(ap, struct hostent *); buffer = va_arg(ap, char *); buflen = va_arg(ap, size_t); errnop = va_arg(ap, int *); h_errnop = va_arg(ap, int *); *((struct hostent **)rval) = NULL; statp = __res_state(); if ((hed = __hostent_data_init()) == NULL) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (_gethostbynisname_r(name, af, &he, hed) != 0) { *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (__copy_hostent(&he, hptr, buffer, buflen) != 0) { *errnop = errno; RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_RETURN); } *((struct hostent **)rval) = hptr; return (NS_SUCCESS); #else *((struct hostent **)rval) = NULL; return (NS_UNAVAIL); #endif } int _nis_gethostbyaddr(void *rval, void *cb_data, va_list ap) { #ifdef YP const void *addr; socklen_t len; int af; char *buffer; size_t buflen; int *errnop, *h_errnop; struct hostent *hptr, he; struct hostent_data *hed; res_state statp; addr = va_arg(ap, const void *); len = va_arg(ap, socklen_t); af = va_arg(ap, int); hptr = va_arg(ap, struct hostent *); buffer = va_arg(ap, char *); buflen = va_arg(ap, size_t); errnop = va_arg(ap, int *); h_errnop = va_arg(ap, int *); *((struct hostent **)rval) = NULL; statp = __res_state(); if ((hed = __hostent_data_init()) == NULL) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (_gethostbynisaddr_r(addr, len, af, &he, hed) != 0) { *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (__copy_hostent(&he, hptr, buffer, buflen) != 0) { *errnop = errno; RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_RETURN); } *((struct hostent **)rval) = hptr; return (NS_SUCCESS); #else *((struct hostent **)rval) = NULL; return (NS_UNAVAIL); #endif } Index: head/lib/libc/net/getnetbynis.c =================================================================== --- head/lib/libc/net/getnetbynis.c (revision 350956) +++ head/lib/libc/net/getnetbynis.c (revision 350957) @@ -1,261 +1,262 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994, Garrett Wollman * * 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. * * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef YP #include #include #include #endif #include "netdb_private.h" #ifdef YP static int _getnetbynis(const char *name, char *map, int af, struct netent *ne, struct netent_data *ned) { char *p, *bp, *ep; char *cp, **q; char *result; int resultlen, len; - char ypbuf[YPMAXRECORD + 2]; + char *ypbuf; switch(af) { case AF_INET: break; default: case AF_INET6: errno = EAFNOSUPPORT; return (-1); } if (ned->yp_domain == (char *)NULL) if (yp_get_default_domain (&ned->yp_domain)) return (-1); if (yp_match(ned->yp_domain, map, name, strlen(name), &result, &resultlen)) return (-1); - bcopy((char *)result, (char *)&ypbuf, resultlen); + ypbuf = alloca(resultlen + 2); + bcopy(result, ypbuf, resultlen); ypbuf[resultlen] = '\0'; free(result); - result = (char *)&ypbuf; + result = ypbuf; if ((cp = strchr(result, '\n'))) *cp = '\0'; cp = strpbrk(result, " \t"); *cp++ = '\0'; bp = ned->netbuf; ep = ned->netbuf + sizeof ned->netbuf; len = strlen(result) + 1; if (ep - bp < len) { RES_SET_H_ERRNO(__res_state(), NO_RECOVERY); return (-1); } strlcpy(bp, result, ep - bp); ne->n_name = bp; bp += len; while (*cp == ' ' || *cp == '\t') cp++; ne->n_net = inet_network(cp); ne->n_addrtype = AF_INET; q = ne->n_aliases = ned->net_aliases; cp = strpbrk(cp, " \t"); if (cp != NULL) *cp++ = '\0'; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } if (q > &ned->net_aliases[_MAXALIASES - 1]) break; p = strpbrk(cp, " \t"); if (p != NULL) *p++ = '\0'; len = strlen(cp) + 1; if (ep - bp < len) break; strlcpy(bp, cp, ep - bp); *q++ = bp; bp += len; cp = p; } *q = NULL; return (0); } #endif /* YP */ int _nis_getnetbyname(void *rval, void *cb_data, va_list ap) { #ifdef YP const char *name; char *buffer; size_t buflen; int *errnop, *h_errnop; struct netent *nptr, ne; struct netent_data *ned; res_state statp; name = va_arg(ap, const char *); nptr = va_arg(ap, struct netent *); buffer = va_arg(ap, char *); buflen = va_arg(ap, size_t); errnop = va_arg(ap, int *); h_errnop = va_arg(ap, int *); statp = __res_state(); if ((ned = __netent_data_init()) == NULL) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_UNAVAIL); } if (_getnetbynis(name, "networks.byname", AF_INET, &ne, ned) != 0) { *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (__copy_netent(&ne, nptr, buffer, buflen) != 0) { *errnop = errno; RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_RETURN); } *((struct netent **)rval) = nptr; return (NS_SUCCESS); #else return (NS_UNAVAIL); #endif } int _nis_getnetbyaddr(void *rval, void *cb_data, va_list ap) { #ifdef YP uint32_t addr; int af; char *buffer; size_t buflen; int *errnop, *h_errnop; struct netent *nptr, ne; struct netent_data *ned; char *str, *cp; uint32_t net2; int nn; unsigned int netbr[4]; char buf[MAXDNAME]; res_state statp; addr = va_arg(ap, uint32_t); af = va_arg(ap, int); nptr = va_arg(ap, struct netent *); buffer = va_arg(ap, char *); buflen = va_arg(ap, size_t); errnop = va_arg(ap, int *); h_errnop = va_arg(ap, int *); statp = __res_state(); if ((ned = __netent_data_init()) == NULL) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_UNAVAIL); } if (af != AF_INET) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; errno = EAFNOSUPPORT; return (NS_UNAVAIL); } for (nn = 4, net2 = addr; net2; net2 >>= 8) { netbr[--nn] = net2 & 0xff; } switch (nn) { case 3: /* Class A */ sprintf(buf, "%u", netbr[3]); break; case 2: /* Class B */ sprintf(buf, "%u.%u", netbr[2], netbr[3]); break; case 1: /* Class C */ sprintf(buf, "%u.%u.%u", netbr[1], netbr[2], netbr[3]); break; case 0: /* Class D - E */ sprintf(buf, "%u.%u.%u.%u", netbr[0], netbr[1], netbr[2], netbr[3]); break; } str = (char *)&buf; cp = str + (strlen(str) - 2); while(!strcmp(cp, ".0")) { *cp = '\0'; cp = str + (strlen(str) - 2); } if (_getnetbynis(str, "networks.byaddr", af, &ne, ned) != 0) { *h_errnop = statp->res_h_errno; return (NS_NOTFOUND); } if (__copy_netent(&ne, nptr, buffer, buflen) != 0) { *errnop = errno; RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_RETURN); } *((struct netent **)rval) = nptr; return (NS_SUCCESS); #else return (NS_UNAVAIL); #endif /* YP */ } Index: head/lib/libc/net/getservent.c =================================================================== --- head/lib/libc/net/getservent.c (revision 350956) +++ head/lib/libc/net/getservent.c (revision 350957) @@ -1,1374 +1,1381 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1993 * The Regents of the University of California. 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef YP #include #include #include #endif #include "namespace.h" #include "reentrant.h" #include "un-namespace.h" #include "netdb_private.h" #ifdef NS_CACHING #include "nscache.h" #endif #include "nss_tls.h" enum constants { SETSERVENT = 1, ENDSERVENT = 2, SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */ }; struct servent_mdata { enum nss_lookup_type how; int compat_mode; }; static const ns_src defaultsrc[] = { { NSSRC_COMPAT, NS_SUCCESS }, { NULL, 0 } }; static int servent_unpack(char *, struct servent *, char **, size_t, int *); /* files backend declarations */ struct files_state { FILE *fp; int stayopen; int compat_mode_active; }; static void files_endstate(void *); NSS_TLS_HANDLING(files); static int files_servent(void *, void *, va_list); static int files_setservent(void *, void *, va_list); /* db backend declarations */ struct db_state { DB *db; int stayopen; int keynum; }; static void db_endstate(void *); NSS_TLS_HANDLING(db); static int db_servent(void *, void *, va_list); static int db_setservent(void *, void *, va_list); #ifdef YP /* nis backend declarations */ static int nis_servent(void *, void *, va_list); static int nis_setservent(void *, void *, va_list); struct nis_state { int yp_stepping; char yp_domain[MAXHOSTNAMELEN]; char *yp_key; int yp_keylen; }; static void nis_endstate(void *); NSS_TLS_HANDLING(nis); static int nis_servent(void *, void *, va_list); static int nis_setservent(void *, void *, va_list); #endif /* compat backend declarations */ static int compat_setservent(void *, void *, va_list); /* get** wrappers for get**_r functions declarations */ struct servent_state { struct servent serv; char *buffer; size_t bufsize; }; static void servent_endstate(void *); NSS_TLS_HANDLING(servent); struct key { const char *proto; union { const char *name; int port; }; }; static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t, struct servent **); static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t, struct servent **); static int wrap_getservent_r(struct key, struct servent *, char *, size_t, struct servent **); static struct servent *getserv(int (*fn)(struct key, struct servent *, char *, size_t, struct servent **), struct key); #ifdef NS_CACHING static int serv_id_func(char *, size_t *, va_list, void *); static int serv_marshal_func(char *, size_t *, void *, va_list, void *); static int serv_unmarshal_func(char *, size_t, void *, va_list, void *); #endif static int servent_unpack(char *p, struct servent *serv, char **aliases, size_t aliases_size, int *errnop) { char *cp, **q, *endp; long l; if (*p == '#') return -1; memset(serv, 0, sizeof(struct servent)); cp = strpbrk(p, "#\n"); if (cp != NULL) *cp = '\0'; serv->s_name = p; p = strpbrk(p, " \t"); if (p == NULL) return -1; *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; cp = strpbrk(p, ",/"); if (cp == NULL) return -1; *cp++ = '\0'; l = strtol(p, &endp, 10); if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) return -1; serv->s_port = htons((in_port_t)l); serv->s_proto = cp; q = serv->s_aliases = aliases; cp = strpbrk(cp, " \t"); if (cp != NULL) *cp++ = '\0'; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } if (q < &aliases[aliases_size - 1]) { *q++ = cp; } else { *q = NULL; *errnop = ERANGE; return -1; } cp = strpbrk(cp, " \t"); if (cp != NULL) *cp++ = '\0'; } *q = NULL; return 0; } static int parse_result(struct servent *serv, char *buffer, size_t bufsize, char *resultbuf, size_t resultbuflen, int *errnop) { char **aliases; int aliases_size; if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) { *errnop = ERANGE; return (NS_RETURN); } aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]); aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *); if (aliases_size < 1) { *errnop = ERANGE; return (NS_RETURN); } memcpy(buffer, resultbuf, resultbuflen); buffer[resultbuflen] = '\0'; if (servent_unpack(buffer, serv, aliases, aliases_size, errnop) != 0) return ((*errnop == 0) ? NS_NOTFOUND : NS_RETURN); return (NS_SUCCESS); } /* files backend implementation */ static void files_endstate(void *p) { FILE * f; if (p == NULL) return; f = ((struct files_state *)p)->fp; if (f != NULL) fclose(f); free(p); } /* * compat structures. compat and files sources functionalities are almost * equal, so they all are managed by files_servent function */ static int files_servent(void *retval, void *mdata, va_list ap) { static const ns_src compat_src[] = { #ifdef YP { NSSRC_NIS, NS_SUCCESS }, #endif { NULL, 0 } }; ns_dtab compat_dtab[] = { { NSSRC_DB, db_servent, (void *)((struct servent_mdata *)mdata)->how }, #ifdef YP { NSSRC_NIS, nis_servent, (void *)((struct servent_mdata *)mdata)->how }, #endif { NULL, NULL, NULL } }; struct files_state *st; int rv; int stayopen; struct servent_mdata *serv_mdata; char *name; char *proto; int port; struct servent *serv; char *buffer; size_t bufsize; int *errnop; size_t linesize; char *line; char **cp; name = NULL; proto = NULL; serv_mdata = (struct servent_mdata *)mdata; switch (serv_mdata->how) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); break; case nss_lt_all: break; default: return NS_NOTFOUND; } serv = va_arg(ap, struct servent *); buffer = va_arg(ap, char *); bufsize = va_arg(ap, size_t); errnop = va_arg(ap,int *); *errnop = files_getstate(&st); if (*errnop != 0) return (NS_UNAVAIL); if (st->fp == NULL) st->compat_mode_active = 0; if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "re")) == NULL) { *errnop = errno; return (NS_UNAVAIL); } if (serv_mdata->how == nss_lt_all) stayopen = 1; else { rewind(st->fp); stayopen = st->stayopen; } rv = NS_NOTFOUND; do { if (!st->compat_mode_active) { if ((line = fgetln(st->fp, &linesize)) == NULL) { *errnop = errno; rv = NS_RETURN; break; } if (*line=='+' && serv_mdata->compat_mode != 0) st->compat_mode_active = 1; } if (st->compat_mode_active != 0) { switch (serv_mdata->how) { case nss_lt_name: rv = nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, "getservbyname_r", compat_src, name, proto, serv, buffer, bufsize, errnop); break; case nss_lt_id: rv = nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, "getservbyport_r", compat_src, port, proto, serv, buffer, bufsize, errnop); break; case nss_lt_all: rv = nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, "getservent_r", compat_src, serv, buffer, bufsize, errnop); break; } if (!(rv & NS_TERMINATE) || serv_mdata->how != nss_lt_all) st->compat_mode_active = 0; continue; } rv = parse_result(serv, buffer, bufsize, line, linesize, errnop); if (rv == NS_NOTFOUND) continue; if (rv == NS_RETURN) break; rv = NS_NOTFOUND; switch (serv_mdata->how) { case nss_lt_name: if (strcmp(name, serv->s_name) == 0) goto gotname; for (cp = serv->s_aliases; *cp; cp++) if (strcmp(name, *cp) == 0) goto gotname; continue; gotname: if (proto == NULL || strcmp(serv->s_proto, proto) == 0) rv = NS_SUCCESS; break; case nss_lt_id: if (port != serv->s_port) continue; if (proto == NULL || strcmp(serv->s_proto, proto) == 0) rv = NS_SUCCESS; break; case nss_lt_all: rv = NS_SUCCESS; break; } } while (!(rv & NS_TERMINATE)); if (!stayopen && st->fp != NULL) { fclose(st->fp); st->fp = NULL; } if ((rv == NS_SUCCESS) && (retval != NULL)) *(struct servent **)retval=serv; return (rv); } static int files_setservent(void *retval, void *mdata, va_list ap) { struct files_state *st; int rv; int f; rv = files_getstate(&st); if (rv != 0) return (NS_UNAVAIL); switch ((enum constants)mdata) { case SETSERVENT: f = va_arg(ap,int); if (st->fp == NULL) st->fp = fopen(_PATH_SERVICES, "re"); else rewind(st->fp); st->stayopen |= f; break; case ENDSERVENT: if (st->fp != NULL) { fclose(st->fp); st->fp = NULL; } st->stayopen = 0; break; default: break; } st->compat_mode_active = 0; return (NS_UNAVAIL); } /* db backend implementation */ static void db_endstate(void *p) { DB *db; if (p == NULL) return; db = ((struct db_state *)p)->db; if (db != NULL) db->close(db); free(p); } static int db_servent(void *retval, void *mdata, va_list ap) { char buf[BUFSIZ]; DBT key, data, *result; DB *db; struct db_state *st; int rv; int stayopen; enum nss_lookup_type how; char *name; char *proto; int port; struct servent *serv; char *buffer; size_t bufsize; int *errnop; name = NULL; proto = NULL; how = (enum nss_lookup_type)mdata; switch (how) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); break; case nss_lt_all: break; default: return NS_NOTFOUND; } serv = va_arg(ap, struct servent *); buffer = va_arg(ap, char *); bufsize = va_arg(ap, size_t); errnop = va_arg(ap,int *); *errnop = db_getstate(&st); if (*errnop != 0) return (NS_UNAVAIL); if (how == nss_lt_all && st->keynum < 0) return (NS_NOTFOUND); if (st->db == NULL) { st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL); if (st->db == NULL) { *errnop = errno; return (NS_UNAVAIL); } } stayopen = (how == nss_lt_all) ? 1 : st->stayopen; db = st->db; do { switch (how) { case nss_lt_name: key.data = buf; if (proto == NULL) key.size = snprintf(buf, sizeof(buf), "\376%s", name); else key.size = snprintf(buf, sizeof(buf), "\376%s/%s", name, proto); key.size++; if (db->get(db, &key, &data, 0) != 0 || db->get(db, &data, &key, 0) != 0) { rv = NS_NOTFOUND; goto db_fin; } result = &key; break; case nss_lt_id: key.data = buf; port = htons(port); if (proto == NULL) key.size = snprintf(buf, sizeof(buf), "\377%d", port); else key.size = snprintf(buf, sizeof(buf), "\377%d/%s", port, proto); key.size++; if (db->get(db, &key, &data, 0) != 0 || db->get(db, &data, &key, 0) != 0) { rv = NS_NOTFOUND; goto db_fin; } result = &key; break; case nss_lt_all: key.data = buf; key.size = snprintf(buf, sizeof(buf), "%d", st->keynum++); key.size++; if (db->get(db, &key, &data, 0) != 0) { st->keynum = -1; rv = NS_NOTFOUND; goto db_fin; } result = &data; break; } rv = parse_result(serv, buffer, bufsize, result->data, result->size - 1, errnop); } while (!(rv & NS_TERMINATE) && how == nss_lt_all); db_fin: if (!stayopen && st->db != NULL) { db->close(db); st->db = NULL; } if (rv == NS_SUCCESS && retval != NULL) *(struct servent **)retval = serv; return (rv); } static int db_setservent(void *retval, void *mdata, va_list ap) { DB *db; struct db_state *st; int rv; int f; rv = db_getstate(&st); if (rv != 0) return (NS_UNAVAIL); switch ((enum constants)mdata) { case SETSERVENT: f = va_arg(ap, int); st->stayopen |= f; st->keynum = 0; break; case ENDSERVENT: db = st->db; if (db != NULL) { db->close(db); st->db = NULL; } st->stayopen = 0; break; default: break; } return (NS_UNAVAIL); } /* nis backend implementation */ #ifdef YP static void nis_endstate(void *p) { if (p == NULL) return; free(((struct nis_state *)p)->yp_key); free(p); } static int nis_servent(void *retval, void *mdata, va_list ap) { char *resultbuf, *lastkey; int resultbuflen; - char buf[YPMAXRECORD + 2]; + char *buf; struct nis_state *st; int rv; enum nss_lookup_type how; char *name; char *proto; int port; struct servent *serv; char *buffer; size_t bufsize; int *errnop; name = NULL; proto = NULL; + buf = NULL; how = (enum nss_lookup_type)mdata; switch (how) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); break; case nss_lt_all: break; default: return NS_NOTFOUND; } serv = va_arg(ap, struct servent *); buffer = va_arg(ap, char *); bufsize = va_arg(ap, size_t); errnop = va_arg(ap, int *); *errnop = nis_getstate(&st); if (*errnop != 0) return (NS_UNAVAIL); if (st->yp_domain[0] == '\0') { if (getdomainname(st->yp_domain, sizeof st->yp_domain)) { *errnop = errno; return (NS_UNAVAIL); } } do { switch (how) { case nss_lt_name: - snprintf(buf, sizeof(buf), "%s/%s", name, proto); + free(buf); + asprintf(&buf, "%s/%s", name, proto); + if (buf == NULL) + return (NS_TRYAGAIN); if (yp_match(st->yp_domain, "services.byname", buf, strlen(buf), &resultbuf, &resultbuflen)) { rv = NS_NOTFOUND; goto fin; } break; case nss_lt_id: - snprintf(buf, sizeof(buf), "%d/%s", ntohs(port), - proto); + free(buf); + asprintf(&buf, "%d/%s", ntohs(port), proto); + if (buf == NULL) + return (NS_TRYAGAIN); /* * We have to be a little flexible * here. Ideally you're supposed to have both * a services.byname and a services.byport * map, but some systems have only * services.byname. FreeBSD cheats a little by * putting the services.byport information in * the same map as services.byname so that * either case will work. We allow for both * possibilities here: if there is no * services.byport map, we try services.byname * instead. */ rv = yp_match(st->yp_domain, "services.byport", buf, strlen(buf), &resultbuf, &resultbuflen); if (rv) { if (rv == YPERR_MAP) { if (yp_match(st->yp_domain, "services.byname", buf, strlen(buf), &resultbuf, &resultbuflen)) { rv = NS_NOTFOUND; goto fin; } } else { rv = NS_NOTFOUND; goto fin; } } break; case nss_lt_all: if (!st->yp_stepping) { free(st->yp_key); rv = yp_first(st->yp_domain, "services.byname", &st->yp_key, &st->yp_keylen, &resultbuf, &resultbuflen); if (rv) { rv = NS_NOTFOUND; goto fin; } st->yp_stepping = 1; } else { lastkey = st->yp_key; rv = yp_next(st->yp_domain, "services.byname", st->yp_key, st->yp_keylen, &st->yp_key, &st->yp_keylen, &resultbuf, &resultbuflen); free(lastkey); if (rv) { st->yp_stepping = 0; rv = NS_NOTFOUND; goto fin; } } break; } rv = parse_result(serv, buffer, bufsize, resultbuf, resultbuflen, errnop); free(resultbuf); } while (!(rv & NS_TERMINATE) && how == nss_lt_all); fin: + free(buf); if (rv == NS_SUCCESS && retval != NULL) *(struct servent **)retval = serv; return (rv); } static int nis_setservent(void *result, void *mdata, va_list ap) { struct nis_state *st; int rv; rv = nis_getstate(&st); if (rv != 0) return (NS_UNAVAIL); switch ((enum constants)mdata) { case SETSERVENT: case ENDSERVENT: free(st->yp_key); st->yp_key = NULL; st->yp_stepping = 0; break; default: break; } return (NS_UNAVAIL); } #endif /* compat backend implementation */ static int compat_setservent(void *retval, void *mdata, va_list ap) { static const ns_src compat_src[] = { #ifdef YP { NSSRC_NIS, NS_SUCCESS }, #endif { NULL, 0 } }; ns_dtab compat_dtab[] = { { NSSRC_DB, db_setservent, mdata }, #ifdef YP { NSSRC_NIS, nis_setservent, mdata }, #endif { NULL, NULL, NULL } }; int f; (void)files_setservent(retval, mdata, ap); switch ((enum constants)mdata) { case SETSERVENT: f = va_arg(ap,int); (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, "setservent", compat_src, f); break; case ENDSERVENT: (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, "endservent", compat_src); break; default: break; } return (NS_UNAVAIL); } #ifdef NS_CACHING static int serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) { char *name; char *proto; int port; size_t desired_size, size, size2; enum nss_lookup_type lookup_type; int res = NS_UNAVAIL; lookup_type = (enum nss_lookup_type)cache_mdata; switch (lookup_type) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); size = strlen(name); desired_size = sizeof(enum nss_lookup_type) + size + 1; if (proto != NULL) { size2 = strlen(proto); desired_size += size2 + 1; } else size2 = 0; if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); if (proto != NULL) memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1, proto, size2 + 1); res = NS_SUCCESS; break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); desired_size = sizeof(enum nss_lookup_type) + sizeof(int); if (proto != NULL) { size = strlen(proto); desired_size += size + 1; } else size = 0; if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); memcpy(buffer + sizeof(enum nss_lookup_type), &port, sizeof(int)); if (proto != NULL) memcpy(buffer + sizeof(enum nss_lookup_type) + sizeof(int), proto, size + 1); res = NS_SUCCESS; break; default: /* should be unreachable */ return (NS_UNAVAIL); } fin: *buffer_size = desired_size; return (res); } int serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, void *cache_mdata) { char *name; char *proto; int port; struct servent *serv; char *orig_buf; size_t orig_buf_size; struct servent new_serv; size_t desired_size; char **alias; char *p; size_t size; size_t aliases_size; switch ((enum nss_lookup_type)cache_mdata) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); break; case nss_lt_all: break; default: /* should be unreachable */ return (NS_UNAVAIL); } serv = va_arg(ap, struct servent *); orig_buf = va_arg(ap, char *); orig_buf_size = va_arg(ap, size_t); desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *); if (serv->s_name != NULL) desired_size += strlen(serv->s_name) + 1; if (serv->s_proto != NULL) desired_size += strlen(serv->s_proto) + 1; aliases_size = 0; if (serv->s_aliases != NULL) { for (alias = serv->s_aliases; *alias; ++alias) { desired_size += strlen(*alias) + 1; ++aliases_size; } desired_size += _ALIGNBYTES + sizeof(char *) * (aliases_size + 1); } if (*buffer_size < desired_size) { /* this assignment is here for future use */ *buffer_size = desired_size; return (NS_RETURN); } memcpy(&new_serv, serv, sizeof(struct servent)); memset(buffer, 0, desired_size); *buffer_size = desired_size; p = buffer + sizeof(struct servent) + sizeof(char *); memcpy(buffer + sizeof(struct servent), &p, sizeof(char *)); p = (char *)_ALIGN(p); if (new_serv.s_name != NULL) { size = strlen(new_serv.s_name); memcpy(p, new_serv.s_name, size); new_serv.s_name = p; p += size + 1; } if (new_serv.s_proto != NULL) { size = strlen(new_serv.s_proto); memcpy(p, new_serv.s_proto, size); new_serv.s_proto = p; p += size + 1; } if (new_serv.s_aliases != NULL) { p = (char *)_ALIGN(p); memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size); new_serv.s_aliases = (char **)p; p += sizeof(char *) * (aliases_size + 1); for (alias = new_serv.s_aliases; *alias; ++alias) { size = strlen(*alias); memcpy(p, *alias, size); *alias = p; p += size + 1; } } memcpy(buffer, &new_serv, sizeof(struct servent)); return (NS_SUCCESS); } int serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, void *cache_mdata) { char *name; char *proto; int port; struct servent *serv; char *orig_buf; char *p; char **alias; size_t orig_buf_size; int *ret_errno; switch ((enum nss_lookup_type)cache_mdata) { case nss_lt_name: name = va_arg(ap, char *); proto = va_arg(ap, char *); break; case nss_lt_id: port = va_arg(ap, int); proto = va_arg(ap, char *); break; case nss_lt_all: break; default: /* should be unreachable */ return (NS_UNAVAIL); } serv = va_arg(ap, struct servent *); orig_buf = va_arg(ap, char *); orig_buf_size = va_arg(ap, size_t); ret_errno = va_arg(ap, int *); if (orig_buf_size < buffer_size - sizeof(struct servent) - sizeof(char *)) { *ret_errno = ERANGE; return (NS_RETURN); } memcpy(serv, buffer, sizeof(struct servent)); memcpy(&p, buffer + sizeof(struct servent), sizeof(char *)); orig_buf = (char *)_ALIGN(orig_buf); memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) + (_ALIGN(p) - (size_t)p), buffer_size - sizeof(struct servent) - sizeof(char *) - (_ALIGN(p) - (size_t)p)); p = (char *)_ALIGN(p); NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *); NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *); if (serv->s_aliases != NULL) { NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **); for (alias = serv->s_aliases; *alias; ++alias) NS_APPLY_OFFSET(*alias, orig_buf, p, char *); } if (retval != NULL) *((struct servent **)retval) = serv; return (NS_SUCCESS); } NSS_MP_CACHE_HANDLING(services); #endif /* NS_CACHING */ /* get**_r functions implementation */ int getservbyname_r(const char *name, const char *proto, struct servent *serv, char *buffer, size_t bufsize, struct servent **result) { static const struct servent_mdata mdata = { nss_lt_name, 0 }; static const struct servent_mdata compat_mdata = { nss_lt_name, 1 }; #ifdef NS_CACHING static const nss_cache_info cache_info = NS_COMMON_CACHE_INFO_INITIALIZER( services, (void *)nss_lt_name, serv_id_func, serv_marshal_func, serv_unmarshal_func); #endif /* NS_CACHING */ static const ns_dtab dtab[] = { { NSSRC_FILES, files_servent, (void *)&mdata }, { NSSRC_DB, db_servent, (void *)nss_lt_name }, #ifdef YP { NSSRC_NIS, nis_servent, (void *)nss_lt_name }, #endif { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r", defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } int getservbyport_r(int port, const char *proto, struct servent *serv, char *buffer, size_t bufsize, struct servent **result) { static const struct servent_mdata mdata = { nss_lt_id, 0 }; static const struct servent_mdata compat_mdata = { nss_lt_id, 1 }; #ifdef NS_CACHING static const nss_cache_info cache_info = NS_COMMON_CACHE_INFO_INITIALIZER( services, (void *)nss_lt_id, serv_id_func, serv_marshal_func, serv_unmarshal_func); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_servent, (void *)&mdata }, { NSSRC_DB, db_servent, (void *)nss_lt_id }, #ifdef YP { NSSRC_NIS, nis_servent, (void *)nss_lt_id }, #endif { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r", defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } int getservent_r(struct servent *serv, char *buffer, size_t bufsize, struct servent **result) { static const struct servent_mdata mdata = { nss_lt_all, 0 }; static const struct servent_mdata compat_mdata = { nss_lt_all, 1 }; #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( services, (void *)nss_lt_all, serv_marshal_func, serv_unmarshal_func); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_servent, (void *)&mdata }, { NSSRC_DB, db_servent, (void *)nss_lt_all }, #ifdef YP { NSSRC_NIS, nis_servent, (void *)nss_lt_all }, #endif { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r", defaultsrc, serv, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } void setservent(int stayopen) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( services, (void *)nss_lt_all, NULL, NULL); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_setservent, (void *)SETSERVENT }, { NSSRC_DB, db_setservent, (void *)SETSERVENT }, #ifdef YP { NSSRC_NIS, nis_setservent, (void *)SETSERVENT }, #endif { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT }, #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc, stayopen); } void endservent(void) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( services, (void *)nss_lt_all, NULL, NULL); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_setservent, (void *)ENDSERVENT }, { NSSRC_DB, db_setservent, (void *)ENDSERVENT }, #ifdef YP { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT }, #endif { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT }, #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc); } /* get** wrappers for get**_r functions implementation */ static void servent_endstate(void *p) { if (p == NULL) return; free(((struct servent_state *)p)->buffer); free(p); } static int wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer, size_t bufsize, struct servent **res) { return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize, res)); } static int wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer, size_t bufsize, struct servent **res) { return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize, res)); } static int wrap_getservent_r(struct key key, struct servent *serv, char *buffer, size_t bufsize, struct servent **res) { return (getservent_r(serv, buffer, bufsize, res)); } static struct servent * getserv(int (*fn)(struct key, struct servent *, char *, size_t, struct servent **), struct key key) { int rv; struct servent *res; struct servent_state * st; rv = servent_getstate(&st); if (rv != 0) { errno = rv; return NULL; } if (st->buffer == NULL) { st->buffer = malloc(SERVENT_STORAGE_INITIAL); if (st->buffer == NULL) return (NULL); st->bufsize = SERVENT_STORAGE_INITIAL; } do { rv = fn(key, &st->serv, st->buffer, st->bufsize, &res); if (res == NULL && rv == ERANGE) { free(st->buffer); if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) { st->buffer = NULL; errno = ERANGE; return (NULL); } st->bufsize <<= 1; st->buffer = malloc(st->bufsize); if (st->buffer == NULL) return (NULL); } } while (res == NULL && rv == ERANGE); if (rv != 0) errno = rv; return (res); } struct servent * getservbyname(const char *name, const char *proto) { struct key key; key.name = name; key.proto = proto; return (getserv(wrap_getservbyname_r, key)); } struct servent * getservbyport(int port, const char *proto) { struct key key; key.port = port; key.proto = proto; return (getserv(wrap_getservbyport_r, key)); } struct servent * getservent(void) { struct key key; key.proto = NULL; key.port = 0; return (getserv(wrap_getservent_r, key)); } Index: head/lib/libc/rpc/getrpcent.c =================================================================== --- head/lib/libc/rpc/getrpcent.c (revision 350956) +++ head/lib/libc/rpc/getrpcent.c (revision 350957) @@ -1,1049 +1,1057 @@ /* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2009, Sun Microsystems, 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: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of Sun Microsystems, 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 COPYRIGHT HOLDER 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. */ #if defined(LIBC_SCCS) && !defined(lint) static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro"; #endif #include __FBSDID("$FreeBSD$"); /* * Copyright (c) 1984 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef YP #include #include #endif #include #include "namespace.h" #include "reentrant.h" #include "un-namespace.h" #include "libc_private.h" #include "nss_tls.h" #ifdef NS_CACHING #include "nscache.h" #endif #define RPCDB "/etc/rpc" /* nsswitch declarations */ enum constants { SETRPCENT = 1, ENDRPCENT = 2, RPCENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ RPCENT_STORAGE_MAX = 1 << 20, /* 1 MByte */ }; static const ns_src defaultsrc[] = { { NSSRC_FILES, NS_SUCCESS }, #ifdef YP { NSSRC_NIS, NS_SUCCESS }, #endif { NULL, 0 } }; /* files backend declarations */ struct files_state { FILE *fp; int stayopen; }; static int files_rpcent(void *, void *, va_list); static int files_setrpcent(void *, void *, va_list); static void files_endstate(void *); NSS_TLS_HANDLING(files); /* nis backend declarations */ #ifdef YP struct nis_state { char domain[MAXHOSTNAMELEN]; char *current; int currentlen; int stepping; int no_name_map; }; static int nis_rpcent(void *, void *, va_list); static int nis_setrpcent(void *, void *, va_list); static void nis_endstate(void *); NSS_TLS_HANDLING(nis); #endif /* get** wrappers for get**_r functions declarations */ struct rpcent_state { struct rpcent rpc; char *buffer; size_t bufsize; }; static void rpcent_endstate(void *); NSS_TLS_HANDLING(rpcent); union key { const char *name; int number; }; static int wrap_getrpcbyname_r(union key, struct rpcent *, char *, size_t, struct rpcent **); static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *, size_t, struct rpcent **); static int wrap_getrpcent_r(union key, struct rpcent *, char *, size_t, struct rpcent **); static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **), union key); #ifdef NS_CACHING static int rpc_id_func(char *, size_t *, va_list, void *); static int rpc_marshal_func(char *, size_t *, void *, va_list, void *); static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *); #endif static int rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases, size_t aliases_size, int *errnop) { char *cp, **q; assert(p != NULL); if (*p == '#') return (-1); cp = strpbrk(p, "#\n"); if (cp == NULL) return (-1); *cp = '\0'; cp = strpbrk(p, " \t"); if (cp == NULL) return (-1); *cp++ = '\0'; /* THIS STUFF IS INTERNET SPECIFIC */ rpc->r_name = p; while (*cp == ' ' || *cp == '\t') cp++; rpc->r_number = atoi(cp); q = rpc->r_aliases = r_aliases; cp = strpbrk(cp, " \t"); if (cp != NULL) *cp++ = '\0'; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } if (q < &(r_aliases[aliases_size - 1])) *q++ = cp; else { *errnop = ERANGE; return -1; } cp = strpbrk(cp, " \t"); if (cp != NULL) *cp++ = '\0'; } *q = NULL; return 0; } /* files backend implementation */ static void files_endstate(void *p) { FILE * f; if (p == NULL) return; f = ((struct files_state *)p)->fp; if (f != NULL) fclose(f); free(p); } static int files_rpcent(void *retval, void *mdata, va_list ap) { char *name; int number; struct rpcent *rpc; char *buffer; size_t bufsize; int *errnop; char *line; size_t linesize; char **aliases; int aliases_size; char **rp; struct files_state *st; int rv; int stayopen; enum nss_lookup_type how; how = (enum nss_lookup_type)mdata; switch (how) { case nss_lt_name: name = va_arg(ap, char *); break; case nss_lt_id: number = va_arg(ap, int); break; case nss_lt_all: break; default: return (NS_NOTFOUND); } rpc = va_arg(ap, struct rpcent *); buffer = va_arg(ap, char *); bufsize = va_arg(ap, size_t); errnop = va_arg(ap, int *); *errnop = files_getstate(&st); if (*errnop != 0) return (NS_UNAVAIL); if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) { *errnop = errno; return (NS_UNAVAIL); } if (how == nss_lt_all) stayopen = 1; else { rewind(st->fp); stayopen = st->stayopen; } do { if ((line = fgetln(st->fp, &linesize)) == NULL) { *errnop = errno; rv = NS_RETURN; break; } if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { *errnop = ERANGE; rv = NS_RETURN; break; } aliases = (char **)_ALIGN(&buffer[linesize+1]); aliases_size = (buffer + bufsize - (char *)aliases)/sizeof(char *); if (aliases_size < 1) { *errnop = ERANGE; rv = NS_RETURN; break; } memcpy(buffer, line, linesize); buffer[linesize] = '\0'; rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop); if (rv != 0) { if (*errnop == 0) { rv = NS_NOTFOUND; continue; } else { rv = NS_RETURN; break; } } switch (how) { case nss_lt_name: if (strcmp(rpc->r_name, name) == 0) goto done; for (rp = rpc->r_aliases; *rp != NULL; rp++) { if (strcmp(*rp, name) == 0) goto done; } rv = NS_NOTFOUND; continue; done: rv = NS_SUCCESS; break; case nss_lt_id: rv = (rpc->r_number == number) ? NS_SUCCESS : NS_NOTFOUND; break; case nss_lt_all: rv = NS_SUCCESS; break; } } while (!(rv & NS_TERMINATE)); if (!stayopen && st->fp!=NULL) { fclose(st->fp); st->fp = NULL; } if ((rv == NS_SUCCESS) && (retval != NULL)) *((struct rpcent **)retval) = rpc; return (rv); } static int files_setrpcent(void *retval, void *mdata, va_list ap) { struct files_state *st; int rv; int f; rv = files_getstate(&st); if (rv != 0) return (NS_UNAVAIL); switch ((enum constants)mdata) { case SETRPCENT: f = va_arg(ap,int); if (st->fp == NULL) st->fp = fopen(RPCDB, "r"); else rewind(st->fp); st->stayopen |= f; break; case ENDRPCENT: if (st->fp != NULL) { fclose(st->fp); st->fp = NULL; } st->stayopen = 0; break; default: break; } return (NS_UNAVAIL); } /* nis backend implementation */ #ifdef YP static void nis_endstate(void *p) { if (p == NULL) return; free(((struct nis_state *)p)->current); free(p); } static int nis_rpcent(void *retval, void *mdata, va_list ap) { char *name; int number; struct rpcent *rpc; char *buffer; size_t bufsize; int *errnop; char **rp; char **aliases; int aliases_size; char *lastkey; char *resultbuf; int resultbuflen; - char buf[YPMAXRECORD + 2]; + char *buf; struct nis_state *st; int rv; enum nss_lookup_type how; int no_name_active; how = (enum nss_lookup_type)mdata; switch (how) { case nss_lt_name: name = va_arg(ap, char *); break; case nss_lt_id: number = va_arg(ap, int); break; case nss_lt_all: break; default: return (NS_NOTFOUND); } + buf = NULL; rpc = va_arg(ap, struct rpcent *); buffer = va_arg(ap, char *); bufsize = va_arg(ap, size_t); errnop = va_arg(ap, int *); *errnop = nis_getstate(&st); if (*errnop != 0) return (NS_UNAVAIL); if (st->domain[0] == '\0') { if (getdomainname(st->domain, sizeof(st->domain)) != 0) { *errnop = errno; return (NS_UNAVAIL); } } no_name_active = 0; do { switch (how) { case nss_lt_name: if (!st->no_name_map) { - snprintf(buf, sizeof buf, "%s", name); + free(buf); + asprintf(&buf, "%s", name); + if (buf == NULL) + return (NS_TRYAGAIN); rv = yp_match(st->domain, "rpc.byname", buf, strlen(buf), &resultbuf, &resultbuflen); switch (rv) { case 0: break; case YPERR_MAP: st->stepping = 0; no_name_active = 1; how = nss_lt_all; rv = NS_NOTFOUND; continue; default: rv = NS_NOTFOUND; goto fin; } } else { st->stepping = 0; no_name_active = 1; how = nss_lt_all; rv = NS_NOTFOUND; continue; } break; case nss_lt_id: - snprintf(buf, sizeof buf, "%d", number); + free(buf); + asprintf(&buf, "%d", number); + if (buf == NULL) + return (NS_TRYAGAIN); if (yp_match(st->domain, "rpc.bynumber", buf, strlen(buf), &resultbuf, &resultbuflen)) { rv = NS_NOTFOUND; goto fin; } break; case nss_lt_all: if (!st->stepping) { rv = yp_first(st->domain, "rpc.bynumber", &st->current, &st->currentlen, &resultbuf, &resultbuflen); if (rv) { rv = NS_NOTFOUND; goto fin; } st->stepping = 1; } else { lastkey = st->current; rv = yp_next(st->domain, "rpc.bynumber", st->current, st->currentlen, &st->current, &st->currentlen, &resultbuf, &resultbuflen); free(lastkey); if (rv) { st->stepping = 0; rv = NS_NOTFOUND; goto fin; } } break; } /* we need a room for additional \n symbol */ if (bufsize <= resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) { *errnop = ERANGE; rv = NS_RETURN; free(resultbuf); break; } aliases=(char **)_ALIGN(&buffer[resultbuflen+2]); aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *); if (aliases_size < 1) { *errnop = ERANGE; rv = NS_RETURN; free(resultbuf); break; } /* * rpcent_unpack expects lines terminated with \n -- make it happy */ memcpy(buffer, resultbuf, resultbuflen); buffer[resultbuflen] = '\n'; buffer[resultbuflen+1] = '\0'; free(resultbuf); if (rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop) != 0) { if (*errnop == 0) rv = NS_NOTFOUND; else rv = NS_RETURN; } else { if ((how == nss_lt_all) && (no_name_active != 0)) { if (strcmp(rpc->r_name, name) == 0) goto done; for (rp = rpc->r_aliases; *rp != NULL; rp++) { if (strcmp(*rp, name) == 0) goto done; } rv = NS_NOTFOUND; continue; done: rv = NS_SUCCESS; } else rv = NS_SUCCESS; } } while (!(rv & NS_TERMINATE) && (how == nss_lt_all)); fin: + free(buf); if ((rv == NS_SUCCESS) && (retval != NULL)) *((struct rpcent **)retval) = rpc; return (rv); } static int nis_setrpcent(void *retval, void *mdata, va_list ap) { struct nis_state *st; int rv; rv = nis_getstate(&st); if (rv != 0) return (NS_UNAVAIL); switch ((enum constants)mdata) { case SETRPCENT: case ENDRPCENT: free(st->current); st->current = NULL; st->stepping = 0; break; default: break; } return (NS_UNAVAIL); } #endif #ifdef NS_CACHING static int rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) { char *name; int rpc; size_t desired_size, size; enum nss_lookup_type lookup_type; int res = NS_UNAVAIL; lookup_type = (enum nss_lookup_type)cache_mdata; switch (lookup_type) { case nss_lt_name: name = va_arg(ap, char *); size = strlen(name); desired_size = sizeof(enum nss_lookup_type) + size + 1; if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); res = NS_SUCCESS; break; case nss_lt_id: rpc = va_arg(ap, int); desired_size = sizeof(enum nss_lookup_type) + sizeof(int); if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); memcpy(buffer + sizeof(enum nss_lookup_type), &rpc, sizeof(int)); res = NS_SUCCESS; break; default: /* should be unreachable */ return (NS_UNAVAIL); } fin: *buffer_size = desired_size; return (res); } static int rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, void *cache_mdata) { char *name; int num; struct rpcent *rpc; char *orig_buf; size_t orig_buf_size; struct rpcent new_rpc; size_t desired_size, size, aliases_size; char *p; char **alias; switch ((enum nss_lookup_type)cache_mdata) { case nss_lt_name: name = va_arg(ap, char *); break; case nss_lt_id: num = va_arg(ap, int); break; case nss_lt_all: break; default: /* should be unreachable */ return (NS_UNAVAIL); } rpc = va_arg(ap, struct rpcent *); orig_buf = va_arg(ap, char *); orig_buf_size = va_arg(ap, size_t); desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *); if (rpc->r_name != NULL) desired_size += strlen(rpc->r_name) + 1; if (rpc->r_aliases != NULL) { aliases_size = 0; for (alias = rpc->r_aliases; *alias; ++alias) { desired_size += strlen(*alias) + 1; ++aliases_size; } desired_size += _ALIGNBYTES + (aliases_size + 1) * sizeof(char *); } if (*buffer_size < desired_size) { /* this assignment is here for future use */ *buffer_size = desired_size; return (NS_RETURN); } new_rpc = *rpc; *buffer_size = desired_size; memset(buffer, 0, desired_size); p = buffer + sizeof(struct rpcent) + sizeof(char *); memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *)); p = (char *)_ALIGN(p); if (new_rpc.r_name != NULL) { size = strlen(new_rpc.r_name); memcpy(p, new_rpc.r_name, size); new_rpc.r_name = p; p += size + 1; } if (new_rpc.r_aliases != NULL) { p = (char *)_ALIGN(p); memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size); new_rpc.r_aliases = (char **)p; p += sizeof(char *) * (aliases_size + 1); for (alias = new_rpc.r_aliases; *alias; ++alias) { size = strlen(*alias); memcpy(p, *alias, size); *alias = p; p += size + 1; } } memcpy(buffer, &new_rpc, sizeof(struct rpcent)); return (NS_SUCCESS); } static int rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, void *cache_mdata) { char *name; int num; struct rpcent *rpc; char *orig_buf; size_t orig_buf_size; int *ret_errno; char *p; char **alias; switch ((enum nss_lookup_type)cache_mdata) { case nss_lt_name: name = va_arg(ap, char *); break; case nss_lt_id: num = va_arg(ap, int); break; case nss_lt_all: break; default: /* should be unreachable */ return (NS_UNAVAIL); } rpc = va_arg(ap, struct rpcent *); orig_buf = va_arg(ap, char *); orig_buf_size = va_arg(ap, size_t); ret_errno = va_arg(ap, int *); if (orig_buf_size < buffer_size - sizeof(struct rpcent) - sizeof(char *)) { *ret_errno = ERANGE; return (NS_RETURN); } memcpy(rpc, buffer, sizeof(struct rpcent)); memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *)); orig_buf = (char *)_ALIGN(orig_buf); memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) + _ALIGN(p) - (size_t)p, buffer_size - sizeof(struct rpcent) - sizeof(char *) - _ALIGN(p) + (size_t)p); p = (char *)_ALIGN(p); NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *); if (rpc->r_aliases != NULL) { NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **); for (alias = rpc->r_aliases ; *alias; ++alias) NS_APPLY_OFFSET(*alias, orig_buf, p, char *); } if (retval != NULL) *((struct rpcent **)retval) = rpc; return (NS_SUCCESS); } NSS_MP_CACHE_HANDLING(rpc); #endif /* NS_CACHING */ /* get**_r functions implementation */ static int getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **result) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_COMMON_CACHE_INFO_INITIALIZER( rpc, (void *)nss_lt_name, rpc_id_func, rpc_marshal_func, rpc_unmarshal_func); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_rpcent, (void *)nss_lt_name }, #ifdef YP { NSSRC_NIS, nis_rpcent, (void *)nss_lt_name }, #endif #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc, name, rpc, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } static int getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **result) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_COMMON_CACHE_INFO_INITIALIZER( rpc, (void *)nss_lt_id, rpc_id_func, rpc_marshal_func, rpc_unmarshal_func); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_rpcent, (void *)nss_lt_id }, #ifdef YP { NSSRC_NIS, nis_rpcent, (void *)nss_lt_id }, #endif #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc, number, rpc, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } static int getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **result) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( rpc, (void *)nss_lt_all, rpc_marshal_func, rpc_unmarshal_func); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_rpcent, (void *)nss_lt_all }, #ifdef YP { NSSRC_NIS, nis_rpcent, (void *)nss_lt_all }, #endif #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; int rv, ret_errno; ret_errno = 0; *result = NULL; rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc, rpc, buffer, bufsize, &ret_errno); if (rv == NS_SUCCESS) return (0); else return (ret_errno); } /* get** wrappers for get**_r functions implementation */ static void rpcent_endstate(void *p) { if (p == NULL) return; free(((struct rpcent_state *)p)->buffer); free(p); } static int wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **res) { return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res)); } static int wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **res) { return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res)); } static int wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer, size_t bufsize, struct rpcent **res) { return (getrpcent_r(rpc, buffer, bufsize, res)); } static struct rpcent * getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **), union key key) { int rv; struct rpcent *res; struct rpcent_state * st; rv=rpcent_getstate(&st); if (rv != 0) { errno = rv; return NULL; } if (st->buffer == NULL) { st->buffer = malloc(RPCENT_STORAGE_INITIAL); if (st->buffer == NULL) return (NULL); st->bufsize = RPCENT_STORAGE_INITIAL; } do { rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res); if (res == NULL && rv == ERANGE) { free(st->buffer); if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) { st->buffer = NULL; errno = ERANGE; return (NULL); } st->bufsize <<= 1; st->buffer = malloc(st->bufsize); if (st->buffer == NULL) return (NULL); } } while (res == NULL && rv == ERANGE); if (rv != 0) errno = rv; return (res); } struct rpcent * getrpcbyname(const char *name) { union key key; key.name = name; return (getrpc(wrap_getrpcbyname_r, key)); } struct rpcent * getrpcbynumber(int number) { union key key; key.number = number; return (getrpc(wrap_getrpcbynumber_r, key)); } struct rpcent * getrpcent(void) { union key key; key.number = 0; /* not used */ return (getrpc(wrap_getrpcent_r, key)); } void setrpcent(int stayopen) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( rpc, (void *)nss_lt_all, NULL, NULL); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_setrpcent, (void *)SETRPCENT }, #ifdef YP { NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT }, #endif #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; (void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc, stayopen); } void endrpcent(void) { #ifdef NS_CACHING static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( rpc, (void *)nss_lt_all, NULL, NULL); #endif static const ns_dtab dtab[] = { { NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT }, #ifdef YP { NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT }, #endif #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { NULL, NULL, NULL } }; (void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc); } Index: head/usr.sbin/rpc.yppasswdd/yppasswdd_server.c =================================================================== --- head/usr.sbin/rpc.yppasswdd/yppasswdd_server.c (revision 350956) +++ head/usr.sbin/rpc.yppasswdd/yppasswdd_server.c (revision 350957) @@ -1,934 +1,949 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995, 1996 * Bill Paul . 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 Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct dom_binding; #include #include "yppasswdd_extern.h" #include "yppasswd.h" #include "yppasswd_private.h" #include "ypxfr_extern.h" #include "yp_extern.h" static struct passwd yp_password; static void xlate_passwd(struct x_master_passwd *xpwd, struct passwd *pwd) { pwd->pw_name = xpwd->pw_name; pwd->pw_passwd = xpwd->pw_passwd; pwd->pw_uid = xpwd->pw_uid; pwd->pw_gid = xpwd->pw_gid; pwd->pw_change = xpwd->pw_change; pwd->pw_class = xpwd->pw_class; pwd->pw_gecos = xpwd->pw_gecos; pwd->pw_dir = xpwd->pw_dir; pwd->pw_shell = xpwd->pw_shell; pwd->pw_expire = xpwd->pw_expire; pwd->pw_fields = xpwd->pw_fields; } static void copy_yp_pass(char *p, int x, int m) { char *t, *s = p; static char *buf; yp_password.pw_fields = 0; buf = realloc(buf, m + 10); bzero(buf, m + 10); /* Turn all colons into NULLs */ while (strchr(s, ':')) { s = (strchr(s, ':') + 1); *(s - 1)= '\0'; } t = buf; #define EXPAND(e) do { \ e = t; \ while ((*t++ = *p++)); \ } while (0) EXPAND(yp_password.pw_name); yp_password.pw_fields |= _PWF_NAME; EXPAND(yp_password.pw_passwd); yp_password.pw_fields |= _PWF_PASSWD; yp_password.pw_uid = atoi(p); p += (strlen(p) + 1); yp_password.pw_fields |= _PWF_UID; yp_password.pw_gid = atoi(p); p += (strlen(p) + 1); yp_password.pw_fields |= _PWF_GID; if (x) { EXPAND(yp_password.pw_class); yp_password.pw_fields |= _PWF_CLASS; yp_password.pw_change = atol(p); p += (strlen(p) + 1); yp_password.pw_fields |= _PWF_CHANGE; yp_password.pw_expire = atol(p); p += (strlen(p) + 1); yp_password.pw_fields |= _PWF_EXPIRE; } EXPAND(yp_password.pw_gecos); yp_password.pw_fields |= _PWF_GECOS; EXPAND(yp_password.pw_dir); yp_password.pw_fields |= _PWF_DIR; EXPAND(yp_password.pw_shell); yp_password.pw_fields |= _PWF_SHELL; return; } static int validchars(char *arg) { size_t i; for (i = 0; i < strlen(arg); i++) { if (iscntrl(arg[i])) { yp_error("string contains a control character"); return(1); } if (arg[i] == ':') { yp_error("string contains a colon"); return(1); } /* Be evil: truncate strings with \n in them silently. */ if (arg[i] == '\n') { arg[i] = '\0'; return(0); } } return(0); } static int validate_master(struct passwd *opw __unused, struct x_master_passwd *npw) { if (npw->pw_name[0] == '+' || npw->pw_name[0] == '-') { yp_error("client tried to modify an NIS entry"); return(1); } if (validchars(npw->pw_shell)) { yp_error("specified shell contains invalid characters"); return(1); } if (validchars(npw->pw_gecos)) { yp_error("specified gecos field contains invalid characters"); return(1); } if (validchars(npw->pw_passwd)) { yp_error("specified password contains invalid characters"); return(1); } return(0); } static int validate(struct passwd *opw, struct x_passwd *npw) { if (npw->pw_name[0] == '+' || npw->pw_name[0] == '-') { yp_error("client tried to modify an NIS entry"); return(1); } if ((uid_t)npw->pw_uid != opw->pw_uid) { yp_error("UID mismatch: client says user %s has UID %d", npw->pw_name, npw->pw_uid); yp_error("database says user %s has UID %d", opw->pw_name, opw->pw_uid); return(1); } if ((gid_t)npw->pw_gid != opw->pw_gid) { yp_error("GID mismatch: client says user %s has GID %d", npw->pw_name, npw->pw_gid); yp_error("database says user %s has GID %d", opw->pw_name, opw->pw_gid); return(1); } /* * Don't allow the user to shoot himself in the foot, * even on purpose. */ if (!no_chsh && !ok_shell(npw->pw_shell)) { yp_error("%s is not a valid shell", npw->pw_shell); return(1); } if (!no_chsh && validchars(npw->pw_shell)) { yp_error("specified shell contains invalid characters"); return(1); } if (validchars(npw->pw_gecos)) { yp_error("specified gecos field contains invalid characters"); return(1); } if (validchars(npw->pw_passwd)) { yp_error("specified password contains invalid characters"); return(1); } return(0); } /* * Kludge alert: * In order to have one rpc.yppasswdd support multiple domains, * we have to cheat: we search each directory under /var/yp * and try to match the user in each master.passwd.byname * map that we find. If the user matches (username, uid and gid * all agree), then we use that domain. If we match the user in * more than one database, we must abort. */ static char * find_domain(struct x_passwd *pw) { struct stat statbuf; struct dirent *dirp; DIR *dird; char yp_mapdir[MAXPATHLEN + 2]; static char domain[YPMAXDOMAIN]; char *tmp = NULL; DBT key, data; int hit = 0; yp_error("performing multidomain lookup"); if ((dird = opendir(yp_dir)) == NULL) { yp_error("opendir(%s) failed: %s", yp_dir, strerror(errno)); return(NULL); } while ((dirp = readdir(dird)) != NULL) { snprintf(yp_mapdir, sizeof yp_mapdir, "%s/%s", yp_dir, dirp->d_name); if (stat(yp_mapdir, &statbuf) < 0) { yp_error("stat(%s) failed: %s", yp_mapdir, strerror(errno)); closedir(dird); return(NULL); } if (S_ISDIR(statbuf.st_mode)) { tmp = (char *)dirp->d_name; key.data = pw->pw_name; key.size = strlen(pw->pw_name); if (yp_get_record(tmp,"master.passwd.byname", &key, &data, 0) != YP_TRUE) { continue; } *((char *)data.data + data.size) = '\0'; copy_yp_pass(data.data, 1, data.size); if (yp_password.pw_uid == (uid_t)pw->pw_uid && yp_password.pw_gid == (gid_t)pw->pw_gid) { hit++; snprintf(domain, YPMAXDOMAIN, "%s", tmp); } } } closedir(dird); if (hit > 1) { yp_error("found same user in two different domains"); return(NULL); } else return((char *)&domain); } static const char *maps[] = { "master.passwd.byname", "master.passwd.byuid", "passwd.byname", "passwd.byuid" }; static const char *formats[] = { "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", "%s:%s:%d:%d:%s:%s:%s", "%s:%s:%d:%d:%s:%s:%s" }; static int update_inplace(struct passwd *pw, char *domain) { DB *dbp = NULL; DBT key = { NULL, 0 }; DBT data = { NULL, 0 }; - char pwbuf[YPMAXRECORD]; + char *pwbuf; char keybuf[20]; int i; char *ptr = NULL; static char yp_last[] = "YP_LAST_MODIFIED"; - char yplastbuf[YPMAXRECORD]; + char yplastbuf[64]; snprintf(yplastbuf, sizeof yplastbuf, "%llu", (unsigned long long)time(NULL)); + pwbuf = NULL; for (i = 0; i < 4; i++) { if (i % 2) { snprintf(keybuf, sizeof keybuf, "%llu", (unsigned long long)pw->pw_uid); key.data = &keybuf; key.size = strlen(keybuf); } else { key.data = pw->pw_name; key.size = strlen(pw->pw_name); } /* * XXX The passwd.byname and passwd.byuid maps come in * two flavors: secure and insecure. The secure version * has a '*' in the password field whereas the insecure one * has a real crypted password. The maps will be insecure * if they were built with 'unsecure = TRUE' enabled in * /var/yp/Makefile, but we'd have no way of knowing if * this has been done unless we were to try parsing the * Makefile, which is a disgusting thought. Instead, we * read the records from the maps, skip to the first ':' * in them, and then look at the character immediately * following it. If it's an '*' then the map is 'secure' * and we must not insert a real password into the pw_passwd * field. If it's not an '*', then we put the real crypted * password in. */ if (yp_get_record(domain,maps[i],&key,&data,1) != YP_TRUE) { yp_error("couldn't read %s/%s: %s", domain, maps[i], strerror(errno)); - return(1); + goto ret1; } if ((ptr = strchr(data.data, ':')) == NULL) { yp_error("no colon in passwd record?!"); - return(1); + goto ret1; } /* * XXX Supposing we have more than one user with the same * UID? (Or more than one user with the same name?) We could * end up modifying the wrong record if were not careful. */ if (i % 2) { if (strncmp(data.data, pw->pw_name, strlen(pw->pw_name))) { yp_error("warning: found entry for UID %d \ in map %s@%s with wrong name (%.*s)", pw->pw_uid, maps[i], domain, (int)(ptr - (char *)data.data), (char *)data.data); yp_error("there may be more than one user \ with the same UID - continuing"); continue; } } else { /* * We're really being ultra-paranoid here. * This is generally a 'can't happen' condition. */ - snprintf(pwbuf, sizeof pwbuf, ":%d:%d:", pw->pw_uid, - pw->pw_gid); + free(pwbuf); + asprintf(&pwbuf, ":%d:%d:", pw->pw_uid, pw->pw_gid); + if (pwbuf == NULL) { + yp_error("no memory"); + goto ret1; + } if (!strstr(data.data, pwbuf)) { yp_error("warning: found entry for user %s \ in map %s@%s with wrong UID", pw->pw_name, maps[i], domain); yp_error("there may be more than one user \ with the same name - continuing"); continue; } } if (i < 2) { - snprintf(pwbuf, sizeof pwbuf, formats[i], + free(pwbuf); + asprintf(&pwbuf, formats[i], pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir, pw->pw_shell); } else { - snprintf(pwbuf, sizeof pwbuf, formats[i], + free(pwbuf); + asprintf(&pwbuf, formats[i], pw->pw_name, *(ptr+1) == '*' ? "*" : pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell); } + if (pwbuf == NULL) { + yp_error("no memory"); + goto ret1; + } #define FLAGS O_RDWR|O_CREAT if ((dbp = yp_open_db_rw(domain, maps[i], FLAGS)) == NULL) { yp_error("couldn't open %s/%s r/w: %s",domain, maps[i],strerror(errno)); - return(1); + goto ret1; } data.data = pwbuf; data.size = strlen(pwbuf); if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) { yp_error("failed to update record in %s/%s", domain, maps[i]); (void)(dbp->close)(dbp); - return(1); + goto ret1; } key.data = yp_last; key.size = strlen(yp_last); data.data = (char *)&yplastbuf; data.size = strlen(yplastbuf); if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) { yp_error("failed to update timestamp in %s/%s", domain, maps[i]); (void)(dbp->close)(dbp); - return(1); + goto ret1; } (void)(dbp->close)(dbp); } - return(0); + free(pwbuf); + return (0); +ret1: + free(pwbuf); + return (1); } int * yppasswdproc_update_1_svc(yppasswd *argp, struct svc_req *rqstp) { static int result; struct sockaddr_in *rqhost; DBT key, data; int rval = 0; int pfd, tfd; int pid; int passwd_changed = 0; int shell_changed = 0; int gecos_changed = 0; char *cryptpw; char *oldshell = NULL; char *oldgecos = NULL; char *passdir; char *passfile_hold; char passdir_buf[MAXPATHLEN + 2]; char passfile_buf[MAXPATHLEN + 2]; char passfile_hold_buf[MAXPATHLEN + 2]; char *domain = yppasswd_domain; static struct sockaddr_in clntaddr; static struct timeval t_saved, t_test; /* * Normal user updates always use the 'default' master.passwd file. */ passfile = passfile_default; result = 1; rqhost = svc_getcaller(rqstp->rq_xprt); gettimeofday(&t_test, NULL); if (!bcmp(rqhost, &clntaddr, sizeof *rqhost) && t_test.tv_sec > t_saved.tv_sec && t_test.tv_sec - t_saved.tv_sec < 300) { bzero(&clntaddr, sizeof clntaddr); bzero(&t_saved, sizeof t_saved); return(NULL); } bcopy(rqhost, &clntaddr, sizeof clntaddr); gettimeofday(&t_saved, NULL); if (yp_access(resvport ? "master.passwd.byname" : NULL, rqstp)) { yp_error("rejected update request from unauthorized host"); svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED); return(&result); } /* * Step one: find the user. (It's kinda pointless to * proceed if the user doesn't exist.) We look for the * user in the master.passwd.byname database, _NOT_ by * using getpwent() and friends! We can't use getpwent() * since the NIS master server is not guaranteed to be * configured as an NIS client. */ if (multidomain) { if ((domain = find_domain(&argp->newpw)) == NULL) { yp_error("multidomain lookup failed - aborting update"); return(&result); } else yp_error("updating user %s in domain %s", argp->newpw.pw_name, domain); } key.data = argp->newpw.pw_name; key.size = strlen(argp->newpw.pw_name); if ((rval = yp_get_record(domain,"master.passwd.byname", &key, &data, 0)) != YP_TRUE) { if (rval == YP_NOKEY) { yp_error("user %s not found in passwd database", argp->newpw.pw_name); } else { yp_error("database access error: %s", yperr_string(rval)); } return(&result); } /* Nul terminate, please. */ *((char *)data.data + data.size) = '\0'; copy_yp_pass(data.data, 1, data.size); /* Step 2: check that the supplied oldpass is valid. */ cryptpw = crypt(argp->oldpass, yp_password.pw_passwd); if (cryptpw == NULL || strcmp(cryptpw, yp_password.pw_passwd)) { yp_error("rejected change attempt -- bad password"); yp_error("client address: %s username: %s", inet_ntoa(rqhost->sin_addr), argp->newpw.pw_name); return(&result); } /* Step 3: validate the arguments passed to us by the client. */ if (validate(&yp_password, &argp->newpw)) { yp_error("rejecting change attempt: bad arguments"); yp_error("client address: %s username: %s", inet_ntoa(rqhost->sin_addr), argp->newpw.pw_name); svcerr_decode(rqstp->rq_xprt); return(&result); } /* Step 4: update the user's passwd structure. */ if (!no_chsh && strcmp(argp->newpw.pw_shell, yp_password.pw_shell)) { oldshell = yp_password.pw_shell; yp_password.pw_shell = argp->newpw.pw_shell; shell_changed++; } if (!no_chfn && strcmp(argp->newpw.pw_gecos, yp_password.pw_gecos)) { oldgecos = yp_password.pw_gecos; yp_password.pw_gecos = argp->newpw.pw_gecos; gecos_changed++; } if (strcmp(argp->newpw.pw_passwd, yp_password.pw_passwd)) { yp_password.pw_passwd = argp->newpw.pw_passwd; yp_password.pw_change = 0; passwd_changed++; } /* * If the caller specified a domain other than our 'default' * domain, change the path to master.passwd accordingly. */ if (strcmp(domain, yppasswd_domain)) { snprintf(passfile_buf, sizeof(passfile_buf), "%s/%s/master.passwd", yp_dir, domain); passfile = (char *)&passfile_buf; } /* * Create a filename to hold the original master.passwd * so if our call to yppwupdate fails we can roll back */ snprintf(passfile_hold_buf, sizeof(passfile_hold_buf), "%s.hold", passfile); passfile_hold = (char *)&passfile_hold_buf; /* Step 5: make a new password file with the updated info. */ snprintf(passdir_buf, sizeof(passdir_buf), "%s", passfile); passdir = dirname(passdir_buf); if (pw_init(passdir, passfile)) { yp_error("pw_init() failed"); return &result; } if ((pfd = pw_lock()) == -1) { pw_fini(); yp_error("pw_lock() failed"); return &result; } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); yp_error("pw_tmp() failed"); return &result; } if (pw_copy(pfd, tfd, &yp_password, NULL) == -1) { pw_fini(); yp_error("pw_copy() failed"); return &result; } if (rename(passfile, passfile_hold) == -1) { pw_fini(); yp_error("rename of %s to %s failed", passfile, passfile_hold); return &result; } if (strcmp(passfile, _PATH_MASTERPASSWD) == 0) { /* * NIS server is exporting the system's master.passwd. * Call pw_mkdb to rebuild passwd and the .db files */ if (pw_mkdb(yp_password.pw_name) == -1) { pw_fini(); yp_error("pw_mkdb() failed"); rename(passfile_hold, passfile); return &result; } } else { /* * NIS server is exporting a private master.passwd. * Rename tempfile into final location */ if (rename(pw_tempname(), passfile) == -1) { pw_fini(); yp_error("rename of %s to %s failed", pw_tempname(), passfile); rename(passfile_hold, passfile); return &result; } } pw_fini(); if (inplace) { if ((rval = update_inplace(&yp_password, domain))) { yp_error("inplace update failed -- rebuilding maps"); } } switch ((pid = fork())) { case 0: if (inplace && !rval) { execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile, yppasswd_domain, "pushpw", (char *)NULL); } else { execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile, yppasswd_domain, (char *)NULL); } yp_error("couldn't exec map update process: %s", strerror(errno)); unlink(passfile); rename(passfile_hold, passfile); exit(1); break; case -1: yp_error("fork() failed: %s", strerror(errno)); unlink(passfile); rename(passfile_hold, passfile); return(&result); break; default: unlink(passfile_hold); break; } if (verbose) { yp_error("update completed for user %s (uid %d) in %s:", argp->newpw.pw_name, argp->newpw.pw_uid, passfile); if (passwd_changed) yp_error("password changed"); if (gecos_changed) yp_error("gecos changed ('%s' -> '%s')", oldgecos, argp->newpw.pw_gecos); if (shell_changed) yp_error("shell changed ('%s' -> '%s')", oldshell, argp->newpw.pw_shell); } result = 0; return (&result); } /* * Note that this function performs a little less sanity checking * than the last one. Since only the superuser is allowed to use it, * it is assumed that the caller knows what he's doing. */ int * yppasswdproc_update_master_1_svc(master_yppasswd *argp, struct svc_req *rqstp) { static int result; int pfd, tfd; int pid; uid_t uid; int rval = 0; DBT key, data; char *passdir; char *passfile_hold; char passdir_buf[MAXPATHLEN + 2]; char passfile_buf[MAXPATHLEN + 2]; char passfile_hold_buf[MAXPATHLEN + 2]; struct sockaddr_in *rqhost; SVCXPRT *transp; struct passwd newpasswd; result = 1; transp = rqstp->rq_xprt; /* * NO AF_INET CONNETCIONS ALLOWED! */ rqhost = svc_getcaller(transp); if (rqhost->sin_family != AF_UNIX) { yp_error("Alert! %s/%d attempted to use superuser-only \ procedure!\n", inet_ntoa(rqhost->sin_addr), rqhost->sin_port); svcerr_auth(transp, AUTH_BADCRED); return(&result); } if (rqstp->rq_cred.oa_flavor != AUTH_SYS) { yp_error("caller didn't send proper credentials"); svcerr_auth(transp, AUTH_BADCRED); return(&result); } if (__rpc_get_local_uid(transp, &uid) < 0) { yp_error("caller didn't send proper credentials"); svcerr_auth(transp, AUTH_BADCRED); return(&result); } if (uid) { yp_error("caller euid is %d, expecting 0 -- rejecting request", uid); svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED); return(&result); } passfile = passfile_default; key.data = argp->newpw.pw_name; key.size = strlen(argp->newpw.pw_name); /* * The superuser may add entries to the passwd maps if * rpc.yppasswdd is started with the -a flag. Paranoia * prevents me from allowing additions by default. */ if ((rval = yp_get_record(argp->domain, "master.passwd.byname", &key, &data, 0)) != YP_TRUE) { if (rval == YP_NOKEY) { yp_error("user %s not found in passwd database", argp->newpw.pw_name); if (allow_additions) yp_error("notice: adding user %s to \ master.passwd database for domain %s", argp->newpw.pw_name, argp->domain); else yp_error("restart rpc.yppasswdd with the -a flag to \ allow additions to be made to the password database"); } else { yp_error("database access error: %s", yperr_string(rval)); } if (!allow_additions) return(&result); } else { /* Nul terminate, please. */ *((char *)data.data + data.size) = '\0'; copy_yp_pass(data.data, 1, data.size); } /* * Perform a small bit of sanity checking. */ if (validate_master(rval == YP_TRUE ? &yp_password:NULL,&argp->newpw)){ yp_error("rejecting update attempt for %s: bad arguments", argp->newpw.pw_name); return(&result); } /* * If the caller specified a domain other than our 'default' * domain, change the path to master.passwd accordingly. */ if (strcmp(argp->domain, yppasswd_domain)) { snprintf(passfile_buf, sizeof(passfile_buf), "%s/%s/master.passwd", yp_dir, argp->domain); passfile = (char *)&passfile_buf; } /* * Create a filename to hold the original master.passwd * so if our call to yppwupdate fails we can roll back */ snprintf(passfile_hold_buf, sizeof(passfile_hold_buf), "%s.hold", passfile); passfile_hold = (char *)&passfile_hold_buf; snprintf(passdir_buf, sizeof(passdir_buf), "%s", passfile); passdir = dirname(passdir_buf); if (pw_init(passdir, passfile)) { yp_error("pw_init() failed"); return &result; } if ((pfd = pw_lock()) == -1) { pw_fini(); yp_error("pw_lock() failed"); return &result; } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); yp_error("pw_tmp() failed"); return &result; } xlate_passwd(&argp->newpw, &newpasswd); if (pw_copy(pfd, tfd, &newpasswd, NULL) == -1) { pw_fini(); yp_error("pw_copy() failed"); return &result; } if (rename(passfile, passfile_hold) == -1) { pw_fini(); yp_error("rename of %s to %s failed", passfile, passfile_hold); return &result; } if (strcmp(passfile, _PATH_MASTERPASSWD) == 0) { /* * NIS server is exporting the system's master.passwd. * Call pw_mkdb to rebuild passwd and the .db files */ if (pw_mkdb(argp->newpw.pw_name) == -1) { pw_fini(); yp_error("pw_mkdb() failed"); rename(passfile_hold, passfile); return &result; } } else { /* * NIS server is exporting a private master.passwd. * Rename tempfile into final location */ if (rename(pw_tempname(), passfile) == -1) { pw_fini(); yp_error("rename of %s to %s failed", pw_tempname(), passfile); rename(passfile_hold, passfile); return &result; } } pw_fini(); if (inplace) { xlate_passwd(&argp->newpw, &newpasswd); if ((rval = update_inplace(&newpasswd, argp->domain))) { yp_error("inplace update failed -- rebuilding maps"); } } switch ((pid = fork())) { case 0: if (inplace && !rval) { execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile, argp->domain, "pushpw", (char *)NULL); } else { execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile, argp->domain, (char *)NULL); } yp_error("couldn't exec map update process: %s", strerror(errno)); unlink(passfile); rename(passfile_hold, passfile); exit(1); break; case -1: yp_error("fork() failed: %s", strerror(errno)); unlink(passfile); rename(passfile_hold, passfile); return(&result); break; default: unlink(passfile_hold); break; } yp_error("performed update of user %s (uid %d) domain %s", argp->newpw.pw_name, argp->newpw.pw_uid, argp->domain); result = 0; return(&result); } Index: head/usr.sbin/rpc.ypupdated/yp_dbupdate.c =================================================================== --- head/usr.sbin/rpc.ypupdated/yp_dbupdate.c (revision 350956) +++ head/usr.sbin/rpc.ypupdated/yp_dbupdate.c (revision 350957) @@ -1,149 +1,149 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1996 * Bill Paul . 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 Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "ypxfr_extern.h" #include "ypupdated_extern.h" static int yp_domake(char *map, char *domain) { int pid; switch ((pid = fork())) { case 0: execlp(MAP_UPDATE_PATH, MAP_UPDATE, map, domain, (char *)NULL); yp_error("couldn't exec map update process: %s", strerror(errno)); exit(1); break; case -1: yp_error("fork() failed: %s", strerror(errno)); return(YPERR_YPERR); break; default: children++; break; } return(0); } int ypmap_update(char *netname, char *map, unsigned int op, unsigned int keylen, char *keyval, unsigned int datlen, char *datval) { DB *dbp; DBT key = { NULL, 0 }, data = { NULL, 0 }; char *yp_last = "YP_LAST_MODIFIED"; - char yplastbuf[YPMAXRECORD]; + char yplastbuf[32]; char *domptr; int rval = 0; if ((domptr = strchr(netname, '@')) == NULL) return(ERR_ACCESS); domptr++; dbp = yp_open_db_rw(domptr, map, O_RDWR); if (dbp == NULL) return(ERR_DBASE); key.data = keyval; key.size = keylen; data.data = datval; data.size = datlen; switch (op) { case YPOP_DELETE: /* delete this entry */ rval = yp_del_record(dbp, &key); if (rval == YP_TRUE) rval = 0; break; case YPOP_INSERT: /* add, do not change */ rval = yp_put_record(dbp, &key, &data, 0); if (rval == YP_TRUE) rval = 0; break; case YPOP_STORE: /* add, or change */ rval = yp_put_record(dbp, &key, &data, 1); if (rval == YP_TRUE) rval = 0; break; case YPOP_CHANGE: /* change, do not add */ if (yp_get_record(domptr, map, &key, &data, 0) != YP_TRUE) { rval = ERR_KEY; break; } rval = yp_put_record(dbp, &key, &data, 1); if (rval == YP_TRUE) rval = 0; break; default: yp_error("unknown update command: (%d)", op); } if (rval) { (void)(dbp->close)(dbp); return(rval); } snprintf(yplastbuf, sizeof(yplastbuf), "%jd", (intmax_t)time(NULL)); key.data = yp_last; key.size = strlen(yp_last); data.data = (char *)&yplastbuf; data.size = strlen(yplastbuf); if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) { yp_error("failed to update timestamp in %s/%s", domptr, map); (void)(dbp->close)(dbp); return(ERR_DBASE); } (void)(dbp->close)(dbp); return(yp_domake(map, domptr)); } Index: head/usr.sbin/ypldap/yp.c =================================================================== --- head/usr.sbin/ypldap/yp.c (revision 350956) +++ head/usr.sbin/ypldap/yp.c (revision 350957) @@ -1,662 +1,680 @@ /* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ypldap.h" void yp_dispatch(struct svc_req *, SVCXPRT *); void yp_disable_events(void); void yp_fd_event(int, short, void *); int yp_check(struct svc_req *); int yp_valid_domain(char *, struct ypresp_val *); void yp_make_val(struct ypresp_val *, char *, int); void yp_make_keyval(struct ypresp_key_val *, char *, char *); static struct env *env; struct yp_event { TAILQ_ENTRY(yp_event) ye_entry; struct event ye_event; }; struct yp_data { SVCXPRT *yp_trans_udp; SVCXPRT *yp_trans_tcp; TAILQ_HEAD(, yp_event) yd_events; }; void yp_disable_events(void) { struct yp_event *ye; while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) { TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry); event_del(&ye->ye_event); free(ye); } } void yp_enable_events(void) { int i; struct yp_event *ye; for (i = 0; i < getdtablesize(); i++) { if ((ye = calloc(1, sizeof(*ye))) == NULL) fatal(NULL); event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL); event_add(&ye->ye_event, NULL); TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry); } } void yp_fd_event(int fd, short event, void *p) { svc_getreq_common(fd); yp_disable_events(); yp_enable_events(); } void yp_init(struct env *x_env) { struct yp_data *yp; if ((yp = calloc(1, sizeof(*yp))) == NULL) fatal(NULL); TAILQ_INIT(&yp->yd_events); env = x_env; env->sc_yp = yp; (void)pmap_unset(YPPROG, YPVERS); if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL) fatal("cannot create udp service"); if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) fatal("cannot create tcp service"); if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, yp_dispatch, IPPROTO_UDP)) { fatal("unable to register (YPPROG, YPVERS, udp)"); } if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, yp_dispatch, IPPROTO_TCP)) { fatal("unable to register (YPPROG, YPVERS, tcp)"); } } /* * lots of inspiration from ypserv by Mats O Jansson */ void yp_dispatch(struct svc_req *req, SVCXPRT *trans) { xdrproc_t xdr_argument; xdrproc_t xdr_result; char *result; char *(*cb)(char *, struct svc_req *); union { domainname ypproc_domain_2_arg; domainname ypproc_domain_nonack_2_arg; ypreq_key ypproc_match_2_arg; ypreq_nokey ypproc_first_2_arg; ypreq_key ypproc_next_2_arg; ypreq_xfr ypproc_xfr_2_arg; ypreq_nokey ypproc_all_2_arg; ypreq_nokey ypproc_master_2_arg; ypreq_nokey ypproc_order_2_arg; domainname ypproc_maplist_2_arg; } argument; xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_void; cb = NULL; switch (req->rq_proc) { case YPPROC_NULL: xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_void; if (yp_check(req) == -1) return; result = NULL; if (!svc_sendreply(trans, (xdrproc_t) xdr_void, (void *)&result)) svcerr_systemerr(trans); return; case YPPROC_DOMAIN: xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_bool; if (yp_check(req) == -1) return; cb = (void *)ypproc_domain_2_svc; break; case YPPROC_DOMAIN_NONACK: xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_bool; if (yp_check(req) == -1) return; cb = (void *)ypproc_domain_nonack_2_svc; break; case YPPROC_MATCH: xdr_argument = (xdrproc_t) xdr_ypreq_key; xdr_result = (xdrproc_t) xdr_ypresp_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_match_2_svc; break; case YPPROC_FIRST: xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_key_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_first_2_svc; break; case YPPROC_NEXT: xdr_argument = (xdrproc_t) xdr_ypreq_key; xdr_result = (xdrproc_t) xdr_ypresp_key_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_next_2_svc; break; case YPPROC_XFR: if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_CLEAR: log_debug("ypproc_clear"); if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_ALL: log_debug("ypproc_all"); xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_all; if (yp_check(req) == -1) return; cb = (void *)ypproc_all_2_svc; break; case YPPROC_MASTER: log_debug("ypproc_master"); xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_master; if (yp_check(req) == -1) return; cb = (void *)ypproc_master_2_svc; break; case YPPROC_ORDER: log_debug("ypproc_order"); if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_MAPLIST: log_debug("ypproc_maplist"); xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_ypresp_maplist; if (yp_check(req) == -1) return; cb = (void *)ypproc_maplist_2_svc; break; default: svcerr_noproc(trans); return; } (void)memset(&argument, 0, sizeof(argument)); if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) { svcerr_decode(trans); return; } result = (*cb)((char *)&argument, req); if (result != NULL && !svc_sendreply(trans, xdr_result, result)) svcerr_systemerr(trans); if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) { /* * ypserv does it too. */ fatal("unable to free arguments"); } } int yp_check(struct svc_req *req) { struct sockaddr_in *caller; caller = svc_getcaller(req->rq_xprt); /* * We might want to know who we allow here. */ return (0); } int yp_valid_domain(char *domain, struct ypresp_val *res) { if (domain == NULL) { log_debug("NULL domain !"); return (-1); } if (strcmp(domain, env->sc_domainname) != 0) { res->stat = YP_NODOM; return (-1); } return (0); } bool_t * ypproc_domain_2_svc(domainname *arg, struct svc_req *req) { static bool_t res; res = (bool_t)1; if (strcmp(*arg, env->sc_domainname) != 0) res = (bool_t)0; return (&res); } bool_t * ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req) { static bool_t res; if (strcmp(*arg, env->sc_domainname) != 0) return NULL; res = (bool_t)1; return (&res); } ypresp_val * ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req) { struct userent ukey; struct userent *ue; struct groupent gkey; struct groupent *ge; static struct ypresp_val res; const char *estr; char *bp, *cp; - char key[YPMAXRECORD+1]; + char *key; log_debug("matching '%.*s' in map %s", arg->key.keydat_len, arg->key.keydat_val, arg->map); if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (env->sc_user_names == NULL) { /* * tree not ready. */ return (NULL); } if (arg->key.keydat_len > YPMAXRECORD) { log_debug("argument too long"); return (NULL); } - memset(key, 0, sizeof(key)); + key = calloc(arg->key.keydat_len + 1, 1); + if (key == NULL) + return (NULL); (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { ukey.ue_line = key; if ((ue = RB_FIND(user_name_tree, env->sc_user_names, &ukey)) == NULL) { res.stat = YP_NOKEY; - return (&res); + goto out; } yp_make_val(&res, ue->ue_line, 1); - return (&res); + goto out; } else if (strcmp(arg->map, "passwd.byuid") == 0 || strcmp(arg->map, "master.passwd.byuid") == 0) { ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; - return (&res); + goto out; } if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, &ukey)) == NULL) { res.stat = YP_NOKEY; - return (&res); + goto out; } yp_make_val(&res, ue->ue_line, 1); return (&res); } else if (strcmp(arg->map, "group.bygid") == 0) { gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; - return (&res); + goto out; } if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids, &gkey)) == NULL) { res.stat = YP_NOKEY; - return (&res); + goto out; } yp_make_val(&res, ge->ge_line, 1); return (&res); } else if (strcmp(arg->map, "group.byname") == 0) { gkey.ge_line = key; if ((ge = RB_FIND(group_name_tree, env->sc_group_names, &gkey)) == NULL) { res.stat = YP_NOKEY; - return (&res); + goto out; } yp_make_val(&res, ge->ge_line, 1); return (&res); } else if (strcmp(arg->map, "netid.byname") == 0) { bp = cp = key; if (strncmp(bp, "unix.", strlen("unix.")) != 0) { res.stat = YP_BADARGS; - return (&res); + goto out; } bp += strlen("unix."); if (*bp == '\0') { res.stat = YP_BADARGS; - return (&res); + goto out; } if (!(cp = strsep(&bp, "@"))) { res.stat = YP_BADARGS; - return (&res); + goto out; } if (strcmp(bp, arg->domain) != 0) { res.stat = YP_BADARGS; - return (&res); + goto out; } ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; - return (&res); + goto out; } if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, &ukey)) == NULL) { res.stat = YP_NOKEY; - return (&res); + goto out; } yp_make_val(&res, ue->ue_netid_line, 0); - return (&res); + goto out; } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; - return (&res); + goto out; } +out: + free(key); + return (&res); } ypresp_key_val * ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_key_val res; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { if (env->sc_user_lines == NULL) return (NULL); yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines); } else if (strcmp(arg->map, "group.byname") == 0) { if (env->sc_group_lines == NULL) return (NULL); yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines); } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; } return (&res); } ypresp_key_val * ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req) { struct userent ukey; struct userent *ue; struct groupent gkey; struct groupent *ge; char *line; static struct ypresp_key_val res; - char key[YPMAXRECORD+1]; + char *key; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); + key = NULL; if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { - memset(key, 0, sizeof(key)); + key = calloc(arg->key.keydat_len + 1, 1); + if (key == NULL) { + res.stat = YP_YPERR; + return (&res); + } (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); ukey.ue_line = key; if ((ue = RB_FIND(user_name_tree, env->sc_user_names, &ukey)) == NULL) { /* * canacar's trick: * the user might have been deleted in between calls * to next since the tree may be modified by a reload. * next should still return the next user in * lexicographical order, hence insert the search key * and look up the next field, then remove it again. */ RB_INSERT(user_name_tree, env->sc_user_names, &ukey); if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names, &ukey)) == NULL) { RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); res.stat = YP_NOKEY; + free(key); return (&res); } RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); } line = ue->ue_line + (strlen(ue->ue_line) + 1); line = line + (strlen(line) + 1); yp_make_keyval(&res, line, line); + free(key); return (&res); } else if (strcmp(arg->map, "group.byname") == 0) { - memset(key, 0, sizeof(key)); + key = calloc(arg->key.keydat_len + 1, 1); + if (key == NULL) { + res.stat = YP_YPERR; + return (&res); + } (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); gkey.ge_line = key; if ((ge = RB_FIND(group_name_tree, env->sc_group_names, &gkey)) == NULL) { /* * canacar's trick reloaded. */ RB_INSERT(group_name_tree, env->sc_group_names, &gkey); if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names, &gkey)) == NULL) { RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); res.stat = YP_NOKEY; + free(key); return (&res); } RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); } line = ge->ge_line + (strlen(ge->ge_line) + 1); line = line + (strlen(line) + 1); yp_make_keyval(&res, line, line); + free(key); return (&res); } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; return (&res); } } ypresp_all * ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_all res; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); svcerr_auth(req->rq_xprt, AUTH_FAILED); return (NULL); } ypresp_master * ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_master res; static char master[YPMAXPEER + 1]; memset(&res, 0, sizeof(res)); if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (gethostname(master, sizeof(master)) == 0) { res.peer = (peername)master; res.stat = YP_TRUE; } else res.stat = YP_NOKEY; return (&res); } ypresp_maplist * ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) { size_t i; static struct { char *name; int cond; } mapnames[] = { { "passwd.byname", YPMAP_PASSWD_BYNAME }, { "passwd.byuid", YPMAP_PASSWD_BYUID }, { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, { "group.byname", YPMAP_GROUP_BYNAME }, { "group.bygid", YPMAP_GROUP_BYGID }, { "netid.byname", YPMAP_NETID_BYNAME }, }; static ypresp_maplist res; static struct ypmaplist maps[nitems(mapnames)]; if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) return (&res); res.stat = YP_TRUE; res.maps = NULL; for (i = 0; i < nitems(mapnames); i++) { if (!(env->sc_flags & mapnames[i].cond)) continue; maps[i].map = mapnames[i].name; maps[i].next = res.maps; res.maps = &maps[i]; } return (&res); } void yp_make_val(struct ypresp_val *res, char *line, int replacecolon) { static char buf[LINE_WIDTH]; memset(buf, 0, sizeof(buf)); if (replacecolon) line[strlen(line)] = ':'; (void)strlcpy(buf, line, sizeof(buf)); if (replacecolon) line[strcspn(line, ":")] = '\0'; log_debug("sending out %s", buf); res->stat = YP_TRUE; res->val.valdat_len = strlen(buf); res->val.valdat_val = buf; } void yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) { static char keybuf[YPMAXRECORD+1]; static char buf[LINE_WIDTH]; memset(keybuf, 0, sizeof(keybuf)); memset(buf, 0, sizeof(buf)); (void)strlcpy(keybuf, key, sizeof(keybuf)); res->key.keydat_len = strlen(keybuf); res->key.keydat_val = keybuf; if (*line == '\0') { res->stat = YP_NOMORE; return; } res->stat = YP_TRUE; line[strlen(line)] = ':'; (void)strlcpy(buf, line, sizeof(buf)); line[strcspn(line, ":")] = '\0'; log_debug("sending out %s => %s", keybuf, buf); res->val.valdat_len = strlen(buf); res->val.valdat_val = buf; } Index: head/usr.sbin/yppush/yppush_main.c =================================================================== --- head/usr.sbin/yppush/yppush_main.c (revision 350956) +++ head/usr.sbin/yppush/yppush_main.c (revision 350957) @@ -1,622 +1,636 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 * Bill Paul . 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 Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ypxfr_extern.h" #include "yppush_extern.h" char *progname = "yppush"; int debug = 1; int _rpcpmstart = 0; char *yp_dir = _PATH_YP; static char *yppush_mapname = NULL; /* Map to transfer. */ static char *yppush_domain = NULL; /* Domain in which map resides. */ static char *yppush_master = NULL; /* Master NIS server for said domain. */ static int skip_master = 0; /* Do not attempt to push map to master. */ static int verbose = 0; /* Toggle verbose mode. */ static unsigned long yppush_transid = 0; static int yppush_timeout = 80; /* Default timeout. */ static int yppush_jobs = 1; /* Number of allowed concurrent jobs. */ static int yppush_running_jobs = 0; /* Number of currently running jobs. */ /* Structure for holding information about a running job. */ struct jobs { unsigned long tid; int port; ypxfrstat stat; unsigned long prognum; char *server; char *map; int polled; struct jobs *next; }; static struct jobs *yppush_joblist; /* Linked list of running jobs. */ static int yppush_svc_run(int); /* * Local error messages. */ static const char * yppusherr_string(int err) { switch (err) { case YPPUSH_TIMEDOUT: return("transfer or callback timed out"); case YPPUSH_YPSERV: return("failed to contact ypserv"); case YPPUSH_NOHOST: return("no such host"); case YPPUSH_PMAP: return("portmapper failure"); default: return("unknown error code"); } } /* * Report state of a job. */ static int yppush_show_status(ypxfrstat status, unsigned long tid) { struct jobs *job; job = yppush_joblist; while (job != NULL) { if (job->tid == tid) break; job = job->next; } if (job == NULL) { yp_error("warning: received callback with invalid transaction ID: %lu", tid); return (0); } if (job->polled) { yp_error("warning: received callback with duplicate transaction ID: %lu", tid); return (0); } if (verbose > 1) { yp_error("checking return status: transaction ID: %lu", job->tid); } if (status != YPXFR_SUCC || verbose) { yp_error("transfer of map %s to server %s %s", job->map, job->server, status == YPXFR_SUCC ? "succeeded" : "failed"); yp_error("status returned by ypxfr: %s", status > YPXFR_AGE ? yppusherr_string(status) : ypxfrerr_string(status)); } job->polled = 1; svc_unregister(job->prognum, 1); yppush_running_jobs--; return(0); } /* Exit routine. */ static void yppush_exit(int now) { struct jobs *jptr; int still_pending = 1; /* Let all the information trickle in. */ while (!now && still_pending) { jptr = yppush_joblist; still_pending = 0; while (jptr) { if (jptr->polled == 0) { still_pending++; if (verbose > 1) yp_error("%s has not responded", jptr->server); } else { if (verbose > 1) yp_error("%s has responded", jptr->server); } jptr = jptr->next; } if (still_pending) { if (verbose > 1) yp_error("%d transfer%sstill pending", still_pending, still_pending > 1 ? "s " : " "); if (yppush_svc_run (YPPUSH_RESPONSE_TIMEOUT) == 0) { yp_error("timed out"); now = 1; } } else { if (verbose) yp_error("all transfers complete"); break; } } /* All stats collected and reported -- kill all the stragglers. */ jptr = yppush_joblist; while (jptr) { if (!jptr->polled) yp_error("warning: exiting with transfer \ to %s (transid = %lu) still pending", jptr->server, jptr->tid); svc_unregister(jptr->prognum, 1); jptr = jptr->next; } exit(0); } /* * Handler for 'normal' signals. */ static void handler(int sig) { yppush_exit (1); return; } /* * Dispatch loop for callback RPC services. * Return value: * -1 error * 0 timeout * >0 request serviced */ static int yppush_svc_run(int timeout_secs) { int rc; fd_set readfds; struct timeval timeout; timeout.tv_usec = 0; timeout.tv_sec = timeout_secs; retry: readfds = svc_fdset; rc = select(svc_maxfd + 1, &readfds, NULL, NULL, &timeout); switch (rc) { case -1: if (errno == EINTR) goto retry; yp_error("select failed: %s", strerror(errno)); break; case 0: yp_error("select() timed out"); break; default: svc_getreqset(&readfds); break; } return rc; } /* * RPC service routines for callbacks. */ void * yppushproc_null_1_svc(void *argp, struct svc_req *rqstp) { static char * result; /* Do nothing -- RPC conventions call for all a null proc. */ return((void *) &result); } void * yppushproc_xfrresp_1_svc(yppushresp_xfr *argp, struct svc_req *rqstp) { static char * result; yppush_show_status(argp->status, argp->transid); return((void *) &result); } /* * Transmit a YPPROC_XFR request to ypserv. */ static int yppush_send_xfr(struct jobs *job) { ypreq_xfr req; /* ypresp_xfr *resp; */ DBT key, data; CLIENT *clnt; struct rpc_err err; struct timeval timeout; timeout.tv_usec = 0; timeout.tv_sec = 0; /* * The ypreq_xfr structure has a member of type map_parms, * which seems to require the order number of the map. * It isn't actually used at the other end (at least the * FreeBSD ypserv doesn't use it) but we fill it in here * for the sake of completeness. */ key.data = "YP_LAST_MODIFIED"; key.size = sizeof ("YP_LAST_MODIFIED") - 1; if (yp_get_record(yppush_domain, yppush_mapname, &key, &data, 1) != YP_TRUE) { yp_error("failed to read order number from %s: %s: %s", yppush_mapname, yperr_string(yp_errno), strerror(errno)); return(1); } /* Fill in the request arguments */ req.map_parms.ordernum = atoi(data.data); req.map_parms.domain = yppush_domain; req.map_parms.peer = yppush_master; req.map_parms.map = job->map; req.transid = job->tid; req.prog = job->prognum; req.port = job->port; /* Get a handle to the remote ypserv. */ if ((clnt = clnt_create(job->server, YPPROG, YPVERS, "udp")) == NULL) { yp_error("%s: %s",job->server,clnt_spcreateerror("couldn't \ create udp handle to NIS server")); switch (rpc_createerr.cf_stat) { case RPC_UNKNOWNHOST: job->stat = YPPUSH_NOHOST; break; case RPC_PMAPFAILURE: job->stat = YPPUSH_PMAP; break; default: job->stat = YPPUSH_RPC; break; } return(1); } /* * Reduce timeout to nothing since we may not * get a response from ypserv and we don't want to block. */ if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE) yp_error("failed to set timeout on ypproc_xfr call"); /* Invoke the ypproc_xfr service. */ if (ypproc_xfr_2(&req, clnt) == NULL) { clnt_geterr(clnt, &err); if (err.re_status != RPC_SUCCESS && err.re_status != RPC_TIMEDOUT) { yp_error("%s: %s", job->server, clnt_sperror(clnt, "yp_xfr failed")); job->stat = YPPUSH_YPSERV; clnt_destroy(clnt); return(1); } } clnt_destroy(clnt); return(0); } /* * Main driver function. Register the callback service, add the transfer * request to the internal list, send the YPPROC_XFR request to ypserv * do other magic things. */ static int yp_push(char *server, char *map, unsigned long tid) { unsigned long prognum; int sock = RPC_ANYSOCK; SVCXPRT *xprt; struct jobs *job; /* Register the job in our linked list of jobs. */ /* First allocate job structure */ if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) { yp_error("malloc failed"); yppush_exit (1); } /* * Register the callback service on the first free transient * program number. */ xprt = svcudp_create(sock); for (prognum = 0x40000000; prognum < 0x5FFFFFFF; prognum++) { if (svc_register(xprt, prognum, 1, yppush_xfrrespprog_1, IPPROTO_UDP) == TRUE) break; } if (prognum == 0x5FFFFFFF) { yp_error ("can't register yppush_xfrrespprog_1"); yppush_exit (1); } /* Initialize the info for this job. */ job->stat = 0; job->tid = tid; job->port = xprt->xp_port; job->server = strdup(server); job->map = strdup(map); job->prognum = prognum; job->polled = 0; job->next = yppush_joblist; yppush_joblist = job; if (verbose) { yp_error("initiating transfer: %s -> %s (transid = %lu)", yppush_mapname, server, tid); } /* * Send the XFR request to ypserv. We don't have to wait for * a response here since we handle them asynchronously. */ if (yppush_send_xfr(job)){ /* Transfer request blew up. */ yppush_show_status(job->stat ? job->stat : YPPUSH_YPSERV,job->tid); } else { if (verbose > 1) yp_error("%s has been called", server); } return(0); } /* * Called for each entry in the ypservers map from yp_get_map(), which * is our private yp_all() routine. */ static int yppush_foreach(int status, char *key, int keylen, char *val, int vallen, char *data) { - char server[YPMAXRECORD + 2]; + char *server; if (status != YP_TRUE) return (status); - snprintf(server, sizeof(server), "%.*s", vallen, val); - if (skip_master && strcasecmp(server, yppush_master) == 0) + asprintf(&server, "%.*s", vallen, val); + + /* + * Do not stop the iteration on the allocation failure. We + * cannot usefully react on low memory condition anyway, and + * the failure is more likely due to insane val. + */ + if (server == NULL) return (0); + if (skip_master && strcasecmp(server, yppush_master) == 0) { + free(server); + return (0); + } + /* * Restrict the number of concurrent jobs: if yppush_jobs number * of jobs have already been dispatched and are still pending, * wait for one of them to finish so we can reuse its slot. */ while (yppush_running_jobs >= yppush_jobs && (yppush_svc_run (yppush_timeout) > 0)) ; /* Cleared for takeoff: set everything in motion. */ - if (yp_push(server, yppush_mapname, yppush_transid)) + if (yp_push(server, yppush_mapname, yppush_transid)) { + free(server); return(yp_errno); + } /* Bump the job counter and transaction ID. */ yppush_running_jobs++; yppush_transid++; + free(server); return (0); } static void usage() { fprintf (stderr, "%s\n%s\n", "usage: yppush [-d domain] [-t timeout] [-j #parallel jobs] [-h host]", " [-p path] mapname"); exit(1); } /* * Entry point. (About time!) */ int main(int argc, char *argv[]) { int ch; DBT key, data; char myname[MAXHOSTNAMELEN]; struct hostlist { char *name; struct hostlist *next; }; struct hostlist *yppush_hostlist = NULL; struct hostlist *tmp; while ((ch = getopt(argc, argv, "d:j:p:h:t:v")) != -1) { switch (ch) { case 'd': yppush_domain = optarg; break; case 'j': yppush_jobs = atoi(optarg); if (yppush_jobs <= 0) yppush_jobs = 1; break; case 'p': yp_dir = optarg; break; case 'h': /* we can handle multiple hosts */ if ((tmp = (struct hostlist *)malloc(sizeof(struct hostlist))) == NULL) { yp_error("malloc failed"); yppush_exit(1); } tmp->name = strdup(optarg); tmp->next = yppush_hostlist; yppush_hostlist = tmp; break; case 't': yppush_timeout = atoi(optarg); break; case 'v': verbose++; break; default: usage(); break; } } argc -= optind; argv += optind; yppush_mapname = argv[0]; if (yppush_mapname == NULL) { /* "No guts, no glory." */ usage(); } /* * If no domain was specified, try to find the default * domain. If we can't find that, we're doomed and must bail. */ if (yppush_domain == NULL) { char *yppush_check_domain; if (!yp_get_default_domain(&yppush_check_domain) && !_yp_check(&yppush_check_domain)) { yp_error("no domain specified and NIS not running"); usage(); } else yp_get_default_domain(&yppush_domain); } /* Check to see that we are the master for this map. */ if (gethostname ((char *)&myname, sizeof(myname))) { yp_error("failed to get name of local host: %s", strerror(errno)); yppush_exit(1); } key.data = "YP_MASTER_NAME"; key.size = sizeof("YP_MASTER_NAME") - 1; if (yp_get_record(yppush_domain, yppush_mapname, &key, &data, 1) != YP_TRUE) { yp_error("couldn't open %s map: %s", yppush_mapname, strerror(errno)); yppush_exit(1); } if (strncasecmp(myname, data.data, data.size) == 0) { /* I am master server, and no explicit host list was specified: do not push map to myself -- this will fail with YPPUSH_AGE anyway. */ if (yppush_hostlist == NULL) skip_master = 1; } else { yp_error("warning: this host is not the master for %s", yppush_mapname); #ifdef NITPICKY yppush_exit(1); #endif } yppush_master = malloc(data.size + 1); strncpy(yppush_master, data.data, data.size); yppush_master[data.size] = '\0'; /* Install some handy handlers. */ signal(SIGTERM, handler); signal(SIGINT, handler); /* set initial transaction ID */ yppush_transid = time((time_t *)NULL); if (yppush_hostlist) { /* * Host list was specified on the command line: * kick off the transfers by hand. */ tmp = yppush_hostlist; while (tmp) { yppush_foreach(YP_TRUE, NULL, 0, tmp->name, strlen(tmp->name), NULL); tmp = tmp->next; } } else { /* * Do a yp_all() on the ypservers map and initiate a ypxfr * for each one. */ ypxfr_get_map("ypservers", yppush_domain, "localhost", yppush_foreach); } if (verbose > 1) yp_error("all jobs dispatched"); /* All done -- normal exit. */ yppush_exit(0); /* Just in case. */ exit(0); } Index: head/usr.sbin/ypserv/yp_server.c =================================================================== --- head/usr.sbin/ypserv/yp_server.c (revision 350956) +++ head/usr.sbin/ypserv/yp_server.c (revision 350957) @@ -1,988 +1,989 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 * Bill Paul . 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 Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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 __FBSDID("$FreeBSD$"); #include "yp.h" #include "yp_extern.h" #include #include #include #include #include #include #include #include #include #include int children = 0; #define MASTER_STRING "YP_MASTER_NAME" #define MASTER_SZ sizeof(MASTER_STRING) - 1 #define ORDER_STRING "YP_LAST_MODIFIED" #define ORDER_SZ sizeof(ORDER_STRING) - 1 static pid_t yp_fork(void) { if (yp_pid != getpid()) { yp_error("child %d trying to fork!", getpid()); errno = EEXIST; return(-1); } return(fork()); } /* * NIS v2 support. This is where most of the action happens. */ void * ypproc_null_2_svc(void *argp, struct svc_req *rqstp) { static char * result; static char rval = 0; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return(NULL); result = &rval; return((void *) &result); } bool_t * ypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp) { static bool_t result; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) { #else if (yp_access(NULL, (struct svc_req *)rqstp)) { #endif result = FALSE; return (&result); } if (argp == NULL || yp_validdomain(*argp)) result = FALSE; else result = TRUE; return (&result); } bool_t * ypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp) { static bool_t result; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return (NULL); if (argp == NULL || yp_validdomain(*argp)) return (NULL); else result = TRUE; return (&result); } ypresp_val * ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_val result; result.val.valdat_val = ""; result.val.valdat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_getbykey(&argp->key, &result.val); /* * Do DNS lookups for hosts maps if database lookup failed. */ #ifdef DB_CACHE if (do_dns && result.stat != YP_TRUE && (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) || (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes")))) { #else if (do_dns && result.stat != YP_TRUE && (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes"))) { #endif - char nbuf[YPMAXRECORD]; + char *nbuf; + nbuf = alloca(argp->key.keydat_len + 1); /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */ bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len); nbuf[argp->key.keydat_len] = '\0'; if (debug) yp_error("doing DNS lookup of %s", nbuf); if (!strcmp(argp->map, "hosts.byname")) result.stat = yp_async_lookup_name(rqstp, nbuf, AF_INET); else if (!strcmp(argp->map, "hosts.byaddr")) result.stat = yp_async_lookup_addr(rqstp, nbuf, AF_INET); else if (!strcmp(argp->map, "ipnodes.byname")) result.stat = yp_async_lookup_name(rqstp, nbuf, AF_INET6); else if (!strcmp(argp->map, "ipnodes.byaddr")) result.stat = yp_async_lookup_addr(rqstp, nbuf, AF_INET6); if (result.stat == YP_TRUE) return(NULL); } return (&result); } ypresp_key_val * ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_key_val result; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_firstbykey(&result.key, &result.val); return (&result); } ypresp_key_val * ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_key_val result; result.val.valdat_val = result.key.keydat_val = ""; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.key.keydat_len = argp->key.keydat_len; result.key.keydat_val = argp->key.keydat_val; result.stat = yp_nextbykey(&result.key, &result.val); return (&result); } static void ypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid, unsigned int prognum, unsigned long port) { CLIENT *clnt; int sock = RPC_ANYSOCK; struct timeval timeout; yppushresp_xfr ypxfr_resp; struct rpc_err err; timeout.tv_sec = 5; timeout.tv_usec = 0; addr->sin_port = htons(port); if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) { yp_error("%s: %s", inet_ntoa(addr->sin_addr), clnt_spcreateerror("failed to establish callback handle")); return; } ypxfr_resp.status = rval; ypxfr_resp.transid = transid; /* Turn the timeout off -- we don't want to block. */ timeout.tv_sec = 0; if (clnt_control(clnt, CLSET_TIMEOUT, &timeout) == FALSE) yp_error("failed to set timeout on ypproc_xfr callback"); if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) { clnt_geterr(clnt, &err); if (err.re_status != RPC_SUCCESS && err.re_status != RPC_TIMEDOUT) yp_error("%s", clnt_sperror(clnt, "ypxfr callback failed")); } clnt_destroy(clnt); return; } #define YPXFR_RETURN(CODE) \ /* Order is important: send regular RPC reply, then callback */ \ result.xfrstat = CODE; \ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_ypresp_xfr, &result); \ ypxfr_callback(CODE,rqhost,argp->transid, \ argp->prog,argp->port); \ return(NULL); ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp) { static ypresp_xfr result; struct sockaddr_in *rqhost; ypresp_master *mres; ypreq_nokey mreq; result.transid = argp->transid; rqhost = svc_getcaller(rqstp->rq_xprt); #ifdef DB_CACHE if (yp_access(argp->map_parms.map, argp->map_parms.domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) { #endif YPXFR_RETURN(YPXFR_REFUSED) } if (argp->map_parms.domain == NULL) { YPXFR_RETURN(YPXFR_BADARGS) } if (yp_validdomain(argp->map_parms.domain)) { YPXFR_RETURN(YPXFR_NODOM) } /* * Determine the master host ourselves. The caller may * be up to no good. This has the side effect of verifying * that the requested map and domain actually exist. */ mreq.domain = argp->map_parms.domain; mreq.map = argp->map_parms.map; mres = ypproc_master_2_svc(&mreq, rqstp); if (mres->stat != YP_TRUE) { yp_error("couldn't find master for map %s@%s", argp->map_parms.map, argp->map_parms.domain); yp_error("host at %s (%s) may be pulling my leg", argp->map_parms.peer, inet_ntoa(rqhost->sin_addr)); YPXFR_RETURN(YPXFR_REFUSED) } switch (yp_fork()) { case 0: { char g[11], t[11], p[11]; char ypxfr_command[MAXPATHLEN + 2]; snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC); snprintf (t, sizeof(t), "%u", argp->transid); snprintf (g, sizeof(g), "%u", argp->prog); snprintf (p, sizeof(p), "%u", argp->port); if (debug) { close(0); close(1); close(2); } if (strcmp(yp_dir, _PATH_YP)) { execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain, "-h", mres->peer, "-p", yp_dir, "-C", t, g, inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map, NULL); } else { execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain, "-h", mres->peer, "-C", t, g, inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map, NULL); } yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno)); YPXFR_RETURN(YPXFR_XFRERR) /* * Just to safe, prevent PR #10970 from biting us in * the unlikely case that execing ypxfr fails. We don't * want to have any child processes spawned from this * child process. */ _exit(0); break; } case -1: yp_error("ypxfr fork(): %s", strerror(errno)); YPXFR_RETURN(YPXFR_XFRERR) break; default: result.xfrstat = YPXFR_SUCC; children++; break; } return (&result); } #undef YPXFR_RETURN void * ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) { static char * result; static char rval = 0; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else if (yp_access(NULL, (struct svc_req *)rqstp)) #endif return (NULL); #ifdef DB_CACHE /* clear out the database cache */ yp_flush_all(); #endif /* Re-read the securenets database for the hell of it. */ load_securenets(); result = &rval; return((void *) &result); } /* * For ypproc_all, we have to send a stream of ypresp_all structures * via TCP, but the XDR filter generated from the yp.x protocol * definition file only serializes one such structure. This means that * to send the whole stream, you need a wrapper which feeds all the * records into the underlying XDR routine until it hits an 'EOF.' * But to use the wrapper, you have to violate the boundaries between * RPC layers by calling svc_sendreply() directly from the ypproc_all * service routine instead of letting the RPC dispatcher do it. * * Bleah. */ /* * Custom XDR routine for serialzing results of ypproc_all: keep * reading from the database and spew until we run out of records * or encounter an error. */ static bool_t xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp) { while (1) { /* Get a record. */ if ((objp->ypresp_all_u.val.stat = yp_nextbykey(&objp->ypresp_all_u.val.key, &objp->ypresp_all_u.val.val)) == YP_TRUE) { objp->more = TRUE; } else { objp->more = FALSE; } /* Serialize. */ if (!xdr_ypresp_all(xdrs, objp)) return(FALSE); if (objp->more == FALSE) return(TRUE); } } ypresp_all * ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_all result; /* * Set this here so that the client will be forced to make * at least one attempt to read from us even if all we're * doing is returning an error. */ result.more = TRUE; result.ypresp_all_u.val.key.keydat_len = 0; result.ypresp_all_u.val.key.keydat_val = ""; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.ypresp_all_u.val.stat = YP_YPERR; return (&result); } if (argp->domain == NULL || argp->map == NULL) { result.ypresp_all_u.val.stat = YP_BADARGS; return (&result); } /* * XXX If we hit the child limit, fail the request. * If we don't, and the map is large, we could block for * a long time in the parent. */ if (children >= MAX_CHILDREN) { result.ypresp_all_u.val.stat = YP_YPERR; return(&result); } /* * The ypproc_all procedure can take a while to complete. * Best to handle it in a subprocess so the parent doesn't * block. (Is there a better way to do this? Maybe with * async socket I/O?) */ if (!debug) { switch (yp_fork()) { case 0: break; case -1: yp_error("ypall fork(): %s", strerror(errno)); result.ypresp_all_u.val.stat = YP_YPERR; return(&result); break; default: children++; return (NULL); break; } } /* * Fix for PR #10971: don't let the child ypserv share * DB handles with the parent process. */ #ifdef DB_CACHE yp_flush_all(); #endif if (yp_select_map(argp->map, argp->domain, &result.ypresp_all_u.val.key, 0) != YP_TRUE) { result.ypresp_all_u.val.stat = yp_errno; return(&result); } /* Kick off the actual data transfer. */ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_my_ypresp_all, &result); /* * Proper fix for PR #10970: exit here so that we don't risk * having a child spawned from this sub-process. */ if (!debug) _exit(0); return &result; } ypresp_master * ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_master result; static char ypvalbuf[YPMAXRECORD]; keydat key = { MASTER_SZ, MASTER_STRING }; valdat val; result.peer = ""; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } /* * Note that we copy the data retrieved from the database to * a private buffer and NUL terminate the buffer rather than * terminating the data in place. We do this because by stuffing * a '\0' into data.data, we will actually be corrupting memory * allocated by the DB package. This is a bad thing now that we * cache DB handles rather than closing the database immediately. */ result.stat = yp_getbykey(&key, &val); if (result.stat == YP_TRUE) { bcopy(val.valdat_val, &ypvalbuf, val.valdat_len); ypvalbuf[val.valdat_len] = '\0'; result.peer = ypvalbuf; } else result.peer = ""; return (&result); } ypresp_order * ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_order result; keydat key = { ORDER_SZ, ORDER_STRING }; valdat val; result.ordernum = 0; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { #else if (yp_access(argp->map, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp->domain == NULL) { result.stat = YP_BADARGS; return (&result); } /* * We could just check the timestamp on the map file, * but that's a hack: we'll only know the last time the file * was touched, not the last time the database contents were * updated. */ if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) { result.stat = yp_errno; return(&result); } result.stat = yp_getbykey(&key, &val); if (result.stat == YP_TRUE) result.ordernum = atoi(val.valdat_val); else result.ordernum = 0; return (&result); } static void yp_maplist_free(struct ypmaplist *yp_maplist) { register struct ypmaplist *next; while (yp_maplist) { next = yp_maplist->next; free(yp_maplist->map); free(yp_maplist); yp_maplist = next; } return; } static struct ypmaplist * yp_maplist_create(const char *domain) { char yp_mapdir[MAXPATHLEN + 2]; char yp_mapname[MAXPATHLEN + 2]; struct ypmaplist *cur = NULL; struct ypmaplist *yp_maplist = NULL; DIR *dird; struct dirent *dirp; struct stat statbuf; snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain); if ((dird = opendir(yp_mapdir)) == NULL) { yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno)); return(NULL); } while ((dirp = readdir(dird)) != NULL) { if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) { snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s", yp_mapdir,dirp->d_name); if (stat(yp_mapname, &statbuf) < 0 || !S_ISREG(statbuf.st_mode)) continue; if ((cur = (struct ypmaplist *) malloc(sizeof(struct ypmaplist))) == NULL) { yp_error("malloc() failed"); closedir(dird); yp_maplist_free(yp_maplist); return(NULL); } if ((cur->map = strdup(dirp->d_name)) == NULL) { yp_error("strdup() failed: %s",strerror(errno)); closedir(dird); yp_maplist_free(yp_maplist); free(cur); return(NULL); } cur->next = yp_maplist; yp_maplist = cur; if (debug) yp_error("map: %s", yp_maplist->map); } } closedir(dird); return(yp_maplist); } ypresp_maplist * ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp) { static ypresp_maplist result = { 0, NULL }; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) { #else if (yp_access(NULL, (struct svc_req *)rqstp)) { #endif result.stat = YP_YPERR; return(&result); } if (argp == NULL) { result.stat = YP_BADARGS; return (&result); } if (yp_validdomain(*argp)) { result.stat = YP_NODOM; return (&result); } /* * We have to construct a linked list for the ypproc_maplist * procedure using dynamically allocated memory. Since the XDR * layer won't free this list for us, we have to deal with it * ourselves. We call yp_maplist_free() first to free any * previously allocated data we may have accumulated to insure * that we have only one linked list in memory at any given * time. */ yp_maplist_free(result.maps); if ((result.maps = yp_maplist_create(*argp)) == NULL) { yp_error("yp_maplist_create failed"); result.stat = YP_YPERR; return(&result); } else result.stat = YP_TRUE; return (&result); } /* * NIS v1 support. The nullproc, domain and domain_nonack * functions from v1 are identical to those in v2, so all * we have to do is hand off to them. * * The other functions are mostly just wrappers around their v2 * counterparts. For example, for the v1 'match' procedure, we * crack open the argument structure, make a request to the v2 * 'match' function, repackage the data into a v1 response and * then send it on its way. * * Note that we don't support the pull, push and get procedures. * There's little documentation available to show what they * do, and I suspect they're meant largely for map transfers * between master and slave servers. */ 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(v2_result, &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(v2_result, &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(v2_result, &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); }