File: | src/usr.sbin/amd/amd/nfs_start.c |
Warning: | line 250, column 4 Potential leak of memory pointed to by 'fdsp' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 1990 Jan-Simon Pendry | |||
3 | * Copyright (c) 1990 Imperial College of Science, Technology & Medicine | |||
4 | * Copyright (c) 1990, 1993 | |||
5 | * The Regents of the University of California. All rights reserved. | |||
6 | * | |||
7 | * This code is derived from software contributed to Berkeley by | |||
8 | * Jan-Simon Pendry at Imperial College, London. | |||
9 | * | |||
10 | * Redistribution and use in source and binary forms, with or without | |||
11 | * modification, are permitted provided that the following conditions | |||
12 | * are met: | |||
13 | * 1. Redistributions of source code must retain the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer. | |||
15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
16 | * notice, this list of conditions and the following disclaimer in the | |||
17 | * documentation and/or other materials provided with the distribution. | |||
18 | * 3. Neither the name of the University nor the names of its contributors | |||
19 | * may be used to endorse or promote products derived from this software | |||
20 | * without specific prior written permission. | |||
21 | * | |||
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
32 | * SUCH DAMAGE. | |||
33 | * | |||
34 | * from: @(#)nfs_start.c 8.1 (Berkeley) 6/6/93 | |||
35 | * $Id: nfs_start.c,v 1.20 2015/08/20 22:46:32 deraadt Exp $ | |||
36 | */ | |||
37 | ||||
38 | #include "am.h" | |||
39 | #include "amq.h" | |||
40 | #include <signal.h> | |||
41 | #include <unistd.h> | |||
42 | #include <setjmp.h> | |||
43 | ||||
44 | extern jmp_buf select_intr; | |||
45 | extern int select_intr_valid; | |||
46 | ||||
47 | #ifdef HAS_TFS | |||
48 | /* | |||
49 | * Use replacement for RPC/UDP transport | |||
50 | * so that we do NFS gatewaying. | |||
51 | */ | |||
52 | #define svcudp_create svcudp2_create | |||
53 | extern SVCXPRT *svcudp2_create(int); | |||
54 | #endif /* HAS_TFS */ | |||
55 | ||||
56 | unsigned short nfs_port; | |||
57 | SVCXPRT *nfsxprt, *lnfsxprt; | |||
58 | SVCXPRT *amqp, *lamqp; | |||
59 | ||||
60 | extern int fwd_sock; | |||
61 | int max_fds = -1; | |||
62 | ||||
63 | #ifdef DEBUG | |||
64 | /* | |||
65 | * Check that we are not burning resources | |||
66 | */ | |||
67 | static void | |||
68 | checkup(void) | |||
69 | { | |||
70 | static int max_fd = 0; | |||
71 | static char *max_mem = 0; | |||
72 | ||||
73 | int next_fd = dup(0); | |||
74 | extern caddr_t sbrk(int); | |||
75 | caddr_t next_mem = sbrk(0); | |||
76 | close(next_fd); | |||
77 | ||||
78 | /*if (max_fd < 0) { | |||
79 | max_fd = next_fd; | |||
80 | } else*/ if (max_fd < next_fd) { | |||
81 | dlog("%d new fds allocated; total is %d", | |||
82 | next_fd - max_fd, next_fd); | |||
83 | max_fd = next_fd; | |||
84 | } | |||
85 | ||||
86 | /*if (max_mem == 0) { | |||
87 | max_mem = next_mem; | |||
88 | } else*/ if (max_mem < next_mem) { | |||
89 | dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)", | |||
90 | (unsigned long)(next_mem - max_mem), | |||
91 | (unsigned long)next_mem, | |||
92 | ((unsigned long)next_mem+getpagesize()-1)/getpagesize()); | |||
93 | max_mem = next_mem; | |||
94 | } | |||
95 | } | |||
96 | #endif /* DEBUG */ | |||
97 | ||||
98 | static int | |||
99 | do_select(sigset_t *mask, sigset_t *omask, int fds, fd_set *fdp, | |||
100 | struct timeval *tvp) | |||
101 | { | |||
102 | int sig; | |||
103 | int nsel; | |||
104 | ||||
105 | if ((sig = setjmp(select_intr))) { | |||
106 | select_intr_valid = 0; | |||
107 | /* Got a signal */ | |||
108 | switch (sig) { | |||
109 | case SIGINT2: | |||
110 | case SIGTERM15: | |||
111 | amd_state = Finishing; | |||
112 | reschedule_timeout_mp(); | |||
113 | break; | |||
114 | } | |||
115 | nsel = -1; | |||
116 | errno(*__errno()) = EINTR4; | |||
117 | } else { | |||
118 | select_intr_valid = 1; | |||
119 | /* | |||
120 | * Invalidate the current clock value | |||
121 | */ | |||
122 | clock_valid = 0; | |||
123 | /* | |||
124 | * Allow interrupts. If a signal | |||
125 | * occurs, then it will cause a longjmp | |||
126 | * up above. | |||
127 | */ | |||
128 | sigprocmask(SIG_SETMASK3, omask, NULL((void *)0)); | |||
129 | /* | |||
130 | * Wait for input | |||
131 | */ | |||
132 | nsel = select(fds, fdp, NULL((void *)0), NULL((void *)0), | |||
133 | tvp->tv_sec ? tvp : (struct timeval *) 0); | |||
134 | ||||
135 | } | |||
136 | ||||
137 | sigprocmask(SIG_BLOCK1, mask, NULL((void *)0)); | |||
138 | ||||
139 | /* | |||
140 | * Perhaps reload the cache? | |||
141 | */ | |||
142 | if (do_mapc_reload < clocktime()(clock_valid ? clock_valid : time(&clock_valid))) { | |||
143 | mapc_reload(); | |||
144 | do_mapc_reload = clocktime()(clock_valid ? clock_valid : time(&clock_valid)) + ONE_HOUR(60 * 60); | |||
145 | } | |||
146 | return nsel; | |||
147 | } | |||
148 | ||||
149 | /* | |||
150 | * Determine whether anything is left in | |||
151 | * the RPC input queue. | |||
152 | */ | |||
153 | static int | |||
154 | rpc_pending_now(void) | |||
155 | { | |||
156 | struct timeval tvv; | |||
157 | int nsel; | |||
158 | fd_set *fdsp; | |||
159 | int fdsn; | |||
160 | ||||
161 | fdsn = howmany(max_fds+1, NFDBITS)(((max_fds+1) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof(__fd_mask) * 8)))) * sizeof(fd_mask__fd_mask); | |||
162 | if ((fdsp = malloc(fdsn)) == NULL((void *)0)) | |||
163 | return(0); | |||
164 | memset(fdsp, 0, fdsn); | |||
165 | FD_SET(fwd_sock, fdsp)__fd_set((fwd_sock), (fdsp)); | |||
166 | ||||
167 | tvv.tv_sec = tvv.tv_usec = 0; | |||
168 | nsel = select(max_fds+1, fdsp, NULL((void *)0), NULL((void *)0), &tvv); | |||
169 | if (nsel < 1) { | |||
170 | free(fdsp); | |||
171 | return(0); | |||
172 | } | |||
173 | if (FD_ISSET(fwd_sock, fdsp)__fd_isset((fwd_sock), (fdsp))) { | |||
174 | free(fdsp); | |||
175 | return(1); | |||
176 | } | |||
177 | free(fdsp); | |||
178 | return(0); | |||
179 | } | |||
180 | ||||
181 | static serv_state | |||
182 | run_rpc(void) | |||
183 | { | |||
184 | sigset_t mask, omask; | |||
185 | ||||
186 | sigemptyset(&mask); | |||
187 | sigaddset(&mask, SIGINT2); | |||
188 | sigaddset(&mask, SIGTERM15); | |||
189 | sigaddset(&mask, SIGCHLD20); | |||
190 | sigaddset(&mask, SIGHUP1); | |||
191 | sigprocmask(SIG_BLOCK1, &mask, &omask); | |||
192 | ||||
193 | next_softclock = clocktime()(clock_valid ? clock_valid : time(&clock_valid)); | |||
194 | ||||
195 | amd_state = Run; | |||
196 | ||||
197 | /* | |||
198 | * Keep on trucking while we are in Run mode. This state | |||
199 | * is switched to Quit after all the file systems have | |||
200 | * been unmounted. | |||
201 | */ | |||
202 | while ((int)amd_state <= (int)Finishing) { | |||
203 | struct timeval tvv; | |||
204 | int nsel; | |||
205 | time_t now; | |||
206 | #ifdef __OpenBSD__1 | |||
207 | extern int __svc_fdsetsize; | |||
208 | extern fd_set *__svc_fdset; | |||
209 | fd_set *fdsp; | |||
210 | int fdsn = __svc_fdsetsize; | |||
211 | int bytes; | |||
212 | ||||
213 | if (fwd_sock > fdsn) | |||
214 | fdsn = fwd_sock; | |||
215 | bytes = howmany(fdsn, NFDBITS)(((fdsn) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / ((( unsigned)(sizeof(__fd_mask) * 8)))) * sizeof(fd_mask__fd_mask); | |||
216 | ||||
217 | fdsp = malloc(bytes); | |||
218 | memset(fdsp, 0, bytes); | |||
219 | memcpy(fdsp, __svc_fdset, bytes); | |||
220 | FD_SET(fwd_sock, fdsp)__fd_set((fwd_sock), (fdsp)); | |||
221 | #else | |||
222 | fd_set *fdsp; | |||
223 | int fdsn = FDSETSIZE; | |||
224 | bytes = howmany(fdsn, NFDBITS)(((fdsn) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / ((( unsigned)(sizeof(__fd_mask) * 8)))) * sizeof(fd_mask__fd_mask); | |||
225 | fdsp = malloc(bytes); | |||
226 | memcpy(fdsp, &svc_fdset, bytes); | |||
227 | FD_SET(fwd_sock, fdsp)__fd_set((fwd_sock), (fdsp)); | |||
228 | #endif | |||
229 | ||||
230 | #ifdef DEBUG | |||
231 | checkup(); | |||
232 | #endif /* DEBUG */ | |||
233 | ||||
234 | /* | |||
235 | * If the full timeout code is not called, | |||
236 | * then recompute the time delta manually. | |||
237 | */ | |||
238 | now = clocktime()(clock_valid ? clock_valid : time(&clock_valid)); | |||
239 | ||||
240 | if (next_softclock
| |||
241 | if (amd_state
| |||
242 | umount_exported(); | |||
243 | tvv.tv_sec = softclock(); | |||
244 | } else { | |||
245 | tvv.tv_sec = next_softclock - now; | |||
246 | } | |||
247 | tvv.tv_usec = 0; | |||
248 | ||||
249 | if (amd_state == Finishing && last_used_map < 0) { | |||
250 | flush_mntfs(); | |||
| ||||
251 | amd_state = Quit; | |||
252 | break; | |||
253 | } | |||
254 | ||||
255 | #ifdef DEBUG | |||
256 | if (tvv.tv_sec) | |||
257 | dlog("Select waits for %llds", (long long)tvv.tv_sec); | |||
258 | else | |||
259 | dlog("Select waits for Godot"); | |||
260 | #endif /* DEBUG */ | |||
261 | ||||
262 | nsel = do_select(&mask, &omask, fdsn + 1, fdsp, &tvv); | |||
263 | ||||
264 | ||||
265 | switch (nsel) { | |||
266 | case -1: | |||
267 | if (errno(*__errno()) == EINTR4) { | |||
268 | #ifdef DEBUG | |||
269 | dlog("select interrupted"); | |||
270 | #endif /* DEBUG */ | |||
271 | continue; | |||
272 | } | |||
273 | perror("select"); | |||
274 | break; | |||
275 | ||||
276 | case 0: | |||
277 | #ifdef DEBUG | |||
278 | /*dlog("select returned 0");*/ | |||
279 | #endif /* DEBUG */ | |||
280 | break; | |||
281 | ||||
282 | default: | |||
283 | /* Read all pending NFS responses at once to avoid | |||
284 | having responses queue up as a consequence of | |||
285 | retransmissions. */ | |||
286 | if (FD_ISSET(fwd_sock, fdsp)__fd_isset((fwd_sock), (fdsp))) { | |||
287 | FD_CLR(fwd_sock, fdsp)__fd_clr((fwd_sock), (fdsp)); | |||
288 | --nsel; | |||
289 | do { | |||
290 | fwd_reply(); | |||
291 | } while (rpc_pending_now() > 0); | |||
292 | } | |||
293 | ||||
294 | if (nsel) { | |||
295 | /* | |||
296 | * Anything left must be a normal | |||
297 | * RPC request. | |||
298 | */ | |||
299 | #ifdef __OpenBSD__1 | |||
300 | svc_getreqset2(fdsp, fdsn); | |||
301 | #else | |||
302 | svc_getreqset(fdsp); | |||
303 | #endif | |||
304 | } | |||
305 | break; | |||
306 | } | |||
307 | free(fdsp); | |||
308 | } | |||
309 | ||||
310 | sigprocmask(SIG_SETMASK3, &omask, NULL((void *)0)); | |||
311 | ||||
312 | if (amd_state == Quit) | |||
313 | amd_state = Done; | |||
314 | ||||
315 | return amd_state; | |||
316 | } | |||
317 | ||||
318 | static int | |||
319 | bindnfs_port(int so) | |||
320 | { | |||
321 | unsigned short port; | |||
322 | int error = bind_resv_port(so, &port); | |||
323 | if (error == 0) | |||
324 | nfs_port = port; | |||
325 | return error; | |||
326 | } | |||
327 | ||||
328 | void | |||
329 | unregister_amq(void) | |||
330 | { | |||
331 | #ifdef DEBUG | |||
332 | Debug(D_AMQ) | |||
333 | #endif /* DEBUG */ | |||
334 | (void) pmap_unset(AMQ_PROGRAM((u_long)300019), AMQ_VERSION((u_long)57)); | |||
335 | } | |||
336 | ||||
337 | int | |||
338 | mount_automounter(pid_t ppid) | |||
339 | { | |||
340 | struct sockaddr_in sin; | |||
341 | int so, so2, nmount; | |||
342 | int sinlen; | |||
343 | int on = 1; | |||
344 | ||||
345 | so = socket(AF_INET2, SOCK_DGRAM2, 0); | |||
346 | ||||
347 | if (so < 0 || bindnfs_port(so) < 0) { | |||
| ||||
348 | perror("Can't create privileged nfs port"); | |||
349 | return 1; | |||
350 | } | |||
351 | ||||
352 | if ((nfsxprt = svcudp_create(so)) == NULL((void *)0) || | |||
353 | (amqp = svcudp_create(so)) == NULL((void *)0)) { | |||
354 | plog(XLOG_FATAL0x0001, "cannot create rpc/udp service"); | |||
355 | return 2; | |||
356 | } | |||
357 | ||||
358 | sinlen = sizeof sin; | |||
359 | if (getsockname(so, (struct sockaddr *)&sin, &sinlen) == -1) { | |||
360 | perror("Can't get information on socket"); | |||
361 | return 1; | |||
362 | } | |||
363 | ||||
364 | so2 = socket(AF_INET2, SOCK_DGRAM2, 0); | |||
365 | if (so2 < 0) { | |||
366 | perror("Can't create 2nd socket"); | |||
367 | return 1; | |||
368 | } | |||
369 | ||||
370 | setsockopt(so2, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof on); | |||
371 | ||||
372 | 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)))); | |||
373 | if (bind(so2, (struct sockaddr *)&sin, sizeof sin) == -1) { | |||
374 | perror("Can't bind 2nd socket"); | |||
375 | return 1; | |||
376 | } | |||
377 | ||||
378 | if ((lnfsxprt = svcudp_create(so2)) == NULL((void *)0) || | |||
379 | (lamqp = svcudp_create(so2)) == NULL((void *)0)) { | |||
380 | plog(XLOG_FATAL0x0001, "cannot create rpc/udp service"); | |||
381 | return 2; | |||
382 | } | |||
383 | ||||
384 | if (!svc_register(nfsxprt, NFS_PROGRAM((u_long)100003), NFS_VERSION((u_long)2), nfs_program_2, 0)) { | |||
385 | plog(XLOG_FATAL0x0001, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); | |||
386 | return 3; | |||
387 | } | |||
388 | ||||
389 | /* | |||
390 | * Start RPC forwarding | |||
391 | */ | |||
392 | if (fwd_init() != 0) | |||
393 | return 3; | |||
394 | ||||
395 | /* | |||
396 | * One or other of so, fwd_sock | |||
397 | * must be the highest fd on | |||
398 | * which to select. | |||
399 | */ | |||
400 | if (so > max_fds) | |||
401 | max_fds = so; | |||
402 | if (so2 > max_fds) | |||
403 | max_fds = so2; | |||
404 | if (fwd_sock > max_fds) | |||
405 | max_fds = fwd_sock; | |||
406 | ||||
407 | /* | |||
408 | * Construct the root automount node | |||
409 | */ | |||
410 | make_root_node(); | |||
411 | ||||
412 | /* | |||
413 | * Pick up the pieces from a previous run | |||
414 | * This is likely to (indirectly) need the rpc_fwd package | |||
415 | * so it *must* come after the call to fwd_init(). | |||
416 | */ | |||
417 | if (restart_existing_mounts) | |||
418 | restart(); | |||
419 | ||||
420 | /* | |||
421 | * Mount the top-level auto-mountpoints | |||
422 | */ | |||
423 | nmount = mount_exported(); | |||
424 | ||||
425 | /* | |||
426 | * Now safe to tell parent that we are up and running | |||
427 | */ | |||
428 | if (ppid) | |||
429 | kill(ppid, SIGQUIT3); | |||
430 | ||||
431 | if (nmount == 0) { | |||
432 | plog(XLOG_FATAL0x0001, "No work to do - quitting"); | |||
433 | amd_state = Done; | |||
434 | return 0; | |||
435 | } | |||
436 | ||||
437 | #ifdef DEBUG | |||
438 | Debug(D_AMQ) { | |||
439 | #endif /* DEBUG */ | |||
440 | /* | |||
441 | * Register with amq | |||
442 | */ | |||
443 | unregister_amq(); | |||
444 | ||||
445 | if (!svc_register(amqp, AMQ_PROGRAM((u_long)300019), AMQ_VERSION((u_long)57), amq_program_57, IPPROTO_UDP17)) { | |||
446 | plog(XLOG_FATAL0x0001, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)"); | |||
447 | return 3; | |||
448 | } | |||
449 | #ifdef DEBUG | |||
450 | } | |||
451 | #endif /* DEBUG */ | |||
452 | ||||
453 | /* | |||
454 | * Start timeout_mp rolling | |||
455 | */ | |||
456 | reschedule_timeout_mp(); | |||
457 | ||||
458 | /* | |||
459 | * Start the server | |||
460 | */ | |||
461 | if (run_rpc() != Done) { | |||
462 | plog(XLOG_FATAL0x0001, "run_rpc failed"); | |||
463 | amd_state = Done; | |||
464 | } | |||
465 | ||||
466 | return 0; | |||
467 | } |