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