15 |
#include <string.h> |
#include <string.h> |
16 |
#include <sys/socket.h> |
#include <sys/socket.h> |
17 |
|
|
18 |
|
#include "dummypmap.h" |
19 |
#include "sunrpc.h" |
#include "sunrpc.h" |
20 |
|
|
21 |
extern const char *progname; |
extern const char *progname; |
22 |
|
|
23 |
struct portmap_call { |
struct portmap_args { |
|
struct rpc_call rpc; |
|
24 |
uint32_t program; |
uint32_t program; |
25 |
uint32_t version; |
uint32_t version; |
26 |
uint32_t proto; |
uint32_t proto; |
27 |
uint32_t port; |
uint32_t port; |
28 |
}; |
}; |
29 |
|
|
30 |
|
struct portmap_call { |
31 |
|
struct rpc_call rpc; |
32 |
|
struct portmap_args args; |
33 |
|
}; |
34 |
|
|
35 |
struct portmap_reply { |
struct portmap_reply { |
36 |
struct rpc_reply rpc; |
struct rpc_reply rpc; |
37 |
uint32_t port; |
uint32_t port; |
71 |
} |
} |
72 |
} |
} |
73 |
|
|
74 |
|
static void * get_auth(struct rpc_auth *auth) |
75 |
|
{ |
76 |
|
switch (ntohl(auth->flavor)) { |
77 |
|
case AUTH_NULL: |
78 |
|
/* Fallthrough */ |
79 |
|
case AUTH_UNIX: |
80 |
|
return (char *)&auth->body + ntohl(auth->len); |
81 |
|
default: |
82 |
|
return NULL; |
83 |
|
} |
84 |
|
} |
85 |
|
|
86 |
|
static int check_unix_cred(struct rpc_auth *cred) |
87 |
|
{ |
88 |
|
uint32_t len; |
89 |
|
int quad_len; |
90 |
|
uint32_t node_name_len; |
91 |
|
int quad_name_len; |
92 |
|
uint32_t *base; |
93 |
|
uint32_t *pos; |
94 |
|
int ret = -1; |
95 |
|
|
96 |
|
len = ntohl(cred->len); |
97 |
|
quad_len = (len + 3) >> 2; |
98 |
|
if (quad_len < 6) |
99 |
|
/* Malformed creds */ |
100 |
|
goto out; |
101 |
|
|
102 |
|
base = pos = cred->body; |
103 |
|
|
104 |
|
/* Skip timestamp */ |
105 |
|
pos++; |
106 |
|
|
107 |
|
/* Skip node name: only localhost can succeed. */ |
108 |
|
node_name_len = ntohl(*pos++); |
109 |
|
quad_name_len = (node_name_len + 3) >> 2; |
110 |
|
if (pos + quad_name_len + 3 > base + quad_len) |
111 |
|
/* Malformed creds */ |
112 |
|
goto out; |
113 |
|
pos += quad_name_len; |
114 |
|
|
115 |
|
/* uid must be 0 */ |
116 |
|
if (*pos++ != 0) |
117 |
|
goto out; |
118 |
|
|
119 |
|
/* gid must be 0 */ |
120 |
|
if (*pos++ != 0) |
121 |
|
goto out; |
122 |
|
|
123 |
|
/* Skip remaining gids */ |
124 |
|
ret = 0; |
125 |
|
|
126 |
|
out: |
127 |
|
return ret; |
128 |
|
} |
129 |
|
|
130 |
|
static int check_cred(struct rpc_auth *cred) |
131 |
|
{ |
132 |
|
switch (ntohl(cred->flavor)) { |
133 |
|
case AUTH_NULL: |
134 |
|
return 0; |
135 |
|
case AUTH_UNIX: |
136 |
|
return check_unix_cred(cred); |
137 |
|
default: |
138 |
|
return -1; |
139 |
|
} |
140 |
|
} |
141 |
|
|
142 |
|
static int check_vrf(struct rpc_auth *vrf) |
143 |
|
{ |
144 |
|
return (vrf->flavor == htonl(AUTH_NULL)) ? 0 : -1; |
145 |
|
} |
146 |
|
|
147 |
static int dummy_portmap(int sock, FILE *portmap_file) |
static int dummy_portmap(int sock, FILE *portmap_file) |
148 |
{ |
{ |
149 |
struct sockaddr_in sin; |
struct sockaddr_in sin; |
150 |
int pktlen, addrlen; |
int pktlen, addrlen; |
151 |
union { |
unsigned char pkt[65536]; /* Max UDP packet size */ |
152 |
struct portmap_call c; |
/* RPC UDP packets do not include TCP fragment size */ |
153 |
unsigned char b[65536]; /* Max UDP packet size */ |
struct rpc_call *rpc = (struct rpc_call *) &pkt[-4]; |
154 |
} pkt; |
struct rpc_auth *cred; |
155 |
|
struct rpc_auth *vrf; |
156 |
|
struct portmap_args *args; |
157 |
struct portmap_reply rply; |
struct portmap_reply rply; |
158 |
|
|
159 |
for (;;) { |
for (;;) { |
160 |
addrlen = sizeof sin; |
addrlen = sizeof sin; |
161 |
pktlen = recvfrom(sock, &pkt.c.rpc.hdr.udp, sizeof pkt, 0, |
pktlen = recvfrom(sock, &pkt, sizeof pkt, 0, |
162 |
(struct sockaddr *)&sin, &addrlen); |
(struct sockaddr *)&sin, &addrlen); |
163 |
|
|
164 |
if (pktlen < 0) { |
if (pktlen < 0) { |
172 |
if (pktlen + 4 < sizeof(struct portmap_call)) |
if (pktlen + 4 < sizeof(struct portmap_call)) |
173 |
continue; /* Bad packet */ |
continue; /* Bad packet */ |
174 |
|
|
175 |
if (pkt.c.rpc.hdr.udp.msg_type != htonl(RPC_CALL)) |
if (rpc->hdr.udp.msg_type != htonl(RPC_CALL)) |
176 |
continue; /* Bad packet */ |
continue; /* Bad packet */ |
177 |
|
|
178 |
memset(&rply, 0, sizeof rply); |
memset(&rply, 0, sizeof rply); |
179 |
|
|
180 |
rply.rpc.hdr.udp.xid = pkt.c.rpc.hdr.udp.xid; |
rply.rpc.hdr.udp.xid = rpc->hdr.udp.xid; |
181 |
rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY); |
rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY); |
182 |
|
|
183 |
if (pkt.c.rpc.rpc_vers != htonl(2)) { |
cred = (struct rpc_auth *) &rpc->cred_flavor; |
184 |
|
if (rpc->rpc_vers != htonl(2)) { |
185 |
rply.rpc.reply_state = htonl(REPLY_DENIED); |
rply.rpc.reply_state = htonl(REPLY_DENIED); |
186 |
/* state <- RPC_MISMATCH == 0 */ |
/* state <- RPC_MISMATCH == 0 */ |
187 |
} else if (pkt.c.rpc.program != htonl(PORTMAP_PROGRAM)) { |
} else if (rpc->program != htonl(PORTMAP_PROGRAM)) { |
188 |
rply.rpc.reply_state = htonl(PROG_UNAVAIL); |
rply.rpc.reply_state = htonl(PROG_UNAVAIL); |
189 |
} else if (pkt.c.rpc.prog_vers != htonl(2)) { |
} else if (rpc->prog_vers != htonl(2)) { |
190 |
rply.rpc.reply_state = htonl(PROG_MISMATCH); |
rply.rpc.reply_state = htonl(PROG_MISMATCH); |
191 |
} else if (pkt.c.rpc.cred_len != 0 || pkt.c.rpc.vrf_len != 0) { |
} else if (!(vrf = get_auth(cred)) || |
192 |
|
(char *)vrf > (char *)pkt + pktlen - 8 - sizeof(*args) || |
193 |
|
!(args = get_auth(vrf)) || |
194 |
|
(char *)args > (char *)pkt + pktlen - sizeof(*args) || |
195 |
|
check_cred(cred) || check_vrf(vrf)) { |
196 |
/* Can't deal with credentials data; the kernel |
/* Can't deal with credentials data; the kernel |
197 |
won't send them */ |
won't send them */ |
198 |
rply.rpc.reply_state = htonl(SYSTEM_ERR); |
rply.rpc.reply_state = htonl(SYSTEM_ERR); |
199 |
} else { |
} else { |
200 |
switch (ntohl(pkt.c.rpc.proc)) { |
switch (ntohl(rpc->proc)) { |
201 |
case PMAP_PROC_NULL: |
case PMAP_PROC_NULL: |
202 |
break; |
break; |
203 |
case PMAP_PROC_SET: |
case PMAP_PROC_SET: |
204 |
if (pkt.c.proto == htonl(IPPROTO_TCP) || |
if (args->proto == htonl(IPPROTO_TCP) || |
205 |
pkt.c.proto == htonl(IPPROTO_UDP)) { |
args->proto == htonl(IPPROTO_UDP)) { |
206 |
if (portmap_file) |
if (portmap_file) |
207 |
fprintf(portmap_file, |
fprintf(portmap_file, |
208 |
"%u %u %s %u\n", |
"%u %u %s %u\n", |
209 |
ntohl(pkt.c.program), |
ntohl(args->program), |
210 |
ntohl(pkt.c.version), |
ntohl(args->version), |
211 |
protoname(pkt.c.proto), |
protoname(args->proto), |
212 |
ntohl(pkt.c.port)); |
ntohl(args->port)); |
213 |
rply.port = htonl(1); /* TRUE = success */ |
rply.port = htonl(1); /* TRUE = success */ |
214 |
} |
} |
215 |
break; |
break; |