Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/dummypmap.c

Parent Directory Parent Directory | Revision Log 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)
-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 }