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