ZDR: New builtin replacement for RPC/XDR called ZDR
[deb_libnfs.git] / lib / libnfs-zdr.c
1 /*
2 Copyright (C) 2012 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 /*
18 * This file contains definitions for the built in ZDR implementation.
19 * This is a very limited ZDR subset that can only marshal to/from a momory buffer,
20 * i.e. zdrmem_create() buffers.
21 * It aims to be compatible with normal rpcgen generated functions.
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include "libnfs-zdr.h"
27
28 struct opaque_auth _null_auth;
29
30 bool_t libnfs_zdr_setpos(ZDR *zdrs, uint32_t pos)
31 {
32 zdrs->pos = pos;
33 }
34
35 uint32_t libnfs_zdr_getpos(ZDR *zdrs)
36 {
37 return zdrs->pos;
38 }
39
40 void libnfs_zdrmem_create(ZDR *zdrs, const caddr_t addr, uint32_t size, enum zdr_op xop)
41 {
42 zdrs->x_op = xop;
43 zdrs->buf = addr;
44 zdrs->size = size;
45 zdrs->pos = 0;
46 zdrs->mem = NULL;
47 }
48
49 static void *zdr_malloc(ZDR *zdrs, uint32_t size)
50 {
51 struct zdr_mem *mem;
52
53 mem = malloc(sizeof(struct zdr_mem));
54 mem->next = zdrs->mem;
55 mem->size = size;
56 mem->buf = malloc(mem->size);
57 zdrs->mem = mem;
58
59 return mem->buf;
60 }
61
62 void libnfs_zdr_destroy(ZDR *zdrs)
63 {
64 while (zdrs->mem != NULL) {
65 struct zdr_mem *mem = zdrs->mem->next;
66 free(zdrs->mem->buf);
67 free(zdrs->mem);
68 zdrs->mem = mem;
69 }
70 }
71
72 bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u)
73 {
74 if (zdrs->pos + 4 > zdrs->size) {
75 return FALSE;
76 }
77
78 switch (zdrs->x_op) {
79 case ZDR_ENCODE:
80 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl(*u);
81 zdrs->pos += 4;
82 return TRUE;
83 break;
84 case ZDR_DECODE:
85 *u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
86 zdrs->pos += 4;
87 return TRUE;
88 break;
89 }
90
91 return FALSE;
92 }
93
94 bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i)
95 {
96 return libnfs_zdr_u_int(zdrs, (uint32_t *)i);
97 }
98
99 bool_t libnfs_zdr_u_quad_t(ZDR *zdrs, uint64_t *u)
100 {
101 if (zdrs->pos + 8 > zdrs->size) {
102 return FALSE;
103 }
104
105 switch (zdrs->x_op) {
106 case ZDR_ENCODE:
107 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u >> 32));
108 zdrs->pos += 4;
109 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u & 0xffffffff));
110 zdrs->pos += 4;
111 return TRUE;
112 break;
113 case ZDR_DECODE:
114 *u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
115 zdrs->pos += 4;
116 *u <<= 32;
117 *u |= ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
118 zdrs->pos += 4;
119 return TRUE;
120 break;
121 }
122
123 return FALSE;
124 }
125
126 bool_t libnfs_zdr_quad_t(ZDR *zdrs, int64_t *i)
127 {
128 return libnfs_zdr_u_quad_t(zdrs, (uint64_t *)i);
129 }
130
131 bool_t libnfs_zdr_bytes(ZDR *zdrs, char **bufp, uint32_t *size, uint32_t maxsize)
132 {
133 if (!libnfs_zdr_u_int(zdrs, size)) {
134 return FALSE;
135 }
136
137 if (zdrs->pos + *size > zdrs->size) {
138 return FALSE;
139 }
140
141 switch (zdrs->x_op) {
142 case ZDR_ENCODE:
143 memcpy(&zdrs->buf[zdrs->pos], *bufp, *size);
144 zdrs->pos += *size;
145 zdrs->pos = (zdrs->pos + 3) & ~3;
146 return TRUE;
147 case ZDR_DECODE:
148 if (*bufp == NULL) {
149 *bufp = zdr_malloc(zdrs, *size);
150 }
151 memcpy(*bufp, &zdrs->buf[zdrs->pos], *size);
152 zdrs->pos += *size;
153 zdrs->pos = (zdrs->pos + 3) & ~3;
154 return TRUE;
155 }
156
157 return FALSE;
158 }
159
160
161 bool_t libnfs_zdr_enum(ZDR *zdrs, int32_t *e)
162 {
163 return libnfs_zdr_u_int(zdrs, (uint32_t *)e);
164 }
165
166 bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b)
167 {
168 return libnfs_zdr_u_int(zdrs, (uint32_t *)b);
169 }
170
171 bool_t libnfs_zdr_void(void)
172 {
173 return TRUE;
174 }
175
176 bool_t libnfs_zdr_pointer(ZDR *zdrs, char **objp, uint32_t size, zdrproc_t proc)
177 {
178 bool_t more_data;
179
180 more_data = (*objp != NULL);
181
182 if (!libnfs_zdr_bool(zdrs, &more_data)) {
183 return FALSE;
184 }
185 if (more_data == 0) {
186 *objp = NULL;
187 return TRUE;
188 }
189
190 if (zdrs->x_op == ZDR_DECODE) {
191 *objp = zdr_malloc(zdrs, size);
192 if (*objp == NULL) {
193 return FALSE;
194 }
195 memset(*objp, 0, size);
196 }
197 return proc(zdrs, *objp);
198 }
199
200 bool_t libnfs_zdr_opaque(ZDR *zdrs, char *objp, uint32_t size)
201 {
202 switch (zdrs->x_op) {
203 case ZDR_ENCODE:
204 memcpy(&zdrs->buf[zdrs->pos], objp, size);
205 zdrs->pos += size;
206 zdrs->pos = (zdrs->pos + 3) & ~3;
207 return TRUE;
208 case ZDR_DECODE:
209 memcpy(objp, &zdrs->buf[zdrs->pos], size);
210 zdrs->pos += size;
211 zdrs->pos = (zdrs->pos + 3) & ~3;
212 return TRUE;
213 }
214
215 return FALSE;
216 }
217
218 bool_t libnfs_zdr_string(ZDR *zdrs, char **strp, uint32_t maxsize)
219 {
220 uint32_t size;
221
222 if (zdrs->x_op == ZDR_ENCODE) {
223 size = strlen(*strp);
224 }
225
226 if (!libnfs_zdr_u_int(zdrs, &size)) {
227 return FALSE;
228 }
229
230 if (zdrs->pos + size > zdrs->size) {
231 return FALSE;
232 }
233
234 switch (zdrs->x_op) {
235 case ZDR_ENCODE:
236 return libnfs_zdr_opaque(zdrs, *strp, size);
237 case ZDR_DECODE:
238 *strp = zdr_malloc(zdrs, size + 1);
239 if (*strp == NULL) {
240 return FALSE;
241 }
242 (*strp)[size] = 0;
243 return libnfs_zdr_opaque(zdrs, *strp, size);
244 }
245
246 return FALSE;
247 }
248
249 bool_t libnfs_zdr_array(ZDR *zdrs, char **arrp, uint32_t *size, uint32_t maxsize, uint32_t elsize, zdrproc_t proc)
250 {
251 int i;
252
253 if (!libnfs_zdr_u_int(zdrs, size)) {
254 return FALSE;
255 }
256
257 if (zdrs->pos + *size * elsize > zdrs->size) {
258 return FALSE;
259 }
260
261 if (zdrs->x_op == ZDR_DECODE) {
262 *arrp = zdr_malloc(zdrs, *size * elsize);
263 if (*arrp == NULL) {
264 return FALSE;
265 }
266 memset(*arrp, 0, *size * elsize);
267 }
268
269 for (i = 0; i < *size; i++) {
270 if (proc(zdrs, *arrp + i * elsize)) {
271 return FALSE;
272 }
273 }
274 return TRUE;
275 }
276
277 void libnfs_zdr_free(zdrproc_t proc, char *objp)
278 {
279 }
280
281 static bool_t libnfs_opaque_auth(ZDR *zdrs, struct opaque_auth *auth)
282 {
283 if (!libnfs_zdr_u_int(zdrs, &auth->oa_flavor)) {
284 return FALSE;
285 }
286
287 if (!libnfs_zdr_bytes(zdrs, &auth->oa_base, &auth->oa_length, &auth->oa_length)) {
288 return FALSE;
289 }
290
291 return TRUE;
292 }
293
294 static bool_t libnfs_rpc_call_body(ZDR *zdrs, struct call_body *cmb)
295 {
296 if (!libnfs_zdr_u_int(zdrs, &cmb->cb_rpcvers)) {
297 return FALSE;
298 }
299
300 if (!libnfs_zdr_u_int(zdrs, &cmb->cb_prog)) {
301 return FALSE;
302 }
303
304 if (!libnfs_zdr_u_int(zdrs, &cmb->cb_vers)) {
305 return FALSE;
306 }
307
308 if (!libnfs_zdr_u_int(zdrs, &cmb->cb_proc)) {
309 return FALSE;
310 }
311
312 if (!libnfs_opaque_auth(zdrs, &cmb->cb_cred)) {
313 return FALSE;
314 }
315
316 if (!libnfs_opaque_auth(zdrs, &cmb->cb_verf)) {
317 return FALSE;
318 }
319 }
320
321 static bool_t libnfs_accepted_reply(ZDR *zdrs, struct accepted_reply *ar)
322 {
323 if (!libnfs_opaque_auth(zdrs, &ar->ar_verf)) {
324 return FALSE;
325 }
326
327 if (!libnfs_zdr_u_int(zdrs, &ar->ar_stat)) {
328 return FALSE;
329 }
330
331 switch (ar->ar_stat) {
332 case SUCCESS:
333 if (!ar->ar_results.proc(zdrs, ar->ar_results.where)) {
334 return FALSE;
335 }
336 return TRUE;
337 case PROG_MISMATCH:
338 if (!libnfs_zdr_u_int(zdrs, &ar->ar_vers.low)) {
339 return FALSE;
340 }
341 if (!libnfs_zdr_u_int(zdrs, &ar->ar_vers.high)) {
342 return FALSE;
343 }
344 return TRUE;
345 default:
346 return TRUE;
347 }
348
349 return FALSE;
350 }
351
352 static bool_t libnfs_rejected_reply(ZDR *zdrs, struct rejected_reply *RP_dr)
353 {
354 printf("rejected reply\n");
355 exit(10);
356 }
357
358 static bool_t libnfs_rpc_reply_body(ZDR *zdrs, struct reply_body *rmb)
359 {
360 if (!libnfs_zdr_u_int(zdrs, &rmb->rp_stat)) {
361 return FALSE;
362 }
363
364 switch (rmb->rp_stat) {
365 case MSG_ACCEPTED:
366 if (!libnfs_accepted_reply(zdrs, &rmb->rp_acpt)) {
367 return FALSE;
368 }
369 return TRUE;
370 case MSG_DENIED:
371 if (!libnfs_rejected_reply(zdrs, &rmb->rp_rjct)) {
372 return FALSE;
373 }
374 return TRUE;
375 }
376
377 return FALSE;
378 }
379
380 static bool_t libnfs_rpc_msg(ZDR *zdrs, struct rpc_msg *msg)
381 {
382 if (!libnfs_zdr_u_int(zdrs, &msg->rm_xid)) {
383 return FALSE;
384 }
385
386 if (!libnfs_zdr_u_int(zdrs, &msg->rm_direction)) {
387 return FALSE;
388 }
389
390 switch (msg->rm_direction) {
391 case CALL:
392 return libnfs_rpc_call_body(zdrs, &msg->ru.RM_cmb);
393 break;
394 case REPLY:
395 return libnfs_rpc_reply_body(zdrs, &msg->ru.RM_rmb);
396 break;
397 default:
398 return FALSE;
399 }
400 }
401
402 bool_t libnfs_zdr_callmsg(ZDR *zdrs, struct rpc_msg *msg)
403 {
404 return libnfs_rpc_msg(zdrs, msg);
405 }
406
407 bool_t libnfs_zdr_replymsg(ZDR *zdrs, struct rpc_msg *msg)
408 {
409 return libnfs_rpc_msg(zdrs, msg);
410 }
411
412 AUTH *authnone_create(void)
413 {
414 AUTH *auth;
415
416 auth = malloc(sizeof(AUTH));
417
418 auth->ah_cred.oa_flavor = AUTH_NONE;
419 auth->ah_cred.oa_length = 0;
420 auth->ah_cred.oa_base = NULL;
421
422 auth->ah_verf.oa_flavor = AUTH_NONE;
423 auth->ah_verf.oa_length = 0;
424 auth->ah_verf.oa_base = NULL;
425
426 auth->ah_private = NULL;
427
428 return auth;
429 }
430
431 AUTH *libnfs_authunix_create(char *host, uint32_t uid, uint32_t gid, uint32_t len, uint32_t *groups)
432 {
433 AUTH *auth;
434 int size;
435 uint32_t *buf;
436 int idx;
437
438 size = 4 + 4 + ((strlen(host) + 3) & ~3) + 4 + 4 + 4 + len * 4;
439 auth = malloc(sizeof(AUTH));
440 auth->ah_cred.oa_flavor = AUTH_UNIX;
441 auth->ah_cred.oa_length = size;
442 auth->ah_cred.oa_base = malloc(size);
443
444 buf = auth->ah_cred.oa_base;
445 idx = 0;
446 buf[idx++] = htonl(time(NULL));
447 buf[idx++] = htonl(strlen(host));
448 memcpy(&buf[2], host, strlen(host));
449
450 idx += (strlen(host) + 3) >> 2;
451 buf[idx++] = htonl(uid);
452 buf[idx++] = htonl(gid);
453 buf[idx++] = htonl(len);
454 while (len-- > 0) {
455 buf[idx++] = htonl(*groups++);
456 }
457
458 auth->ah_verf.oa_flavor = AUTH_NONE;
459 auth->ah_verf.oa_length = 0;
460 auth->ah_verf.oa_base = NULL;
461
462 auth->ah_private = NULL;
463
464 return auth;
465 }
466
467 AUTH *libnfs_authunix_create_default(void)
468 {
469 return libnfs_authunix_create("libnfs", getuid(), -1, 0, NULL);
470 }
471
472 void libnfs_auth_destroy(AUTH *auth)
473 {
474 if (auth->ah_cred.oa_base) {
475 free(auth->ah_cred.oa_base);
476 }
477 if (auth->ah_verf.oa_base) {
478 free(auth->ah_verf.oa_base);
479 }
480 free(auth);
481 }
482