File: dummypmap.c

package info (click to toggle)
yaird 0.0.12-18etch1
  • links: PTS
  • area: main
  • in suites: etch
  • size: 1,432 kB
  • ctags: 725
  • sloc: perl: 4,161; xml: 3,233; ansic: 3,105; sh: 876; makefile: 150
file content (146 lines) | stat: -rw-r--r-- 3,379 bytes parent folder | download | duplicates (2)
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