1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
* dummypmap.c
*
* Enough portmapper functionality that mount doesn't hang trying
* to start lockd. Enables nfsroot with locking functionality.
*
* Note: the kernel will only speak to the local portmapper
* using RPC over UDP.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include "sunrpc.h"
struct portmap_call
{
struct rpc_call rpc;
__u32 program;
__u32 version;
__u32 proto;
__u32 port;
};
struct portmap_reply
{
struct rpc_reply rpc;
__u32 port;
};
int bind_portmap(void)
{
int sock = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin;
if ( sock < 0 )
return -1;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
sin.sin_port = htons(RPC_PMAP_PORT);
if ( bind(sock, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
int err = errno;
close(sock);
errno = err;
return -1;
}
return sock;
}
int dummy_portmap(int sock, FILE *portmap_file)
{
struct sockaddr_in sin;
int pktlen, addrlen;
union {
struct portmap_call c;
unsigned char b[65536]; /* Max UDP packet size */
} pkt;
struct portmap_reply rply;
for(;;) {
addrlen = sizeof sin;
pktlen = recvfrom(sock, &pkt.c.rpc.hdr.udp, sizeof pkt, 0,
(struct sockaddr *)&sin, &addrlen);
if ( pktlen < 0 ) {
if ( errno == EINTR )
continue;
return -1;
}
/* +4 to skip the TCP fragment header */
if ( pktlen+4 < sizeof(struct portmap_call) )
continue; /* Bad packet */
if ( pkt.c.rpc.hdr.udp.msg_type != htonl(RPC_CALL) )
continue; /* Bad packet */
memset(&rply, 0, sizeof rply);
rply.rpc.hdr.udp.xid = pkt.c.rpc.hdr.udp.xid;
rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY);
if ( pkt.c.rpc.rpc_vers != htonl(2) ) {
rply.rpc.reply_state = htonl(REPLY_DENIED);
/* state <- RPC_MISMATCH == 0 */
} else if ( pkt.c.rpc.program != htonl(PORTMAP_PROGRAM) ) {
rply.rpc.reply_state = htonl(PROG_UNAVAIL);
} else if ( pkt.c.rpc.prog_vers != htonl(2) ) {
rply.rpc.reply_state = htonl(PROG_MISMATCH);
} else if ( pkt.c.rpc.cred_len != 0 ||
pkt.c.rpc.vrf_len != 0 ) {
/* Can't deal with credentials data; the kernel won't send them */
rply.rpc.reply_state = htonl(SYSTEM_ERR);
} else {
switch ( ntohl(pkt.c.rpc.proc) ) {
case PMAP_PROC_NULL:
break;
case PMAP_PROC_SET:
if ( pkt.c.proto == htonl(IPPROTO_TCP) ||
pkt.c.proto == htonl(IPPROTO_UDP) ) {
if ( portmap_file )
fprintf(portmap_file, "%u %u %s %u\n",
ntohl(pkt.c.program), ntohl(pkt.c.version),
pkt.c.proto == htonl(IPPROTO_TCP) ? "tcp" : "udp",
ntohl(pkt.c.port));
rply.port = htonl(1); /* TRUE = success */
}
break;
case PMAP_PROC_UNSET:
rply.port = htonl(1); /* TRUE = success */
break;
case PMAP_PROC_GETPORT:
break;
case PMAP_PROC_DUMP:
break;
default:
rply.rpc.reply_state = htonl(PROC_UNAVAIL);
break;
}
}
sendto(sock, &rply.rpc.hdr.udp, sizeof rply - 4, 0,
(struct sockaddr *)&sin, addrlen);
}
}
#ifdef TEST
int main(int argc, char *argv[])
{
if ( argc > 1 )
portmap_file = fopen(argv[1], "a");
return dummy_portmap();
}
#endif
|