Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/dummypmap.c
Parent Directory | Revision Log
Revision 532 -
(show 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 | /* |
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 | } |