xref: /openbsd/usr.sbin/ypserv/yppush/yppush.c (revision 133306f0)
1 /*	$OpenBSD: yppush.c,v 1.13 2001/01/11 23:38:07 deraadt 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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Mats O Jansson
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char rcsid[] = "$OpenBSD: yppush.c,v 1.13 2001/01/11 23:38:07 deraadt Exp $";
36 #endif /* not lint */
37 
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/resource.h>
41 #include <sys/signal.h>
42 #include <sys/wait.h>
43 
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <signal.h>
49 
50 #include <rpc/rpc.h>
51 #include <rpc/xdr.h>
52 #include <rpcsvc/yp.h>
53 #include <rpcsvc/ypclnt.h>
54 
55 #include <netdb.h>
56 #include <string.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 
60 #include "yplib_host.h"
61 #include "ypdef.h"
62 #include "ypdb.h"
63 
64 int  Verbose = 0;
65 char Domain[MAXHOSTNAMELEN], Map[255];
66 u_int32_t OrderNum;
67 char *master;
68 
69 extern void yppush_xfrrespprog_1(struct svc_req *request, SVCXPRT *xprt);
70 extern bool_t xdr_ypreq_xfr(XDR *, struct ypreq_xfr *);
71 
72 void
73 usage()
74 {
75 	fprintf(stderr, "Usage:\n");
76 	fprintf(stderr, "\typpush [-d domainname] [-h host] [-v] mapname\n");
77 	exit(1);
78 }
79 
80 void
81 _svc_run()
82 {
83 	fd_set *readfdsp = NULL;
84 	extern fd_set *__svc_fdset;
85 	extern int __svc_fdsetsize;
86 	struct timeval timeout;
87 
88 	timeout.tv_sec = 60;
89 	timeout.tv_usec = 0;
90 
91 	for (;;) {
92 		if (readfdsp)
93 			free(readfdsp);
94 		readfdsp = (fd_set *)calloc(howmany(__svc_fdsetsize, NFDBITS),
95 		    sizeof(fd_mask));
96 		if (readfdsp == NULL) {
97 			perror("calloc");
98 			return;
99 		}
100 		bcopy(__svc_fdset, readfdsp, howmany(__svc_fdsetsize, NFDBITS) *
101 		    sizeof(fd_mask));
102 
103 		switch (select(svc_maxfd, readfdsp, NULL,
104 		    NULL, &timeout)) {
105 		case -1:
106 			if (errno == EINTR)
107 				continue;
108 			perror("yppush: _svc_run: select failed");
109 			return;
110 		case 0:
111 			fprintf(stderr, "yppush: Callback timed out.\n");
112 			exit(0);
113 		default:
114 			svc_getreqset(readfdsp);
115 			break;
116 		}
117 	}
118 }
119 
120 void
121 req_xfr(pid, prog, transp, host, client)
122 pid_t pid;
123 u_int prog;
124 SVCXPRT *transp;
125 char *host;
126 CLIENT *client;
127 {
128 	struct ypreq_xfr request;
129 	struct timeval tv;
130 
131 	tv.tv_sec = 0;
132 	tv.tv_usec = 0;
133 
134 	request.map_parms.domain=(char *)&Domain;
135 	request.map_parms.map=(char *)&Map;
136 	request.map_parms.peer=master;
137 	request.map_parms.ordernum=OrderNum;
138 	request.transid=(u_int)pid;
139 	request.prog=prog;
140 	request.port=transp->xp_port;
141 
142 	if (Verbose)
143 		printf("%d: %s(%u@%s) -> %s@%s\n",
144 		    request.transid, request.map_parms.map,
145 		    request.map_parms.ordernum, host,
146 		    request.map_parms.peer, request.map_parms.domain);
147 	switch (clnt_call(client, YPPROC_XFR, xdr_ypreq_xfr, &request,
148 	    xdr_void, NULL, tv)) {
149 	case RPC_SUCCESS:
150 	case RPC_TIMEDOUT:
151 		break;
152 	default:
153 		clnt_perror(client, "yppush: Cannot call YPPROC_XFR");
154 		kill(pid, SIGTERM);
155 		break;
156 	}
157 }
158 
159 void
160 push(inlen, indata)
161 int inlen;
162 char *indata;
163 {
164 	char host[MAXHOSTNAMELEN];
165 	CLIENT *client;
166 	SVCXPRT *transp;
167 	int sock = RPC_ANYSOCK;
168 	u_int prog;
169 	bool_t sts = 0;
170 	pid_t pid;
171 	int status;
172 	struct rusage res;
173 
174 	snprintf(host,sizeof host,"%*.*s" ,inlen ,inlen, indata);
175 
176 	client = clnt_create(host, YPPROG, YPVERS, "tcp");
177 	if (client == NULL) {
178 		if (Verbose)
179 			fprintf(stderr,"Target Host: %s\n",host);
180 		clnt_pcreateerror("yppush: Cannot create client");
181 		return;
182 	}
183 
184 	transp = svcudp_create(sock);
185 	if (transp == NULL) {
186 		fprintf(stderr, "yppush: Cannot create callback transport.\n");
187 		return;
188 	}
189 	if (transp->xp_port >= IPPORT_RESERVED) {
190 		SVC_DESTROY(transp);
191 		fprintf(stderr, "yppush: Cannot allocate reserved port.\n");
192 		return;
193 	}
194 
195 	for (prog=0x40000000; prog<0x5fffffff; prog++) {
196 		if ((sts = svc_register(transp, prog, 1,
197 		    yppush_xfrrespprog_1, IPPROTO_UDP)))
198 			break;
199 	}
200 
201 	if (!sts) {
202 		fprintf(stderr, "yppush: Cannot register callback.\n");
203 		return;
204 	}
205 
206 	switch(pid=fork()) {
207 	case -1:
208 		fprintf(stderr, "yppush: Cannot fork.\n");
209 		exit(1);
210 	case 0:
211 		_svc_run();
212 		exit(0);
213 	default:
214 		close(transp->xp_sock);
215 		transp->xp_sock = -1;
216 		req_xfr(pid, prog, transp, host, client);
217 		wait4(pid, &status, 0, &res);
218 		svc_unregister(prog, 1);
219 		if (client != NULL)
220 			clnt_destroy(client);
221 		/* XXX transp leak? */
222 	}
223 
224 }
225 
226 int
227 pushit(instatus, inkey, inkeylen, inval, invallen, indata)
228 int instatus;
229 char *inkey;
230 int inkeylen;
231 char *inval;
232 int invallen;
233 char *indata;
234 {
235 	if (instatus != YP_TRUE)
236 		return instatus;
237 	push(invallen, inval);
238 	return 0;
239 }
240 
241 int
242 main(argc, argv)
243 int  argc;
244 char **argv;
245 {
246 	struct ypall_callback ypcb;
247 	extern char *optarg;
248 	extern int optind;
249 	char	*domain,*map,*hostname,*parallel,*timeout;
250 	int c, r, i;
251 	char *ypmap = "ypservers";
252 	CLIENT *client;
253 	static char map_path[MAXPATHLEN];
254 	struct stat finfo;
255 	DBM *yp_databas;
256 	char order_key[YP_LAST_LEN] = YP_LAST_KEY;
257 	datum o;
258 
259 	yp_get_default_domain(&domain);
260 	hostname = NULL;
261 	while ((c=getopt(argc, argv, "d:h:v")) != -1)
262 		switch(c) {
263 		case 'd':
264 			domain = optarg;
265 			break;
266 		case 'h':
267 			hostname = optarg;
268 			break;
269 		case 'p':
270 			parallel = optarg;
271 			break;
272 		case 't':
273 			timeout = optarg;
274 			break;
275 		case 'v':
276 			Verbose = 1;
277 			break;
278 		default:
279 			usage();
280 			/*NOTREACHED*/
281 		}
282 
283 	if (optind + 1 != argc )
284 		usage();
285 
286 	map = argv[optind];
287 
288 	strncpy(Domain,domain,sizeof(Domain)-1);
289 	Domain[sizeof(Domain)-1] = '\0';
290 	strncpy(Map,map,sizeof(Map)-1);
291 	Map[sizeof(Map)-1] = '\0';
292 
293 	/* Check domain */
294 	snprintf(map_path,sizeof map_path,"%s/%s",YP_DB_PATH,domain);
295 	if (!((stat(map_path, &finfo) == 0) &&
296 	      ((finfo.st_mode & S_IFMT) == S_IFDIR))) {
297 	  	fprintf(stderr,"yppush: Map does not exist.\n");
298 		exit(1);
299 	}
300 
301 
302 	/* Check map */
303 	snprintf(map_path,sizeof map_path,"%s/%s/%s%s",
304 	    YP_DB_PATH,domain,Map,YPDB_SUFFIX);
305 	if (!(stat(map_path, &finfo) == 0)) {
306 		fprintf(stderr,"yppush: Map does not exist.\n");
307 		exit(1);
308 	}
309 
310 	snprintf(map_path,sizeof map_path,"%s/%s/%s",YP_DB_PATH,domain,Map);
311 	yp_databas = ypdb_open(map_path,0,O_RDONLY);
312 	OrderNum=0xffffffff;
313 	if (yp_databas == 0) {
314 		fprintf(stderr, "yppush: %s%s: Cannot open database\n",
315 			map_path, YPDB_SUFFIX);
316 	} else {
317 		o.dptr = (char *) &order_key;
318 		o.dsize = YP_LAST_LEN;
319 		o=ypdb_fetch(yp_databas,o);
320 		if (o.dptr == NULL) {
321 			fprintf(stderr,
322 				"yppush: %s: Cannot determine order number\n",
323 				Map);
324 		} else {
325 			OrderNum=0;
326 			for (i=0; i<o.dsize-1; i++) {
327 				if (!isdigit(o.dptr[i])) {
328 					OrderNum=0xffffffff;
329 				}
330 			}
331 			if (OrderNum != 0) {
332 				fprintf(stderr,
333 				    "yppush: %s: Invalid order number '%s'\n",
334 				    Map, o.dptr);
335 			} else {
336 				OrderNum = atoi(o.dptr);
337 			}
338 		}
339 	}
340 
341 
342 	yp_bind(Domain);
343 
344 	r = yp_master(Domain, ypmap, &master);
345 	if (r != 0) {
346 		fprintf(stderr, "yppush: could not get ypservers map\n");
347 		exit(1);
348 	}
349 
350 	if (hostname != NULL) {
351 		push(strlen(hostname), hostname);
352 	} else {
353 		if (Verbose) {
354 			printf("Contacting master for ypservers (%s).\n",
355 			    master);
356 		}
357 
358 		client = yp_bind_host(master, YPPROG, YPVERS, 0, 1);
359 
360 		ypcb.foreach = pushit;
361 		ypcb.data = NULL;
362 		r = yp_all_host(client,Domain, ypmap, &ypcb);
363 	}
364 
365 	exit(0);
366 }
367 
368