Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 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     }