xref: /openbsd-src/usr.sbin/ypserv/yppush/yppush.c (revision efea18b263485f6aa661cac8f1dab94e92e7a55a)
1 /*	$OpenBSD: yppush.c,v 1.32 2024/05/20 02:00:25 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 1995 Mats O Jansson <moj@stacken.kth.se>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/resource.h>
32 #include <sys/wait.h>
33 
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <signal.h>
38 #include <ctype.h>
39 
40 #include <rpc/rpc.h>
41 #include <rpc/xdr.h>
42 #include <rpcsvc/yp.h>
43 #include <rpcsvc/ypclnt.h>
44 
45 #include <netdb.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 
50 #include "yplib_host.h"
51 #include "ypdef.h"
52 #include "ypdb.h"
53 
54 int  Verbose = 0;
55 char Domain[HOST_NAME_MAX+1], Map[255];
56 u_int32_t OrderNum;
57 char *master;
58 
59 extern void yppush_xfrrespprog_1(struct svc_req *request, SVCXPRT *xprt);
60 
61 static void
usage(void)62 usage(void)
63 {
64 	fprintf(stderr,
65 	    "usage: yppush [-v] [-d domainname] [-h hostname] mapname\n");
66 	exit(1);
67 }
68 
69 static void
my_svc_run(void)70 my_svc_run(void)
71 {
72 	struct pollfd *pfd = NULL, *newp;
73 	int nready, saved_max_pollfd = 0;
74 
75 	for (;;) {
76 		if (svc_max_pollfd > saved_max_pollfd) {
77 			newp = reallocarray(pfd, svc_max_pollfd, sizeof(*pfd));
78 			if (newp == NULL) {
79 				free(pfd);
80 				perror("svc_run: - realloc failed");
81 				return;
82 			}
83 			pfd = newp;
84 			saved_max_pollfd = svc_max_pollfd;
85 		}
86 		memcpy(pfd, svc_pollfd, sizeof(*pfd) * svc_max_pollfd);
87 
88 		nready = poll(pfd, svc_max_pollfd, 60 * 1000);
89 		switch (nready) {
90 		case -1:
91 			if (errno == EINTR)
92 				continue;
93 			perror("yppush: my_svc_run: poll failed");
94 			free(pfd);
95 			return;
96 		case 0:
97 			fprintf(stderr, "yppush: Callback timed out.\n");
98 			exit(0);
99 		default:
100 			svc_getreq_poll(pfd, nready);
101 			break;
102 		}
103 	}
104 }
105 
106 static void
req_xfr(pid_t pid,u_int prog,SVCXPRT * transp,char * host,CLIENT * client)107 req_xfr(pid_t pid, u_int prog, SVCXPRT *transp, char *host, CLIENT *client)
108 {
109 	struct ypreq_xfr request;
110 	struct timeval tv;
111 
112 	tv.tv_sec = 0;
113 	tv.tv_usec = 0;
114 
115 	request.map_parms.domain=(char *)&Domain;
116 	request.map_parms.map=(char *)&Map;
117 	request.map_parms.peer=master;
118 	request.map_parms.ordernum=OrderNum;
119 	request.transid=(u_int)pid;
120 	request.prog=prog;
121 	request.port=transp->xp_port;
122 
123 	if (Verbose)
124 		printf("%d: %s(%u@%s) -> %s@%s\n",
125 		    request.transid, request.map_parms.map,
126 		    request.map_parms.ordernum, host,
127 		    request.map_parms.peer, request.map_parms.domain);
128 	switch (clnt_call(client, YPPROC_XFR, xdr_ypreq_xfr, &request,
129 	    xdr_void, NULL, tv)) {
130 	case RPC_SUCCESS:
131 	case RPC_TIMEDOUT:
132 		break;
133 	default:
134 		clnt_perror(client, "yppush: Cannot call YPPROC_XFR");
135 		kill(pid, SIGTERM);
136 		break;
137 	}
138 }
139 
140 static void
push(int inlen,char * indata)141 push(int inlen, char *indata)
142 {
143 	char host[HOST_NAME_MAX+1];
144 	CLIENT *client;
145 	SVCXPRT *transp;
146 	int sock = RPC_ANYSOCK, status;
147 	u_int prog;
148 	bool_t sts = 0;
149 	pid_t pid;
150 	struct rusage res;
151 
152 	snprintf(host, sizeof host, "%*.*s", inlen, inlen, indata);
153 
154 	client = clnt_create(host, YPPROG, YPVERS, "tcp");
155 	if (client == NULL) {
156 		if (Verbose)
157 			fprintf(stderr, "Target Host: %s\n", host);
158 		clnt_pcreateerror("yppush: Cannot create client");
159 		return;
160 	}
161 
162 	transp = svcudp_create(sock);
163 	if (transp == NULL) {
164 		fprintf(stderr, "yppush: Cannot create callback transport.\n");
165 		return;
166 	}
167 	if (transp->xp_port >= IPPORT_RESERVED) {
168 		SVC_DESTROY(transp);
169 		fprintf(stderr, "yppush: Cannot allocate reserved port.\n");
170 		return;
171 	}
172 
173 	for (prog=0x40000000; prog<0x5fffffff; prog++) {
174 		if ((sts = svc_register(transp, prog, 1,
175 		    yppush_xfrrespprog_1, IPPROTO_UDP)))
176 			break;
177 	}
178 
179 	if (!sts) {
180 		fprintf(stderr, "yppush: Cannot register callback.\n");
181 		return;
182 	}
183 
184 	switch (pid=fork()) {
185 	case -1:
186 		fprintf(stderr, "yppush: Cannot fork.\n");
187 		exit(1);
188 	case 0:
189 		my_svc_run();
190 		exit(0);
191 	default:
192 		close(transp->xp_sock);
193 		transp->xp_sock = -1;
194 		req_xfr(pid, prog, transp, host, client);
195 		wait4(pid, &status, 0, &res);
196 		svc_unregister(prog, 1);
197 		if (client != NULL)
198 			clnt_destroy(client);
199 		/* XXX transp leak? */
200 	}
201 
202 }
203 
204 static int
pushit(u_long instatus,char * inkey,int inkeylen,char * inval,int invallen,void * indata)205 pushit(u_long instatus, char *inkey, int inkeylen, char *inval, int invallen,
206     void *indata)
207 {
208 	if (instatus != YP_TRUE)
209 		return instatus;
210 	push(invallen, inval);
211 	return 0;
212 }
213 
214 int
main(int argc,char * argv[])215 main(int argc, char *argv[])
216 {
217 	struct ypall_callback ypcb;
218 	extern char *optarg;
219 	extern int optind;
220 	char	*domain, *map, *hostname;
221 	int c, r, i;
222 	char *ypmap = "ypservers";
223 	CLIENT *client;
224 	static char map_path[PATH_MAX];
225 	struct stat finfo;
226 	DBM *yp_databas;
227 	char order_key[YP_LAST_LEN] = YP_LAST_KEY;
228 	datum o;
229 
230 	yp_get_default_domain(&domain);
231 	hostname = NULL;
232 	while ((c=getopt(argc, argv, "d:h:v")) != -1)
233 		switch (c) {
234 		case 'd':
235 			domain = optarg;
236 			break;
237 		case 'h':
238 			hostname = optarg;
239 			break;
240 		case 'v':
241 			Verbose = 1;
242 			break;
243 		default:
244 			usage();
245 			/*NOTREACHED*/
246 		}
247 
248 	if (optind + 1 != argc )
249 		usage();
250 
251 	map = argv[optind];
252 
253 	strncpy(Domain, domain, sizeof(Domain)-1);
254 	Domain[sizeof(Domain)-1] = '\0';
255 	strncpy(Map, map, sizeof(Map)-1);
256 	Map[sizeof(Map)-1] = '\0';
257 
258 	/* Check domain */
259 	snprintf(map_path, sizeof map_path, "%s/%s", YP_DB_PATH, domain);
260 	if (!((stat(map_path, &finfo) == 0) && S_ISDIR(finfo.st_mode))) {
261 		fprintf(stderr, "yppush: Map does not exist.\n");
262 		exit(1);
263 	}
264 
265 	/* Check map */
266 	snprintf(map_path, sizeof map_path, "%s/%s/%s%s",
267 	    YP_DB_PATH, domain, Map, YPDB_SUFFIX);
268 	if (!(stat(map_path, &finfo) == 0)) {
269 		fprintf(stderr, "yppush: Map does not exist.\n");
270 		exit(1);
271 	}
272 
273 	snprintf(map_path, sizeof map_path, "%s/%s/%s",
274 	    YP_DB_PATH, domain, Map);
275 	yp_databas = ypdb_open(map_path, 0, O_RDONLY);
276 	OrderNum=0xffffffff;
277 	if (yp_databas == 0) {
278 		fprintf(stderr, "yppush: %s%s: Cannot open database\n",
279 		    map_path, YPDB_SUFFIX);
280 	} else {
281 		o.dptr = (char *) &order_key;
282 		o.dsize = YP_LAST_LEN;
283 		o = ypdb_fetch(yp_databas, o);
284 		if (o.dptr == NULL) {
285 			fprintf(stderr,
286 			    "yppush: %s: Cannot determine order number\n",
287 			    Map);
288 		} else {
289 			OrderNum=0;
290 			for (i=0; i<o.dsize-1; i++) {
291 				if (!isdigit((unsigned char)o.dptr[i]))
292 					OrderNum=0xffffffff;
293 			}
294 			if (OrderNum != 0) {
295 				fprintf(stderr,
296 				    "yppush: %s: Invalid order number '%s'\n",
297 				    Map, o.dptr);
298 			} else {
299 				OrderNum = atoi(o.dptr);
300 			}
301 		}
302 	}
303 
304 	yp_bind(Domain);
305 
306 	r = yp_master(Domain, ypmap, &master);
307 	if (r != 0) {
308 		fprintf(stderr, "yppush: could not get ypservers map\n");
309 		exit(1);
310 	}
311 
312 	if (hostname != NULL) {
313 		push(strlen(hostname), hostname);
314 	} else {
315 		if (Verbose) {
316 			printf("Contacting master for ypservers (%s).\n",
317 			    master);
318 		}
319 
320 		client = yp_bind_host(master, YPPROG, YPVERS, 0, 1);
321 
322 		ypcb.foreach = pushit;
323 		ypcb.data = NULL;
324 		r = yp_all_host(client, Domain, ypmap, &ypcb);
325 	}
326 
327 	exit(0);
328 }
329