Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/dummypmap.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 4107 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 4107 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | /* |
2 | * Enough portmapper functionality that mount doesn't hang trying | ||
3 | * to start lockd. Enables nfsroot with locking functionality. | ||
4 | * | ||
5 | * Note: the kernel will only speak to the local portmapper | ||
6 | * using RPC over UDP. | ||
7 | */ | ||
8 | |||
9 | #include <sys/types.h> | ||
10 | #include <netinet/in.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <errno.h> | ||
14 | #include <unistd.h> | ||
15 | #include <string.h> | ||
16 | #include <sys/socket.h> | ||
17 | |||
18 | #include "sunrpc.h" | ||
19 | |||
20 | extern const char *progname; | ||
21 | |||
22 | struct portmap_call { | ||
23 | struct rpc_call rpc; | ||
24 | uint32_t program; | ||
25 | uint32_t version; | ||
26 | uint32_t proto; | ||
27 | uint32_t port; | ||
28 | }; | ||
29 | |||
30 | struct portmap_reply { | ||
31 | struct rpc_reply rpc; | ||
32 | uint32_t port; | ||
33 | }; | ||
34 | |||
35 | static int bind_portmap(void) | ||
36 | { | ||
37 | int sock = socket(PF_INET, SOCK_DGRAM, 0); | ||
38 | struct sockaddr_in sin; | ||
39 | |||
40 | if (sock < 0) | ||
41 | return -1; | ||
42 | |||
43 | memset(&sin, 0, sizeof sin); | ||
44 | sin.sin_family = AF_INET; | ||
45 | sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ | ||
46 | sin.sin_port = htons(RPC_PMAP_PORT); | ||
47 | if (bind(sock, (struct sockaddr *)&sin, sizeof sin) < 0) { | ||
48 | int err = errno; | ||
49 | close(sock); | ||
50 | errno = err; | ||
51 | return -1; | ||
52 | } | ||
53 | |||
54 | return sock; | ||
55 | } | ||
56 | |||
57 | static const char *protoname(uint32_t proto) | ||
58 | { | ||
59 | switch (ntohl(proto)) { | ||
60 | case IPPROTO_TCP: | ||
61 | return "tcp"; | ||
62 | case IPPROTO_UDP: | ||
63 | return "udp"; | ||
64 | default: | ||
65 | return NULL; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static int dummy_portmap(int sock, FILE *portmap_file) | ||
70 | { | ||
71 | struct sockaddr_in sin; | ||
72 | int pktlen, addrlen; | ||
73 | union { | ||
74 | struct portmap_call c; | ||
75 | unsigned char b[65536]; /* Max UDP packet size */ | ||
76 | } pkt; | ||
77 | struct portmap_reply rply; | ||
78 | |||
79 | for (;;) { | ||
80 | addrlen = sizeof sin; | ||
81 | pktlen = recvfrom(sock, &pkt.c.rpc.hdr.udp, sizeof pkt, 0, | ||
82 | (struct sockaddr *)&sin, &addrlen); | ||
83 | |||
84 | if (pktlen < 0) { | ||
85 | if (errno == EINTR) | ||
86 | continue; | ||
87 | |||
88 | return -1; | ||
89 | } | ||
90 | |||
91 | /* +4 to skip the TCP fragment header */ | ||
92 | if (pktlen + 4 < sizeof(struct portmap_call)) | ||
93 | continue; /* Bad packet */ | ||
94 | |||
95 | if (pkt.c.rpc.hdr.udp.msg_type != htonl(RPC_CALL)) | ||
96 | continue; /* Bad packet */ | ||
97 | |||
98 | memset(&rply, 0, sizeof rply); | ||
99 | |||
100 | rply.rpc.hdr.udp.xid = pkt.c.rpc.hdr.udp.xid; | ||
101 | rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY); | ||
102 | |||
103 | if (pkt.c.rpc.rpc_vers != htonl(2)) { | ||
104 | rply.rpc.reply_state = htonl(REPLY_DENIED); | ||
105 | /* state <- RPC_MISMATCH == 0 */ | ||
106 | } else if (pkt.c.rpc.program != htonl(PORTMAP_PROGRAM)) { | ||
107 | rply.rpc.reply_state = htonl(PROG_UNAVAIL); | ||
108 | } else if (pkt.c.rpc.prog_vers != htonl(2)) { | ||
109 | rply.rpc.reply_state = htonl(PROG_MISMATCH); | ||
110 | } else if (pkt.c.rpc.cred_len != 0 || pkt.c.rpc.vrf_len != 0) { | ||
111 | /* Can't deal with credentials data; the kernel | ||
112 | won't send them */ | ||
113 | rply.rpc.reply_state = htonl(SYSTEM_ERR); | ||
114 | } else { | ||
115 | switch (ntohl(pkt.c.rpc.proc)) { | ||
116 | case PMAP_PROC_NULL: | ||
117 | break; | ||
118 | case PMAP_PROC_SET: | ||
119 | if (pkt.c.proto == htonl(IPPROTO_TCP) || | ||
120 | pkt.c.proto == htonl(IPPROTO_UDP)) { | ||
121 | if (portmap_file) | ||
122 | fprintf(portmap_file, | ||
123 | "%u %u %s %u\n", | ||
124 | ntohl(pkt.c.program), | ||
125 | ntohl(pkt.c.version), | ||
126 | protoname(pkt.c.proto), | ||
127 | ntohl(pkt.c.port)); | ||
128 | rply.port = htonl(1); /* TRUE = success */ | ||
129 | } | ||
130 | break; | ||
131 | case PMAP_PROC_UNSET: | ||
132 | rply.port = htonl(1); /* TRUE = success */ | ||
133 | break; | ||
134 | case PMAP_PROC_GETPORT: | ||
135 | break; | ||
136 | case PMAP_PROC_DUMP: | ||
137 | break; | ||
138 | default: | ||
139 | rply.rpc.reply_state = htonl(PROC_UNAVAIL); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | sendto(sock, &rply.rpc.hdr.udp, sizeof rply - 4, 0, | ||
145 | (struct sockaddr *)&sin, addrlen); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | pid_t start_dummy_portmap(const char *file) | ||
150 | { | ||
151 | FILE *portmap_filep; | ||
152 | int sock; | ||
153 | pid_t spoof_portmap; | ||
154 | |||
155 | portmap_filep = fopen(file, "w"); | ||
156 | if (!portmap_filep) { | ||
157 | fprintf(stderr, "%s: cannot write portmap file: %s\n", | ||
158 | progname, file); | ||
159 | return -1; | ||
160 | } | ||
161 | |||
162 | sock = bind_portmap(); | ||
163 | if (sock == -1) { | ||
164 | if (errno == EINVAL || errno == EADDRINUSE) | ||
165 | return 0; /* Assume not needed */ | ||
166 | else { | ||
167 | fprintf(stderr, "%s: portmap spoofing failed\n", | ||
168 | progname); | ||
169 | return -1; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | spoof_portmap = fork(); | ||
174 | if (spoof_portmap == -1) { | ||
175 | fprintf(stderr, "%s: cannot fork\n", progname); | ||
176 | return -1; | ||
177 | } else if (spoof_portmap == 0) { | ||
178 | /* Child process */ | ||
179 | dummy_portmap(sock, portmap_filep); | ||
180 | _exit(255); /* Error */ | ||
181 | } else { | ||
182 | /* Parent process */ | ||
183 | close(sock); | ||
184 | return spoof_portmap; | ||
185 | } | ||
186 | } |