1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
27 */
28
29/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30/*	  All Rights Reserved   */
31
32/*
33 * Portions of this source code were derived from Berkeley
34 * under license from the Regents of the University of
35 * California.
36 */
37
38#pragma ident	"%Z%%M%	%I%	%E% SMI"
39
40#include "mt.h"
41#include <stdlib.h>
42#include <unistd.h>
43#include <rpc/rpc.h>
44#include <sys/types.h>
45#include "yp_b.h"
46#include <rpcsvc/yp_prot.h>
47#include <rpcsvc/ypclnt.h>
48#include <string.h>
49
50static int domaster(char *, char *, struct dom_binding *, struct timeval,
51    char **);
52extern int __yp_master_rsvdport(char *, char *, char **);
53
54/*
55 * This checks parameters, and implements the outer "until binding success"
56 * loop.
57 */
58int
59yp_master(char *domain, char *map, char **master)
60{
61	size_t domlen;
62	size_t maplen;
63	int reason;
64	struct dom_binding *pdomb;
65
66	if ((map == NULL) || (domain == NULL))
67		return (YPERR_BADARGS);
68
69	domlen = strlen(domain);
70	maplen = strlen(map);
71
72	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
73	    (maplen == 0) || (maplen > YPMAXMAP) ||
74	    (master == NULL))
75		return (YPERR_BADARGS);
76
77	for (;;) {
78
79		if (reason = __yp_dobind(domain, &pdomb))
80			return (reason);
81
82		if (pdomb->dom_binding->ypbind_hi_vers >= YPVERS) {
83
84			reason = domaster(domain, map, pdomb, _ypserv_timeout,
85			    master);
86
87			__yp_rel_binding(pdomb);
88			if (reason == YPERR_RPC) {
89				yp_unbind(domain);
90				(void) sleep(_ypsleeptime);
91			} else {
92				break;
93			}
94		} else {
95			__yp_rel_binding(pdomb);
96			return (YPERR_VERS);
97		}
98	}
99
100	if (reason == YPERR_MAP && geteuid() == 0) {
101		/*
102		 * Lookup could be for a secure map; fail over to retry
103		 * from a reserved port. Only useful to try this if we're
104		 * the super user.
105		 */
106		int rsvdreason;
107		rsvdreason = __yp_master_rsvdport(domain, map, master);
108		if (rsvdreason == 0)
109			reason = rsvdreason;
110	}
111
112	return (reason);
113}
114
115
116/*
117 * This function is identical to 'yp_master' with the exception that it calls
118 * '__yp_dobind_rsvdport' rather than '__yp_dobind'
119 */
120int
121__yp_master_rsvdport(char *domain, char *map, char **master)
122{
123	size_t domlen;
124	size_t maplen;
125	int reason;
126	struct dom_binding *pdomb;
127
128	if ((map == NULL) || (domain == NULL))
129		return (YPERR_BADARGS);
130
131	domlen = strlen(domain);
132	maplen = strlen(map);
133
134	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
135	    (maplen == 0) || (maplen > YPMAXMAP) ||
136	    (master == NULL))
137		return (YPERR_BADARGS);
138
139	for (;;) {
140
141		if (reason = __yp_dobind_rsvdport(domain, &pdomb))
142			return (reason);
143
144		if (pdomb->dom_binding->ypbind_hi_vers >= YPVERS) {
145
146			reason = domaster(domain, map, pdomb, _ypserv_timeout,
147			    master);
148
149			/*
150			 * Have to free the binding since the reserved
151			 * port bindings are not cached.
152			 */
153			__yp_rel_binding(pdomb);
154			free_dom_binding(pdomb);
155			if (reason == YPERR_RPC) {
156				yp_unbind(domain);
157				(void) sleep(_ypsleeptime);
158			} else {
159				break;
160			}
161		} else {
162			/*
163			 * Have to free the binding since the reserved
164			 * port bindings are not cached.
165			 */
166			__yp_rel_binding(pdomb);
167			free_dom_binding(pdomb);
168			return (YPERR_VERS);
169		}
170	}
171	return (reason);
172}
173
174/*
175 * This talks v2 to ypserv
176 */
177static int
178domaster(char *domain, char *map, struct dom_binding *pdomb,
179					struct timeval timeout, char **master)
180{
181	struct ypreq_nokey req;
182	struct ypresp_master resp;
183	unsigned int retval = 0;
184
185	req.domain = domain;
186	req.map = map;
187	(void) memset(&resp, 0, sizeof (struct ypresp_master));
188
189	/*
190	 * Do the get_master request.  If the rpc call failed, return with
191	 * status from this point.
192	 */
193
194	if (clnt_call(pdomb->dom_client,
195			YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey,
196		    (char *)&req, (xdrproc_t)xdr_ypresp_master, (char *)&resp,
197		    timeout) != RPC_SUCCESS)
198		return (YPERR_RPC);
199
200	/* See if the request succeeded */
201
202	if (resp.status != YP_TRUE)
203		retval = ypprot_err(resp.status);
204
205	/* Get some memory which the user can get rid of as they like */
206
207	if (!retval && ((*master = malloc(strlen(resp.master) + 1)) == NULL))
208		retval = YPERR_RESRC;
209
210	if (!retval)
211		(void) strcpy(*master, resp.master);
212
213	CLNT_FREERES(pdomb->dom_client,
214		(xdrproc_t)xdr_ypresp_master, (char *)&resp);
215	return (retval);
216}
217