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 *)⤅
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