File: | src/usr.sbin/ypbind/ypbind.c |
Warning: | line 662, column 3 Address of stack memory associated with local variable 'dom' is still referred to by the global variable 'rmtca' upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ypbind.c,v 1.79 2023/11/27 18:37:53 tb Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 1992, 1993, 1996, 1997, 1998 Theo de Raadt <deraadt@openbsd.org> | |||
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/socket.h> | |||
31 | #include <sys/stat.h> | |||
32 | #include <sys/uio.h> | |||
33 | #include <sys/syslog.h> | |||
34 | ||||
35 | #include <arpa/inet.h> | |||
36 | #include <net/if.h> | |||
37 | #include <rpc/rpc.h> | |||
38 | #include <rpc/xdr.h> | |||
39 | #include <rpc/pmap_clnt.h> | |||
40 | #include <rpc/pmap_prot.h> | |||
41 | #include <rpc/pmap_rmt.h> | |||
42 | #include <rpcsvc/yp.h> | |||
43 | #include <rpcsvc/ypclnt.h> | |||
44 | ||||
45 | #include <ctype.h> | |||
46 | #include <dirent.h> | |||
47 | #include <err.h> | |||
48 | #include <errno(*__errno()).h> | |||
49 | #include <fcntl.h> | |||
50 | #include <ifaddrs.h> | |||
51 | #include <limits.h> | |||
52 | #include <netdb.h> | |||
53 | #include <poll.h> | |||
54 | #include <stdio.h> | |||
55 | #include <stdlib.h> | |||
56 | #include <string.h> | |||
57 | #include <unistd.h> | |||
58 | ||||
59 | #define SERVERSDIR"/etc/yp" "/etc/yp" | |||
60 | #define BINDINGDIR"/var/yp/binding" "/var/yp/binding" | |||
61 | ||||
62 | struct _dom_binding { | |||
63 | struct _dom_binding *dom_pnext; | |||
64 | char dom_domain[YPMAXDOMAIN64 + 1]; | |||
65 | struct sockaddr_in dom_server_addr; | |||
66 | unsigned short int dom_server_port; | |||
67 | int dom_socket; | |||
68 | CLIENT *dom_client; | |||
69 | long dom_vers; | |||
70 | time_t dom_check_t; | |||
71 | time_t dom_ask_t; | |||
72 | int dom_lockfd; | |||
73 | int dom_alive; | |||
74 | u_int32_t dom_xid; | |||
75 | char dom_servlist[PATH_MAX1024]; | |||
76 | FILE *dom_servlistfp; | |||
77 | }; | |||
78 | ||||
79 | void rpc_received(char *dom, struct sockaddr_in *raddrp, int force); | |||
80 | void checkwork(void); | |||
81 | enum clnt_stat handle_replies(void); | |||
82 | enum clnt_stat handle_ping(void); | |||
83 | int broadcast(struct _dom_binding *ypdb, char *, int); | |||
84 | int direct(struct _dom_binding *ypdb, char *, int); | |||
85 | int ping(struct _dom_binding *ypdb); | |||
86 | int pings(struct _dom_binding *ypdb); | |||
87 | ||||
88 | char *domain; | |||
89 | ||||
90 | struct _dom_binding *ypbindlist; | |||
91 | int check; | |||
92 | ||||
93 | #define YPSET_NO0 0 | |||
94 | #define YPSET_LOCAL1 1 | |||
95 | #define YPSET_ALL2 2 | |||
96 | int ypsetmode = YPSET_NO0; | |||
97 | int insecure = 0; | |||
98 | ||||
99 | int rpcsock, pingsock; | |||
100 | struct rmtcallargs rmtca; | |||
101 | struct rmtcallres rmtcr; | |||
102 | bool_tint32_t rmtcr_outval; | |||
103 | u_long rmtcr_port; | |||
104 | SVCXPRT *udptransp, *tcptransp; | |||
105 | SVCXPRT *ludptransp, *ltcptransp; | |||
106 | ||||
107 | struct _dom_binding *xid2ypdb(u_int32_t xid); | |||
108 | u_int32_t unique_xid(struct _dom_binding *ypdb); | |||
109 | ||||
110 | /* | |||
111 | * We name the local RPC functions ypbindproc_XXX_2x() instead | |||
112 | * of ypbindproc_XXX_2() because we need to pass an additional | |||
113 | * parameter. ypbindproc_setdom_2x() does a security check, and | |||
114 | * hence needs the CLIENT * | |||
115 | * | |||
116 | * We are faced with either making ypbindprog_2() do the security | |||
117 | * check before calling ypbindproc_setdom_2().. or we can simply | |||
118 | * declare sun's interface insufficient and roll our own. | |||
119 | */ | |||
120 | ||||
121 | static void * | |||
122 | ypbindproc_null_2x(SVCXPRT *transp, void *argp, CLIENT *clnt) | |||
123 | { | |||
124 | static char res; | |||
125 | ||||
126 | memset(&res, 0, sizeof(res)); | |||
127 | return (void *)&res; | |||
128 | } | |||
129 | ||||
130 | static struct ypbind_resp * | |||
131 | ypbindproc_domain_2x(SVCXPRT *transp, domainname *argp, CLIENT *clnt) | |||
132 | { | |||
133 | static struct ypbind_resp res; | |||
134 | struct _dom_binding *ypdb; | |||
135 | char path[PATH_MAX1024]; | |||
136 | time_t now; | |||
137 | int count = 0; | |||
138 | ||||
139 | if (strchr((char *)argp, '/')) | |||
140 | return NULL((void *)0); | |||
141 | ||||
142 | memset(&res, 0, sizeof(res)); | |||
143 | res.ypbind_status = YPBIND_FAIL_VAL; | |||
144 | ||||
145 | for (ypdb = ypbindlist; ypdb && count < 100; ypdb = ypdb->dom_pnext) | |||
146 | count++; | |||
147 | if (count >= 100) | |||
148 | return NULL((void *)0); /* prevent DOS: sorry, you lose */ | |||
149 | ||||
150 | for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) | |||
151 | if (!strcmp(ypdb->dom_domain, *argp)) | |||
152 | break; | |||
153 | ||||
154 | if (ypdb == NULL((void *)0)) { | |||
155 | ypdb = malloc(sizeof *ypdb); | |||
156 | if (ypdb == NULL((void *)0)) | |||
157 | return NULL((void *)0); | |||
158 | memset(ypdb, 0, sizeof *ypdb); | |||
159 | strncpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain-1); | |||
160 | ypdb->dom_domain[sizeof ypdb->dom_domain-1] = '\0'; | |||
161 | ypdb->dom_vers = YPVERS((u_long)2); | |||
162 | ypdb->dom_alive = 0; | |||
163 | ypdb->dom_lockfd = -1; | |||
164 | snprintf(path, sizeof path, "%s/%s.%d", BINDINGDIR"/var/yp/binding", | |||
165 | ypdb->dom_domain, (int)ypdb->dom_vers); | |||
166 | unlink(path); | |||
167 | snprintf(ypdb->dom_servlist, sizeof ypdb->dom_servlist, | |||
168 | "%s/%s", SERVERSDIR"/etc/yp", ypdb->dom_domain); | |||
169 | ypdb->dom_servlistfp = fopen(ypdb->dom_servlist, "r"); | |||
170 | ypdb->dom_xid = unique_xid(ypdb); | |||
171 | ypdb->dom_pnext = ypbindlist; | |||
172 | ypbindlist = ypdb; | |||
173 | check++; | |||
174 | return NULL((void *)0); | |||
175 | } | |||
176 | ||||
177 | if (ypdb->dom_alive == 0) | |||
178 | return NULL((void *)0); | |||
179 | ||||
180 | #ifdef HEURISTIC1 | |||
181 | time(&now); | |||
182 | if (now < ypdb->dom_ask_t + 5) { | |||
183 | /* | |||
184 | * Hmm. More than 2 requests in 5 seconds have indicated | |||
185 | * that my binding is possibly incorrect. | |||
186 | * Ok, do an immediate poll of the server. | |||
187 | */ | |||
188 | if (ypdb->dom_check_t >= now) { | |||
189 | /* don't flood it */ | |||
190 | ypdb->dom_check_t = 0; | |||
191 | check++; | |||
192 | } | |||
193 | } | |||
194 | ypdb->dom_ask_t = now; | |||
195 | #endif | |||
196 | ||||
197 | res.ypbind_status = YPBIND_SUCC_VAL; | |||
198 | memmove(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, | |||
199 | &ypdb->dom_server_addr.sin_addr, | |||
200 | sizeof(res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr)); | |||
201 | memmove(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, | |||
202 | &ypdb->dom_server_port, | |||
203 | sizeof(res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port)); | |||
204 | #ifdef DEBUG | |||
205 | printf("domain %s at %s/%d\n", ypdb->dom_domain, | |||
206 | inet_ntoa(ypdb->dom_server_addr.sin_addr), | |||
207 | ntohs(ypdb->dom_server_addr.sin_port)(__uint16_t)(__builtin_constant_p(ypdb->dom_server_addr.sin_port ) ? (__uint16_t)(((__uint16_t)(ypdb->dom_server_addr.sin_port ) & 0xffU) << 8 | ((__uint16_t)(ypdb->dom_server_addr .sin_port) & 0xff00U) >> 8) : __swap16md(ypdb->dom_server_addr .sin_port))); | |||
208 | #endif | |||
209 | return &res; | |||
210 | } | |||
211 | ||||
212 | static bool_tint32_t * | |||
213 | ypbindproc_setdom_2x(SVCXPRT *transp, struct ypbind_setdom *argp, CLIENT *clnt) | |||
214 | { | |||
215 | struct sockaddr_in *fromsin, bindsin; | |||
216 | static bool_tint32_t res = 1; | |||
217 | ||||
218 | fromsin = svc_getcaller(transp)(&(transp)->xp_raddr); | |||
219 | ||||
220 | switch (ypsetmode) { | |||
221 | case YPSET_LOCAL1: | |||
222 | if (transp != ludptransp && transp != ltcptransp) { | |||
223 | syslog(LOG_WARNING4, "attempted spoof of ypsetme"); | |||
224 | svcerr_weakauth(transp); | |||
225 | return NULL((void *)0); | |||
226 | } | |||
227 | if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001))))) { | |||
228 | svcerr_weakauth(transp); | |||
229 | return NULL((void *)0); | |||
230 | } | |||
231 | break; | |||
232 | case YPSET_ALL2: | |||
233 | break; | |||
234 | case YPSET_NO0: | |||
235 | default: | |||
236 | svcerr_weakauth(transp); | |||
237 | return NULL((void *)0); | |||
238 | } | |||
239 | ||||
240 | if (ntohs(fromsin->sin_port)(__uint16_t)(__builtin_constant_p(fromsin->sin_port) ? (__uint16_t )(((__uint16_t)(fromsin->sin_port) & 0xffU) << 8 | ((__uint16_t)(fromsin->sin_port) & 0xff00U) >> 8) : __swap16md(fromsin->sin_port)) >= IPPORT_RESERVED1024) { | |||
241 | svcerr_weakauth(transp); | |||
242 | return NULL((void *)0); | |||
243 | } | |||
244 | ||||
245 | if (argp->ypsetdom_vers != YPVERS((u_long)2)) { | |||
246 | svcerr_noprog(transp); | |||
247 | return NULL((void *)0); | |||
248 | } | |||
249 | ||||
250 | memset(&bindsin, 0, sizeof bindsin); | |||
251 | bindsin.sin_family = AF_INET2; | |||
252 | bindsin.sin_len = sizeof(bindsin); | |||
253 | memcpy(&bindsin.sin_addr, &argp->ypsetdom_binding.ypbind_binding_addr, | |||
254 | sizeof(argp->ypsetdom_binding.ypbind_binding_addr)); | |||
255 | memcpy(&bindsin.sin_port, &argp->ypsetdom_binding.ypbind_binding_port, | |||
256 | sizeof(argp->ypsetdom_binding.ypbind_binding_port)); | |||
257 | rpc_received(argp->ypsetdom_domain, &bindsin, 1); | |||
258 | ||||
259 | return &res; | |||
260 | } | |||
261 | ||||
262 | static void | |||
263 | ypbindprog_2(struct svc_req *rqstp, SVCXPRT *transp) | |||
264 | { | |||
265 | union argument { | |||
266 | domainname ypbindproc_domain_2_arg; | |||
267 | struct ypbind_setdom ypbindproc_setdom_2_arg; | |||
268 | } argument; | |||
269 | struct authunix_parms *creds; | |||
270 | char *result; | |||
271 | xdrproc_t xdr_argument, xdr_result; | |||
272 | char *(*local)(SVCXPRT *, union argument *, struct svc_req *); | |||
273 | ||||
274 | switch (rqstp->rq_proc) { | |||
275 | case YPBINDPROC_NULL((u_long)0): | |||
276 | xdr_argument = xdr_void; | |||
277 | xdr_result = xdr_void; | |||
278 | local = (char *(*)(SVCXPRT *, union argument *, struct svc_req *)) | |||
279 | ypbindproc_null_2x; | |||
280 | break; | |||
281 | ||||
282 | case YPBINDPROC_DOMAIN((u_long)1): | |||
283 | xdr_argument = xdr_domainname; | |||
284 | xdr_result = xdr_ypbind_resp; | |||
285 | local = (char *(*)(SVCXPRT *, union argument *, struct svc_req *)) | |||
286 | ypbindproc_domain_2x; | |||
287 | break; | |||
288 | ||||
289 | case YPBINDPROC_SETDOM((u_long)2): | |||
290 | switch (rqstp->rq_cred.oa_flavor) { | |||
291 | case AUTH_UNIX1: | |||
292 | creds = (struct authunix_parms *)rqstp->rq_clntcred; | |||
293 | if (creds->aup_uid != 0) { | |||
294 | svcerr_auth(transp, AUTH_BADCRED); | |||
295 | return; | |||
296 | } | |||
297 | break; | |||
298 | default: | |||
299 | svcerr_auth(transp, AUTH_TOOWEAK); | |||
300 | return; | |||
301 | } | |||
302 | ||||
303 | xdr_argument = xdr_ypbind_setdom; | |||
304 | xdr_result = xdr_void; | |||
305 | local = (char *(*)(SVCXPRT *, union argument *, struct svc_req *)) | |||
306 | ypbindproc_setdom_2x; | |||
307 | break; | |||
308 | ||||
309 | default: | |||
310 | svcerr_noproc(transp); | |||
311 | return; | |||
312 | } | |||
313 | memset(&argument, 0, sizeof(argument)); | |||
314 | if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)(*(transp)->xp_ops->xp_getargs)((transp), (xdr_argument ), ((caddr_t)&argument))) { | |||
315 | svcerr_decode(transp); | |||
316 | return; | |||
317 | } | |||
318 | result = (*local)(transp, &argument, rqstp); | |||
319 | if (result != NULL((void *)0) && !svc_sendreply(transp, xdr_result, result)) { | |||
320 | svcerr_systemerr(transp); | |||
321 | } | |||
322 | return; | |||
323 | } | |||
324 | ||||
325 | static void | |||
326 | usage(void) | |||
327 | { | |||
328 | fprintf(stderr(&__sF[2]), "usage: ypbind [-insecure] [-ypset] [-ypsetme]\n"); | |||
329 | exit(1); | |||
330 | } | |||
331 | ||||
332 | int | |||
333 | main(int argc, char *argv[]) | |||
334 | { | |||
335 | char path[PATH_MAX1024]; | |||
336 | struct sockaddr_in sin; | |||
337 | struct pollfd *pfd = NULL((void *)0); | |||
338 | int width = 0, nready, lsock; | |||
339 | socklen_t len; | |||
340 | int evil = 0, one = 1; | |||
341 | DIR *dirp; | |||
342 | struct dirent *dent; | |||
343 | ||||
344 | if (yp_get_default_domain(&domain) != 0 || domain[0] == '\0') { | |||
| ||||
345 | fprintf(stderr(&__sF[2]), "domainname not set. Aborting.\n"); | |||
346 | exit(1); | |||
347 | } | |||
348 | ||||
349 | while (--argc) { | |||
350 | ++argv; | |||
351 | if (!strcmp("-insecure", *argv)) | |||
352 | insecure = 1; | |||
353 | else if (!strcmp("-ypset", *argv)) | |||
354 | ypsetmode = YPSET_ALL2; | |||
355 | else if (!strcmp("-ypsetme", *argv)) | |||
356 | ypsetmode = YPSET_LOCAL1; | |||
357 | else | |||
358 | usage(); | |||
359 | } | |||
360 | ||||
361 | /* blow away everything in BINDINGDIR */ | |||
362 | dirp = opendir(BINDINGDIR"/var/yp/binding"); | |||
363 | if (dirp) { | |||
364 | while ((dent = readdir(dirp))) { | |||
365 | if (!strcmp(dent->d_name, ".") || | |||
366 | !strcmp(dent->d_name, "..")) | |||
367 | continue; | |||
368 | (void)unlinkat(dirfd(dirp), dent->d_name, 0); | |||
369 | } | |||
370 | closedir(dirp); | |||
371 | } else { | |||
372 | (void)mkdir(BINDINGDIR"/var/yp/binding", 0755); | |||
373 | } | |||
374 | ||||
375 | (void)pmap_unset(YPBINDPROG((u_long)100007), YPBINDVERS((u_long)2)); | |||
376 | ||||
377 | udptransp = svcudp_create(RPC_ANYSOCK-1); | |||
378 | if (udptransp == NULL((void *)0)) { | |||
379 | fprintf(stderr(&__sF[2]), "cannot create udp service.\n"); | |||
380 | exit(1); | |||
381 | } | |||
382 | if (!svc_register(udptransp, YPBINDPROG((u_long)100007), YPBINDVERS((u_long)2), ypbindprog_2, | |||
383 | IPPROTO_UDP17)) { | |||
384 | fprintf(stderr(&__sF[2]), | |||
385 | "unable to register (YPBINDPROG, YPBINDVERS, udp).\n"); | |||
386 | exit(1); | |||
387 | } | |||
388 | ||||
389 | tcptransp = svctcp_create(RPC_ANYSOCK-1, 0, 0); | |||
390 | if (tcptransp == NULL((void *)0)) { | |||
391 | fprintf(stderr(&__sF[2]), "cannot create tcp service.\n"); | |||
392 | exit(1); | |||
393 | } | |||
394 | if (!svc_register(tcptransp, YPBINDPROG((u_long)100007), YPBINDVERS((u_long)2), ypbindprog_2, | |||
395 | IPPROTO_TCP6)) { | |||
396 | fprintf(stderr(&__sF[2]), | |||
397 | "unable to register (YPBINDPROG, YPBINDVERS, tcp).\n"); | |||
398 | exit(1); | |||
399 | } | |||
400 | ||||
401 | if (ypsetmode
| |||
402 | /* build UDP local port */ | |||
403 | if ((lsock = socket(AF_INET2, SOCK_DGRAM2, IPPROTO_UDP17)) == -1) { | |||
404 | syslog(LOG_ERR3, "cannot create local udp socket: %m"); | |||
405 | exit(1); | |||
406 | } | |||
407 | (void)setsockopt(lsock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &one, | |||
408 | (socklen_t)sizeof one); | |||
409 | len = sizeof(sin); | |||
410 | if (getsockname(udptransp->xp_sock, (struct sockaddr *)&sin, | |||
411 | &len) == -1) { | |||
412 | syslog(LOG_ERR3, "cannot getsockname local udp: %m"); | |||
413 | exit(1); | |||
414 | } | |||
415 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001)))); | |||
416 | sin.sin_port = htons(udptransp->xp_port)(__uint16_t)(__builtin_constant_p(udptransp->xp_port) ? (__uint16_t )(((__uint16_t)(udptransp->xp_port) & 0xffU) << 8 | ((__uint16_t)(udptransp->xp_port) & 0xff00U) >> 8) : __swap16md(udptransp->xp_port)); | |||
417 | if (bind(lsock, (struct sockaddr *)&sin, len) != 0) { | |||
418 | syslog(LOG_ERR3, "cannot bind local udp: %m"); | |||
419 | exit(1); | |||
420 | } | |||
421 | if ((ludptransp = svcudp_create(lsock)) == NULL((void *)0)) { | |||
422 | fprintf(stderr(&__sF[2]), "cannot create udp service.\n"); | |||
423 | exit(1); | |||
424 | } | |||
425 | ||||
426 | /* build TCP local port */ | |||
427 | if ((lsock = socket(AF_INET2, SOCK_STREAM1, IPPROTO_TCP6)) == -1) { | |||
428 | syslog(LOG_ERR3, "cannot create udp socket: %m"); | |||
429 | exit(1); | |||
430 | } | |||
431 | (void)setsockopt(lsock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &one, | |||
432 | (socklen_t)sizeof one); | |||
433 | len = sizeof(sin); | |||
434 | if (getsockname(tcptransp->xp_sock, (struct sockaddr *)&sin, | |||
435 | &len) == -1) { | |||
436 | syslog(LOG_ERR3, "cannot getsockname udp: %m"); | |||
437 | exit(1); | |||
438 | } | |||
439 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001)))); | |||
440 | sin.sin_port = htons(tcptransp->xp_port)(__uint16_t)(__builtin_constant_p(tcptransp->xp_port) ? (__uint16_t )(((__uint16_t)(tcptransp->xp_port) & 0xffU) << 8 | ((__uint16_t)(tcptransp->xp_port) & 0xff00U) >> 8) : __swap16md(tcptransp->xp_port)); | |||
441 | if (bind(lsock, (struct sockaddr *)&sin, len) == -1) { | |||
442 | syslog(LOG_ERR3, "cannot bind local tcp: %m"); | |||
443 | exit(1); | |||
444 | } | |||
445 | if ((ltcptransp = svctcp_create(lsock, 0, 0)) == NULL((void *)0)) { | |||
446 | fprintf(stderr(&__sF[2]), "cannot create tcp service.\n"); | |||
447 | exit(1); | |||
448 | } | |||
449 | } | |||
450 | ||||
451 | if ((rpcsock = socket(AF_INET2, SOCK_DGRAM2 | SOCK_NONBLOCK0x4000, 0)) == -1) { | |||
452 | perror("socket"); | |||
453 | return -1; | |||
454 | } | |||
455 | memset(&sin, 0, sizeof sin); | |||
456 | sin.sin_family = AF_INET2; | |||
457 | sin.sin_addr.s_addr = htonl(INADDR_ANY)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x00000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x00000000)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x00000000 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x00000000)))); | |||
458 | sin.sin_port = 0; | |||
459 | bindresvport(rpcsock, &sin); | |||
460 | ||||
461 | if ((pingsock = socket(AF_INET2, SOCK_DGRAM2 | SOCK_NONBLOCK0x4000, 0)) == -1) { | |||
462 | perror("socket"); | |||
463 | return -1; | |||
464 | } | |||
465 | memset(&sin, 0, sizeof sin); | |||
466 | sin.sin_family = AF_INET2; | |||
467 | sin.sin_addr.s_addr = htonl(INADDR_ANY)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x00000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x00000000)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x00000000 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x00000000)))); | |||
468 | sin.sin_port = 0; | |||
469 | bindresvport(pingsock, &sin); | |||
470 | ||||
471 | setsockopt(rpcsock, SOL_SOCKET0xffff, SO_BROADCAST0x0020, &one, | |||
472 | (socklen_t)sizeof(one)); | |||
473 | rmtca.prog = YPPROG((u_long)100004); | |||
474 | rmtca.vers = YPVERS((u_long)2); | |||
475 | rmtca.proc = YPPROC_DOMAIN_NONACK((u_long)2); | |||
476 | rmtca.xdr_args = NULL((void *)0); /* set at call time */ | |||
477 | rmtca.args_ptr = NULL((void *)0); /* set at call time */ | |||
478 | rmtcr.port_ptr = &rmtcr_port; | |||
479 | rmtcr.xdr_results = xdr_bool; | |||
480 | rmtcr.results_ptr = (caddr_t)&rmtcr_outval; | |||
481 | ||||
482 | if (strchr(domain, '/')) | |||
483 | errx(1, "bad domainname %s", domain); | |||
484 | ||||
485 | /* build initial domain binding, make it "unsuccessful" */ | |||
486 | ypbindlist = malloc(sizeof *ypbindlist); | |||
487 | if (ypbindlist == NULL((void *)0)) | |||
488 | errx(1, "no memory"); | |||
489 | memset(ypbindlist, 0, sizeof *ypbindlist); | |||
490 | strncpy(ypbindlist->dom_domain, domain, sizeof ypbindlist->dom_domain-1); | |||
491 | ypbindlist->dom_domain[sizeof (ypbindlist->dom_domain)-1] = '\0'; | |||
492 | ypbindlist->dom_vers = YPVERS((u_long)2); | |||
493 | snprintf(ypbindlist->dom_servlist, sizeof ypbindlist->dom_servlist, | |||
494 | "%s/%s", SERVERSDIR"/etc/yp", ypbindlist->dom_domain); | |||
495 | ypbindlist->dom_servlistfp = fopen(ypbindlist->dom_servlist, "r"); | |||
496 | ypbindlist->dom_alive = 0; | |||
497 | ypbindlist->dom_lockfd = -1; | |||
498 | ypbindlist->dom_xid = unique_xid(ypbindlist); | |||
499 | snprintf(path, sizeof path, "%s/%s.%d", BINDINGDIR"/var/yp/binding", | |||
500 | ypbindlist->dom_domain, (int)ypbindlist->dom_vers); | |||
501 | (void)unlink(path); | |||
502 | ||||
503 | checkwork(); | |||
504 | ||||
505 | while (1) { | |||
506 | if (pfd == NULL((void *)0) || width != svc_max_pollfd + 2) { | |||
507 | width = svc_max_pollfd + 2; | |||
508 | pfd = reallocarray(pfd, width, sizeof *pfd); | |||
509 | if (pfd == NULL((void *)0)) | |||
510 | err(1, NULL((void *)0)); | |||
511 | } | |||
512 | ||||
513 | pfd[0].fd = rpcsock; | |||
514 | pfd[0].events = POLLIN0x0001; | |||
515 | pfd[1].fd = pingsock; | |||
516 | pfd[1].events = POLLIN0x0001; | |||
517 | memcpy(pfd + 2, svc_pollfd, sizeof(*pfd) * svc_max_pollfd); | |||
518 | ||||
519 | nready = poll(pfd, width, 1000); | |||
520 | switch (nready) { | |||
521 | case 0: | |||
522 | checkwork(); | |||
523 | break; | |||
524 | case -1: | |||
525 | if (errno(*__errno()) != EINTR4) | |||
526 | perror("poll"); | |||
527 | break; | |||
528 | default: | |||
529 | /* No need to check for POLLHUP on UDP sockets. */ | |||
530 | if (pfd[0].revents & POLLIN0x0001) { | |||
531 | handle_replies(); | |||
532 | nready--; | |||
533 | } | |||
534 | if (pfd[1].revents & POLLIN0x0001) { | |||
535 | handle_ping(); | |||
536 | nready--; | |||
537 | } | |||
538 | svc_getreq_poll(pfd + 2, nready); | |||
539 | if (check) | |||
540 | checkwork(); | |||
541 | break; | |||
542 | } | |||
543 | ||||
544 | #ifdef DAEMON1 | |||
545 | if (!evil && ypbindlist->dom_alive) { | |||
546 | evil = 1; | |||
547 | daemon(0, 0); | |||
548 | } | |||
549 | #endif | |||
550 | } | |||
551 | } | |||
552 | ||||
553 | /* | |||
554 | * State transition is done like this: | |||
555 | * | |||
556 | * STATE EVENT ACTION NEWSTATE TIMEOUT | |||
557 | * no binding timeout broadcast no binding 5 sec | |||
558 | * no binding answer -- binding 60 sec | |||
559 | * binding timeout ping server checking 5 sec | |||
560 | * checking timeout ping server + broadcast checking 5 sec | |||
561 | * checking answer -- binding 60 sec | |||
562 | */ | |||
563 | void | |||
564 | checkwork(void) | |||
565 | { | |||
566 | struct _dom_binding *ypdb; | |||
567 | time_t t; | |||
568 | ||||
569 | time(&t); | |||
570 | for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { | |||
571 | if (ypdb->dom_check_t < t) { | |||
572 | if (ypdb->dom_alive == 1) | |||
573 | ping(ypdb); | |||
574 | else | |||
575 | pings(ypdb); | |||
576 | time(&t); | |||
577 | ypdb->dom_check_t = t + 5; | |||
578 | } | |||
579 | } | |||
580 | check = 0; | |||
581 | } | |||
582 | ||||
583 | int | |||
584 | ping(struct _dom_binding *ypdb) | |||
585 | { | |||
586 | domainname dom = ypdb->dom_domain; | |||
587 | struct rpc_msg msg; | |||
588 | char buf[1400]; | |||
589 | enum clnt_stat st; | |||
590 | int outlen; | |||
591 | AUTH *rpcua; | |||
592 | XDR xdr; | |||
593 | ||||
594 | memset(&xdr, 0, sizeof xdr); | |||
595 | memset(&msg, 0, sizeof msg); | |||
596 | ||||
597 | rpcua = authunix_create_default(); | |||
598 | if (rpcua == (AUTH *)NULL((void *)0)) { | |||
599 | /*printf("cannot get unix auth\n");*/ | |||
600 | return RPC_SYSTEMERROR; | |||
601 | } | |||
602 | msg.rm_direction = CALL; | |||
603 | msg.rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
604 | msg.rm_callru.RM_cmb.cb_prog = YPPROG((u_long)100004); | |||
605 | msg.rm_callru.RM_cmb.cb_vers = YPVERS((u_long)2); | |||
606 | msg.rm_callru.RM_cmb.cb_proc = YPPROC_DOMAIN_NONACK((u_long)2); | |||
607 | msg.rm_callru.RM_cmb.cb_cred = rpcua->ah_cred; | |||
608 | msg.rm_callru.RM_cmb.cb_verf = rpcua->ah_verf; | |||
609 | ||||
610 | msg.rm_xid = ypdb->dom_xid; | |||
611 | xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE); | |||
612 | if (!xdr_callmsg(&xdr, &msg)) { | |||
613 | st = RPC_CANTENCODEARGS; | |||
614 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
615 | return st; | |||
616 | } | |||
617 | if (!xdr_domainname(&xdr, &dom)) { | |||
618 | st = RPC_CANTENCODEARGS; | |||
619 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
620 | return st; | |||
621 | } | |||
622 | outlen = (int)xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
623 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
624 | if (outlen < 1) { | |||
625 | st = RPC_CANTENCODEARGS; | |||
626 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
627 | return st; | |||
628 | } | |||
629 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
630 | ||||
631 | ypdb->dom_alive = 2; | |||
632 | if (sendto(pingsock, buf, outlen, 0, | |||
633 | (struct sockaddr *)&ypdb->dom_server_addr, | |||
634 | (socklen_t)sizeof ypdb->dom_server_addr) == -1) | |||
635 | perror("sendto"); | |||
636 | return 0; | |||
637 | ||||
638 | } | |||
639 | ||||
640 | int | |||
641 | pings(struct _dom_binding *ypdb) | |||
642 | { | |||
643 | domainname dom = ypdb->dom_domain; | |||
644 | struct rpc_msg msg; | |||
645 | struct sockaddr_in bindsin; | |||
646 | char buf[1400]; | |||
647 | char path[PATH_MAX1024]; | |||
648 | enum clnt_stat st; | |||
649 | int outlen; | |||
650 | AUTH *rpcua; | |||
651 | XDR xdr; | |||
652 | ||||
653 | rmtca.xdr_args = xdr_domainname; | |||
654 | rmtca.args_ptr = (char *)&dom; | |||
655 | ||||
656 | memset(&xdr, 0, sizeof xdr); | |||
657 | memset(&msg, 0, sizeof msg); | |||
658 | ||||
659 | rpcua = authunix_create_default(); | |||
660 | if (rpcua == (AUTH *)NULL((void *)0)) { | |||
661 | /*printf("cannot get unix auth\n");*/ | |||
662 | return RPC_SYSTEMERROR; | |||
| ||||
663 | } | |||
664 | msg.rm_direction = CALL; | |||
665 | msg.rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
666 | msg.rm_callru.RM_cmb.cb_prog = PMAPPROG((unsigned long)100000); | |||
667 | msg.rm_callru.RM_cmb.cb_vers = PMAPVERS((unsigned long)2); | |||
668 | msg.rm_callru.RM_cmb.cb_proc = PMAPPROC_CALLIT((unsigned long)5); | |||
669 | msg.rm_callru.RM_cmb.cb_cred = rpcua->ah_cred; | |||
670 | msg.rm_callru.RM_cmb.cb_verf = rpcua->ah_verf; | |||
671 | ||||
672 | msg.rm_xid = ypdb->dom_xid; | |||
673 | xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE); | |||
674 | if (!xdr_callmsg(&xdr, &msg)) { | |||
675 | st = RPC_CANTENCODEARGS; | |||
676 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
677 | return st; | |||
678 | } | |||
679 | if (!xdr_rmtcall_args(&xdr, &rmtca)) { | |||
680 | st = RPC_CANTENCODEARGS; | |||
681 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
682 | return st; | |||
683 | } | |||
684 | outlen = (int)xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
685 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
686 | if (outlen < 1) { | |||
687 | st = RPC_CANTENCODEARGS; | |||
688 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
689 | return st; | |||
690 | } | |||
691 | AUTH_DESTROY(rpcua)((*((rpcua)->ah_ops->ah_destroy))(rpcua)); | |||
692 | ||||
693 | if (ypdb->dom_lockfd != -1) { | |||
694 | close(ypdb->dom_lockfd); | |||
695 | ypdb->dom_lockfd = -1; | |||
696 | snprintf(path, sizeof path, "%s/%s.%d", BINDINGDIR"/var/yp/binding", | |||
697 | ypdb->dom_domain, (int)ypdb->dom_vers); | |||
698 | unlink(path); | |||
699 | } | |||
700 | ||||
701 | if (ypdb->dom_alive == 2) { | |||
702 | /* | |||
703 | * This resolves the following situation: | |||
704 | * ypserver on other subnet was once bound, | |||
705 | * but rebooted and is now using a different port | |||
706 | */ | |||
707 | memset(&bindsin, 0, sizeof bindsin); | |||
708 | bindsin.sin_family = AF_INET2; | |||
709 | bindsin.sin_len = sizeof(bindsin); | |||
710 | bindsin.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t )(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8 | ((__uint16_t)(((unsigned short)111)) & 0xff00U) >> 8) : __swap16md(((unsigned short)111))); | |||
711 | bindsin.sin_addr = ypdb->dom_server_addr.sin_addr; | |||
712 | if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin, | |||
713 | (socklen_t)sizeof bindsin) == -1) | |||
714 | perror("sendto"); | |||
715 | } | |||
716 | if (ypdb->dom_servlistfp) | |||
717 | return direct(ypdb, buf, outlen); | |||
718 | return broadcast(ypdb, buf, outlen); | |||
719 | } | |||
720 | ||||
721 | int | |||
722 | broadcast(struct _dom_binding *ypdb, char *buf, int outlen) | |||
723 | { | |||
724 | struct ifaddrs *ifap, *ifa; | |||
725 | struct sockaddr_in bindsin; | |||
726 | struct in_addr in; | |||
727 | ||||
728 | memset(&bindsin, 0, sizeof bindsin); | |||
729 | bindsin.sin_family = AF_INET2; | |||
730 | bindsin.sin_len = sizeof(bindsin); | |||
731 | bindsin.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t )(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8 | ((__uint16_t)(((unsigned short)111)) & 0xff00U) >> 8) : __swap16md(((unsigned short)111))); | |||
732 | ||||
733 | if (getifaddrs(&ifap) != 0) { | |||
734 | perror("getifaddrs"); | |||
735 | return -1; | |||
736 | } | |||
737 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | |||
738 | if (ifa->ifa_addr == NULL((void *)0) || | |||
739 | ifa->ifa_addr->sa_family != AF_INET2) | |||
740 | continue; | |||
741 | if ((ifa->ifa_flags & IFF_UP0x1) == 0) | |||
742 | continue; | |||
743 | ||||
744 | switch (ifa->ifa_flags & (IFF_LOOPBACK0x8 | IFF_BROADCAST0x2)) { | |||
745 | case IFF_BROADCAST0x2: | |||
746 | if (!ifa->ifa_broadaddrifa_dstaddr) | |||
747 | continue; | |||
748 | if (ifa->ifa_broadaddrifa_dstaddr->sa_family != AF_INET2) | |||
749 | continue; | |||
750 | in = ((struct sockaddr_in *)ifa->ifa_broadaddrifa_dstaddr)->sin_addr; | |||
751 | break; | |||
752 | case IFF_LOOPBACK0x8: | |||
753 | in = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; | |||
754 | break; | |||
755 | default: | |||
756 | continue; | |||
757 | } | |||
758 | ||||
759 | bindsin.sin_addr = in; | |||
760 | if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin, | |||
761 | (socklen_t)bindsin.sin_len) == -1) | |||
762 | perror("sendto"); | |||
763 | } | |||
764 | freeifaddrs(ifap); | |||
765 | return 0; | |||
766 | } | |||
767 | ||||
768 | int | |||
769 | direct(struct _dom_binding *ypdb, char *buf, int outlen) | |||
770 | { | |||
771 | char line[1024], *p; | |||
772 | struct hostent *hp; | |||
773 | struct sockaddr_in bindsin; | |||
774 | int i, c; | |||
775 | struct stat fst, st; | |||
776 | ||||
777 | if (fstat(fileno(ypdb->dom_servlistfp)(!__isthreaded ? ((ypdb->dom_servlistfp)->_file) : (fileno )(ypdb->dom_servlistfp)), &fst) != -1 && | |||
778 | stat(ypdb->dom_servlist, &st) != -1 && | |||
779 | (st.st_dev != fst.st_dev || st.st_ino != fst.st_ino)) { | |||
780 | FILE *fp; | |||
781 | ||||
782 | fp = fopen(ypdb->dom_servlist, "r"); | |||
783 | if (fp) { | |||
784 | fclose(ypdb->dom_servlistfp); | |||
785 | ypdb->dom_servlistfp = fp; | |||
786 | } | |||
787 | } | |||
788 | (void) rewind(ypdb->dom_servlistfp); | |||
789 | ||||
790 | memset(&bindsin, 0, sizeof bindsin); | |||
791 | bindsin.sin_family = AF_INET2; | |||
792 | bindsin.sin_len = sizeof(bindsin); | |||
793 | bindsin.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t )(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8 | ((__uint16_t)(((unsigned short)111)) & 0xff00U) >> 8) : __swap16md(((unsigned short)111))); | |||
794 | ||||
795 | while (fgets(line, sizeof(line), ypdb->dom_servlistfp) != NULL((void *)0)) { | |||
796 | /* skip lines that are too big */ | |||
797 | p = strchr(line, '\n'); | |||
798 | if (p == NULL((void *)0)) { | |||
799 | while ((c = getc(ypdb->dom_servlistfp)(!__isthreaded ? (--(ypdb->dom_servlistfp)->_r < 0 ? __srget(ypdb->dom_servlistfp) : (int)(*(ypdb->dom_servlistfp )->_p++)) : (getc)(ypdb->dom_servlistfp))) != '\n' && c != EOF(-1)) | |||
800 | ; | |||
801 | continue; | |||
802 | } | |||
803 | *p = '\0'; | |||
804 | p = line; | |||
805 | while (isspace((unsigned char)*p)) | |||
806 | p++; | |||
807 | if (*p == '#') | |||
808 | continue; | |||
809 | hp = gethostbyname(p); | |||
810 | if (!hp) | |||
811 | continue; | |||
812 | /* step through all addresses in case first is unavailable */ | |||
813 | for (i = 0; hp->h_addr_list[i]; i++) { | |||
814 | memmove(&bindsin.sin_addr, hp->h_addr_list[0], | |||
815 | hp->h_length); | |||
816 | if (sendto(rpcsock, buf, outlen, 0, | |||
817 | (struct sockaddr *)&bindsin, | |||
818 | (socklen_t)sizeof bindsin) == -1) { | |||
819 | perror("sendto"); | |||
820 | continue; | |||
821 | } | |||
822 | } | |||
823 | } | |||
824 | return 0; | |||
825 | } | |||
826 | ||||
827 | enum clnt_stat | |||
828 | handle_replies(void) | |||
829 | { | |||
830 | char buf[1400]; | |||
831 | int inlen; | |||
832 | socklen_t fromlen; | |||
833 | struct _dom_binding *ypdb; | |||
834 | struct sockaddr_in raddr; | |||
835 | struct rpc_msg msg; | |||
836 | XDR xdr; | |||
837 | ||||
838 | recv_again: | |||
839 | memset(&xdr, 0, sizeof(xdr)); | |||
840 | memset(&msg, 0, sizeof(msg)); | |||
841 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
842 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = (caddr_t)&rmtcr; | |||
843 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_rmtcallres; | |||
844 | ||||
845 | try_again: | |||
846 | fromlen = sizeof (struct sockaddr); | |||
847 | inlen = recvfrom(rpcsock, buf, sizeof buf, 0, | |||
848 | (struct sockaddr *)&raddr, &fromlen); | |||
849 | if (inlen == -1) { | |||
850 | if (errno(*__errno()) == EINTR4) | |||
851 | goto try_again; | |||
852 | return RPC_CANTRECV; | |||
853 | } | |||
854 | if (inlen < sizeof(u_int32_t)) | |||
855 | goto recv_again; | |||
856 | ||||
857 | /* | |||
858 | * see if reply transaction id matches sent id. | |||
859 | * If so, decode the results. | |||
860 | */ | |||
861 | xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); | |||
862 | if (xdr_replymsg(&xdr, &msg)) { | |||
863 | if ((msg.rm_replyru.RM_rmb.rp_stat == MSG_ACCEPTED) && | |||
864 | (msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_stat == SUCCESS)) { | |||
865 | raddr.sin_port = htons((u_short)rmtcr_port)(__uint16_t)(__builtin_constant_p((u_short)rmtcr_port) ? (__uint16_t )(((__uint16_t)((u_short)rmtcr_port) & 0xffU) << 8 | ((__uint16_t)((u_short)rmtcr_port) & 0xff00U) >> 8 ) : __swap16md((u_short)rmtcr_port)); | |||
866 | ypdb = xid2ypdb(msg.rm_xid); | |||
867 | if (ypdb) | |||
868 | rpc_received(ypdb->dom_domain, &raddr, 0); | |||
869 | } | |||
870 | } | |||
871 | xdr.x_op = XDR_FREE; | |||
872 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
873 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
874 | ||||
875 | return RPC_SUCCESS; | |||
876 | } | |||
877 | ||||
878 | enum clnt_stat | |||
879 | handle_ping(void) | |||
880 | { | |||
881 | char buf[1400]; | |||
882 | int inlen; | |||
883 | socklen_t fromlen; | |||
884 | struct _dom_binding *ypdb; | |||
885 | struct sockaddr_in raddr; | |||
886 | struct rpc_msg msg; | |||
887 | XDR xdr; | |||
888 | bool_tint32_t res; | |||
889 | ||||
890 | recv_again: | |||
891 | memset(&xdr, 0, sizeof(xdr)); | |||
892 | memset(&msg, 0, sizeof(msg)); | |||
893 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
894 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = (caddr_t)&res; | |||
895 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_bool; | |||
896 | ||||
897 | try_again: | |||
898 | fromlen = sizeof (struct sockaddr); | |||
899 | inlen = recvfrom(pingsock, buf, sizeof buf, 0, | |||
900 | (struct sockaddr *)&raddr, &fromlen); | |||
901 | if (inlen == -1) { | |||
902 | if (errno(*__errno()) == EINTR4) | |||
903 | goto try_again; | |||
904 | return RPC_CANTRECV; | |||
905 | } | |||
906 | if (inlen < sizeof(u_int32_t)) | |||
907 | goto recv_again; | |||
908 | ||||
909 | /* | |||
910 | * see if reply transaction id matches sent id. | |||
911 | * If so, decode the results. | |||
912 | */ | |||
913 | xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); | |||
914 | if (xdr_replymsg(&xdr, &msg)) { | |||
915 | if ((msg.rm_replyru.RM_rmb.rp_stat == MSG_ACCEPTED) && | |||
916 | (msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_stat == SUCCESS)) { | |||
917 | ypdb = xid2ypdb(msg.rm_xid); | |||
918 | if (ypdb) | |||
919 | rpc_received(ypdb->dom_domain, &raddr, 0); | |||
920 | } | |||
921 | } | |||
922 | xdr.x_op = XDR_FREE; | |||
923 | msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
924 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
925 | ||||
926 | return RPC_SUCCESS; | |||
927 | } | |||
928 | ||||
929 | /* | |||
930 | * We prefer loopback connections. | |||
931 | */ | |||
932 | void | |||
933 | rpc_received(char *dom, struct sockaddr_in *raddrp, int force) | |||
934 | { | |||
935 | struct _dom_binding *ypdb; | |||
936 | struct iovec iov[3]; | |||
937 | struct ypbind_resp ybr; | |||
938 | char path[PATH_MAX1024]; | |||
939 | u_short ypserv_tcp, ypserv_udp; | |||
940 | int fd; | |||
941 | ||||
942 | if (strchr(dom, '/')) | |||
943 | return; | |||
944 | ||||
945 | #ifdef DEBUG | |||
946 | printf("returned from %s about %s\n", inet_ntoa(raddrp->sin_addr), dom); | |||
947 | #endif | |||
948 | ||||
949 | if (dom == NULL((void *)0)) | |||
950 | return; | |||
951 | ||||
952 | for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) | |||
953 | if (!strcmp(ypdb->dom_domain, dom)) | |||
954 | break; | |||
955 | ||||
956 | if (ypdb == NULL((void *)0)) { | |||
957 | if (force == 0) | |||
958 | return; | |||
959 | ypdb = malloc(sizeof *ypdb); | |||
960 | if (ypdb == NULL((void *)0)) | |||
961 | return; | |||
962 | memset(ypdb, 0, sizeof *ypdb); | |||
963 | strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain-1); | |||
964 | ypdb->dom_domain[sizeof (ypdb->dom_domain)-1] = '\0'; | |||
965 | ypdb->dom_lockfd = -1; | |||
966 | ypdb->dom_xid = unique_xid(ypdb); | |||
967 | ypdb->dom_pnext = ypbindlist; | |||
968 | ypbindlist = ypdb; | |||
969 | } | |||
970 | ||||
971 | /* we do not support sunos 3.0 insecure servers */ | |||
972 | if (insecure == 0 && ntohs(raddrp->sin_port)(__uint16_t)(__builtin_constant_p(raddrp->sin_port) ? (__uint16_t )(((__uint16_t)(raddrp->sin_port) & 0xffU) << 8 | ((__uint16_t)(raddrp->sin_port) & 0xff00U) >> 8 ) : __swap16md(raddrp->sin_port)) >= IPPORT_RESERVED1024) | |||
973 | return; | |||
974 | ||||
975 | /* soft update, alive */ | |||
976 | if (ypdb->dom_alive == 1 && force == 0) { | |||
977 | if (!memcmp(&ypdb->dom_server_addr, raddrp, | |||
978 | sizeof ypdb->dom_server_addr)) { | |||
979 | ypdb->dom_alive = 1; | |||
980 | /* recheck binding in 60 sec */ | |||
981 | ypdb->dom_check_t = time(NULL((void *)0)) + 60; | |||
982 | } | |||
983 | if (raddrp->sin_addr.s_addr == htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001))))) { | |||
984 | /* | |||
985 | * we are alive and already have a binding, but | |||
986 | * after a broadcast we prefer the localhost | |||
987 | */ | |||
988 | memcpy(&ypdb->dom_server_addr, raddrp, | |||
989 | sizeof ypdb->dom_server_addr); | |||
990 | } | |||
991 | return; | |||
992 | } | |||
993 | ||||
994 | /* synchronously ask for the matching ypserv TCP port number */ | |||
995 | ypserv_udp = raddrp->sin_port; | |||
996 | ypserv_tcp = pmap_getport(raddrp, YPPROG((u_long)100004), | |||
997 | YPVERS((u_long)2), IPPROTO_TCP6); | |||
998 | if (ypserv_tcp == 0) { | |||
999 | clnt_pcreateerror("pmap_getport"); | |||
1000 | return; | |||
1001 | } | |||
1002 | if (ypserv_tcp >= IPPORT_RESERVED1024 || ypserv_tcp == 20) | |||
1003 | return; | |||
1004 | ypserv_tcp = htons(ypserv_tcp)(__uint16_t)(__builtin_constant_p(ypserv_tcp) ? (__uint16_t)( ((__uint16_t)(ypserv_tcp) & 0xffU) << 8 | ((__uint16_t )(ypserv_tcp) & 0xff00U) >> 8) : __swap16md(ypserv_tcp )); | |||
1005 | ||||
1006 | memcpy(&ypdb->dom_server_addr, raddrp, sizeof ypdb->dom_server_addr); | |||
1007 | /* recheck binding in 60 seconds */ | |||
1008 | ypdb->dom_check_t = time(NULL((void *)0)) + 60; | |||
1009 | ypdb->dom_vers = YPVERS((u_long)2); | |||
1010 | ypdb->dom_alive = 1; | |||
1011 | ||||
1012 | if (ypdb->dom_lockfd != -1) | |||
1013 | close(ypdb->dom_lockfd); | |||
1014 | ||||
1015 | snprintf(path, sizeof path, "%s/%s.%d", BINDINGDIR"/var/yp/binding", | |||
1016 | ypdb->dom_domain, (int)ypdb->dom_vers); | |||
1017 | if ((fd = open(path, O_CREAT0x0200|O_SHLOCK0x0010|O_RDWR0x0002|O_TRUNC0x0400, 0644)) == -1) { | |||
1018 | (void)mkdir(BINDINGDIR"/var/yp/binding", 0755); | |||
1019 | if ((fd = open(path, O_CREAT0x0200|O_SHLOCK0x0010|O_RDWR0x0002|O_TRUNC0x0400, | |||
1020 | 0644)) == -1) | |||
1021 | return; | |||
1022 | } | |||
1023 | ||||
1024 | /* | |||
1025 | * ok, if BINDINGDIR exists, and we can create the binding file, | |||
1026 | * then write to it.. | |||
1027 | */ | |||
1028 | ypdb->dom_lockfd = fd; | |||
1029 | ||||
1030 | iov[0].iov_base = (caddr_t)&(udptransp->xp_port); | |||
1031 | iov[0].iov_len = sizeof udptransp->xp_port; | |||
1032 | iov[1].iov_base = (caddr_t)&ybr; | |||
1033 | iov[1].iov_len = sizeof ybr; | |||
1034 | iov[2].iov_base = (caddr_t)&ypserv_tcp; | |||
1035 | iov[2].iov_len = sizeof ypserv_tcp; | |||
1036 | ||||
1037 | memset(&ybr, 0, sizeof ybr); | |||
1038 | ybr.ypbind_status = YPBIND_SUCC_VAL; | |||
1039 | memmove(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, | |||
1040 | &raddrp->sin_addr, | |||
1041 | sizeof(ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr)); | |||
1042 | memmove(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, | |||
1043 | &ypserv_udp, | |||
1044 | sizeof(ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port)); | |||
1045 | ||||
1046 | if (writev(ypdb->dom_lockfd, iov, sizeof(iov)/sizeof(iov[0])) != | |||
1047 | iov[0].iov_len + iov[1].iov_len + iov[2].iov_len) { | |||
1048 | perror("write"); | |||
1049 | close(ypdb->dom_lockfd); | |||
1050 | unlink(path); | |||
1051 | ypdb->dom_lockfd = -1; | |||
1052 | return; | |||
1053 | } | |||
1054 | } | |||
1055 | ||||
1056 | struct _dom_binding * | |||
1057 | xid2ypdb(u_int32_t xid) | |||
1058 | { | |||
1059 | struct _dom_binding *ypdb; | |||
1060 | ||||
1061 | for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) | |||
1062 | if (ypdb->dom_xid == xid) | |||
1063 | break; | |||
1064 | return (ypdb); | |||
1065 | } | |||
1066 | ||||
1067 | u_int32_t | |||
1068 | unique_xid(struct _dom_binding *ypdb) | |||
1069 | { | |||
1070 | u_int32_t xid; | |||
1071 | ||||
1072 | xid = arc4random(); | |||
1073 | while (xid2ypdb(xid) != NULL((void *)0)) | |||
1074 | xid++; | |||
1075 | ||||
1076 | return (xid); | |||
1077 | } |