libnfs: Fix segfault if O_TRUNC fails when creating
[deb_libnfs.git] / lib / libnfs-zdr.c
... / ...
CommitLineData
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#ifdef WIN32
24#include "win32_compat.h"
25#endif
26
27#ifdef AROS
28#include "aros_compat.h"
29#endif
30
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34#include "libnfs-zdr.h"
35
36struct opaque_auth _null_auth;
37
38bool_t libnfs_zdr_setpos(ZDR *zdrs, uint32_t pos)
39{
40 zdrs->pos = pos;
41
42 return TRUE;
43}
44
45uint32_t libnfs_zdr_getpos(ZDR *zdrs)
46{
47 return zdrs->pos;
48}
49
50void libnfs_zdrmem_create(ZDR *zdrs, const caddr_t addr, uint32_t size, enum zdr_op xop)
51{
52 zdrs->x_op = xop;
53 zdrs->buf = addr;
54 zdrs->size = size;
55 zdrs->pos = 0;
56 zdrs->mem = NULL;
57}
58
59static void *zdr_malloc(ZDR *zdrs, uint32_t size)
60{
61 struct zdr_mem *mem;
62
63 mem = malloc(sizeof(struct zdr_mem));
64 mem->next = zdrs->mem;
65 mem->size = size;
66 mem->buf = malloc(mem->size);
67 zdrs->mem = mem;
68
69 return mem->buf;
70}
71
72void libnfs_zdr_destroy(ZDR *zdrs)
73{
74 while (zdrs->mem != NULL) {
75 struct zdr_mem *mem = zdrs->mem->next;
76 free(zdrs->mem->buf);
77 free(zdrs->mem);
78 zdrs->mem = mem;
79 }
80}
81
82bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u)
83{
84 if (zdrs->pos + 4 > zdrs->size) {
85 return FALSE;
86 }
87
88 switch (zdrs->x_op) {
89 case ZDR_ENCODE:
90 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl(*u);
91 zdrs->pos += 4;
92 return TRUE;
93 break;
94 case ZDR_DECODE:
95 *u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
96 zdrs->pos += 4;
97 return TRUE;
98 break;
99 }
100
101 return FALSE;
102}
103
104bool_t libnfs_zdr_int(ZDR *zdrs, int32_t *i)
105{
106 return libnfs_zdr_u_int(zdrs, (uint32_t *)i);
107}
108
109bool_t libnfs_zdr_u_quad_t(ZDR *zdrs, uint64_t *u)
110{
111 if (zdrs->pos + 8 > zdrs->size) {
112 return FALSE;
113 }
114
115 switch (zdrs->x_op) {
116 case ZDR_ENCODE:
117 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u >> 32));
118 zdrs->pos += 4;
119 *(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u & 0xffffffff));
120 zdrs->pos += 4;
121 return TRUE;
122 break;
123 case ZDR_DECODE:
124 *u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
125 zdrs->pos += 4;
126 *u <<= 32;
127 *u |= (uint32_t)ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
128 zdrs->pos += 4;
129 return TRUE;
130 break;
131 }
132
133 return FALSE;
134}
135
136bool_t libnfs_zdr_quad_t(ZDR *zdrs, int64_t *i)
137{
138 return libnfs_zdr_u_quad_t(zdrs, (uint64_t *)i);
139}
140
141bool_t libnfs_zdr_bytes(ZDR *zdrs, char **bufp, uint32_t *size, uint32_t maxsize)
142{
143 if (!libnfs_zdr_u_int(zdrs, size)) {
144 return FALSE;
145 }
146
147 if (zdrs->pos + *size > zdrs->size) {
148 return FALSE;
149 }
150
151 switch (zdrs->x_op) {
152 case ZDR_ENCODE:
153 memcpy(&zdrs->buf[zdrs->pos], *bufp, *size);
154 zdrs->pos += *size;
155 zdrs->pos = (zdrs->pos + 3) & ~3;
156 return TRUE;
157 case ZDR_DECODE:
158 if (*bufp == NULL) {
159 *bufp = zdr_malloc(zdrs, *size);
160 }
161 memcpy(*bufp, &zdrs->buf[zdrs->pos], *size);
162 zdrs->pos += *size;
163 zdrs->pos = (zdrs->pos + 3) & ~3;
164 return TRUE;
165 }
166
167 return FALSE;
168}
169
170
171bool_t libnfs_zdr_enum(ZDR *zdrs, enum_t *e)
172{
173 bool_t ret;
174 int32_t i = *e;
175
176 ret = libnfs_zdr_u_int(zdrs, (uint32_t *)&i);
177 *e = i;
178
179 return ret;
180}
181
182bool_t libnfs_zdr_bool(ZDR *zdrs, bool_t *b)
183{
184 return libnfs_zdr_u_int(zdrs, (uint32_t *)b);
185}
186
187bool_t libnfs_zdr_void(void)
188{
189 return TRUE;
190}
191
192bool_t libnfs_zdr_pointer(ZDR *zdrs, char **objp, uint32_t size, zdrproc_t proc)
193{
194 bool_t more_data;
195
196 more_data = (*objp != NULL);
197
198 if (!libnfs_zdr_bool(zdrs, &more_data)) {
199 return FALSE;
200 }
201 if (more_data == 0) {
202 *objp = NULL;
203 return TRUE;
204 }
205
206 if (zdrs->x_op == ZDR_DECODE) {
207 *objp = zdr_malloc(zdrs, size);
208 if (*objp == NULL) {
209 return FALSE;
210 }
211 memset(*objp, 0, size);
212 }
213 return proc(zdrs, *objp);
214}
215
216bool_t libnfs_zdr_opaque(ZDR *zdrs, char *objp, uint32_t size)
217{
218 switch (zdrs->x_op) {
219 case ZDR_ENCODE:
220 memcpy(&zdrs->buf[zdrs->pos], objp, size);
221 zdrs->pos += size;
222 if (zdrs->pos & 3) {
223 memset(&zdrs->buf[zdrs->pos], 0x00, 4 - (zdrs->pos & 3));
224 }
225 zdrs->pos = (zdrs->pos + 3) & ~3;
226 return TRUE;
227 case ZDR_DECODE:
228 memcpy(objp, &zdrs->buf[zdrs->pos], size);
229 zdrs->pos += size;
230 zdrs->pos = (zdrs->pos + 3) & ~3;
231 return TRUE;
232 }
233
234 return FALSE;
235}
236
237bool_t libnfs_zdr_string(ZDR *zdrs, char **strp, uint32_t maxsize)
238{
239 uint32_t size;
240
241 if (zdrs->x_op == ZDR_ENCODE) {
242 size = strlen(*strp);
243 }
244
245 if (!libnfs_zdr_u_int(zdrs, &size)) {
246 return FALSE;
247 }
248
249 if (zdrs->pos + size > zdrs->size) {
250 return FALSE;
251 }
252
253 switch (zdrs->x_op) {
254 case ZDR_ENCODE:
255 return libnfs_zdr_opaque(zdrs, *strp, size);
256 case ZDR_DECODE:
257 *strp = zdr_malloc(zdrs, size + 1);
258 if (*strp == NULL) {
259 return FALSE;
260 }
261 (*strp)[size] = 0;
262 return libnfs_zdr_opaque(zdrs, *strp, size);
263 }
264
265 return FALSE;
266}
267
268bool_t libnfs_zdr_array(ZDR *zdrs, char **arrp, uint32_t *size, uint32_t maxsize, uint32_t elsize, zdrproc_t proc)
269{
270 int i;
271
272 if (!libnfs_zdr_u_int(zdrs, size)) {
273 return FALSE;
274 }
275
276 if (zdrs->pos + *size * elsize > zdrs->size) {
277 return FALSE;
278 }
279
280 if (zdrs->x_op == ZDR_DECODE) {
281 *arrp = zdr_malloc(zdrs, *size * elsize);
282 if (*arrp == NULL) {
283 return FALSE;
284 }
285 memset(*arrp, 0, *size * elsize);
286 }
287
288 for (i = 0; i < *size; i++) {
289 if (!proc(zdrs, *arrp + i * elsize)) {
290 return FALSE;
291 }
292 }
293 return TRUE;
294}
295
296void libnfs_zdr_free(zdrproc_t proc, char *objp)
297{
298}
299
300static bool_t libnfs_opaque_auth(ZDR *zdrs, struct opaque_auth *auth)
301{
302 if (!libnfs_zdr_u_int(zdrs, &auth->oa_flavor)) {
303 return FALSE;
304 }
305
306 if (!libnfs_zdr_bytes(zdrs, &auth->oa_base, &auth->oa_length, auth->oa_length)) {
307 return FALSE;
308 }
309
310 return TRUE;
311}
312
313static bool_t libnfs_rpc_call_body(struct rpc_context *rpc, ZDR *zdrs, struct call_body *cmb)
314{
315 if (!libnfs_zdr_u_int(zdrs, &cmb->rpcvers)) {
316 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
317 "RPCVERS");
318 return FALSE;
319 }
320
321 if (!libnfs_zdr_u_int(zdrs, &cmb->prog)) {
322 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
323 "PROG");
324 return FALSE;
325 }
326
327 if (!libnfs_zdr_u_int(zdrs, &cmb->vers)) {
328 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
329 "VERS");
330 return FALSE;
331 }
332
333 if (!libnfs_zdr_u_int(zdrs, &cmb->proc)) {
334 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
335 "PROC");
336 return FALSE;
337 }
338
339 if (!libnfs_opaque_auth(zdrs, &cmb->cred)) {
340 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
341 "CRED");
342 return FALSE;
343 }
344
345 if (!libnfs_opaque_auth(zdrs, &cmb->verf)) {
346 rpc_set_error(rpc, "libnfs_rpc_call_body failed to encode "
347 "VERF");
348 return FALSE;
349 }
350
351 return TRUE;
352}
353
354static bool_t libnfs_accepted_reply(ZDR *zdrs, struct accepted_reply *ar)
355{
356 if (!libnfs_opaque_auth(zdrs, &ar->verf)) {
357 return FALSE;
358 }
359
360 if (!libnfs_zdr_u_int(zdrs, &ar->stat)) {
361 return FALSE;
362 }
363
364 switch (ar->stat) {
365 case SUCCESS:
366 if (!ar->reply_data.results.proc(zdrs, ar->reply_data.results.where)) {
367 return FALSE;
368 }
369 return TRUE;
370 case PROG_MISMATCH:
371 if (!libnfs_zdr_u_int(zdrs, &ar->reply_data.mismatch_info.low)) {
372 return FALSE;
373 }
374 if (!libnfs_zdr_u_int(zdrs, &ar->reply_data.mismatch_info.high)) {
375 return FALSE;
376 }
377 return TRUE;
378 default:
379 return TRUE;
380 }
381
382 return FALSE;
383}
384
385static bool_t libnfs_rejected_reply(ZDR *zdrs, struct rejected_reply *rr)
386{
387 if (!libnfs_zdr_u_int(zdrs, &rr->stat)) {
388 return FALSE;
389 }
390
391 switch (rr->stat) {
392 case RPC_MISMATCH:
393 if (!libnfs_zdr_u_int(zdrs, &rr->reject_data.mismatch_info.low)) {
394 return FALSE;
395 }
396 if (!libnfs_zdr_u_int(zdrs, &rr->reject_data.mismatch_info.high)) {
397 return FALSE;
398 }
399 return TRUE;
400 case AUTH_ERROR:
401 if (!libnfs_zdr_u_int(zdrs, &rr->reject_data.stat)) {
402 return FALSE;
403 }
404 return TRUE;
405 default:
406 return TRUE;
407 }
408
409 return FALSE;
410}
411
412static bool_t libnfs_rpc_reply_body(struct rpc_context *rpc, ZDR *zdrs, struct reply_body *rmb)
413{
414 if (!libnfs_zdr_u_int(zdrs, &rmb->stat)) {
415 rpc_set_error(rpc, "libnfs_rpc_reply_body failed to decode "
416 "STAT");
417 return FALSE;
418 }
419
420 switch (rmb->stat) {
421 case MSG_ACCEPTED:
422 if (!libnfs_accepted_reply(zdrs, &rmb->reply.areply)) {
423 rpc_set_error(rpc, "libnfs_rpc_reply_body failed to "
424 "decode ACCEPTED");
425 return FALSE;
426 }
427 return TRUE;
428 case MSG_DENIED:
429 if (!libnfs_rejected_reply(zdrs, &rmb->reply.rreply)) {
430 rpc_set_error(rpc, "libnfs_rpc_reply_body failed to "
431 "decode DENIED");
432 return FALSE;
433 }
434 return TRUE;
435 }
436
437 rpc_set_error(rpc, "libnfs_rpc_reply_body failed to "
438 "decode. Neither ACCEPTED nor DENIED");
439 return FALSE;
440}
441
442static bool_t libnfs_rpc_msg(struct rpc_context *rpc, ZDR *zdrs, struct rpc_msg *msg)
443{
444 int ret;
445
446 if (!libnfs_zdr_u_int(zdrs, &msg->xid)) {
447 rpc_set_error(rpc, "libnfs_rpc_msg failed to decode XID");
448 return FALSE;
449 }
450
451 if (!libnfs_zdr_u_int(zdrs, &msg->direction)) {
452 rpc_set_error(rpc, "libnfs_rpc_msg failed to decode DIRECTION");
453 return FALSE;
454 }
455
456 switch (msg->direction) {
457 case CALL:
458 ret = libnfs_rpc_call_body(rpc, zdrs, &msg->body.cbody);
459 if (!ret) {
460 rpc_set_error(rpc, "libnfs_rpc_msg failed to encode "
461 "CALL, ret=%d: %s", ret, rpc_get_error(rpc));
462 }
463 return ret;
464 case REPLY:
465 ret = libnfs_rpc_reply_body(rpc, zdrs, &msg->body.rbody);
466 if (!ret) {
467 rpc_set_error(rpc, "libnfs_rpc_msg failed to decode "
468 "REPLY, ret=%d: %s", ret, rpc_get_error(rpc));
469 }
470 return ret;
471 default:
472 rpc_set_error(rpc, "libnfs_rpc_msg failed to decode. "
473 "Neither CALL not REPLY");
474 return FALSE;
475 }
476}
477
478bool_t libnfs_zdr_callmsg(struct rpc_context *rpc, ZDR *zdrs, struct rpc_msg *msg)
479{
480 return libnfs_rpc_msg(rpc, zdrs, msg);
481}
482
483bool_t libnfs_zdr_replymsg(struct rpc_context *rpc, ZDR *zdrs, struct rpc_msg *msg)
484{
485 return libnfs_rpc_msg(rpc, zdrs, msg);
486}
487
488struct AUTH *authnone_create(void)
489{
490 struct AUTH *auth;
491
492 auth = malloc(sizeof(struct AUTH));
493
494 auth->ah_cred.oa_flavor = AUTH_NONE;
495 auth->ah_cred.oa_length = 0;
496 auth->ah_cred.oa_base = NULL;
497
498 auth->ah_verf.oa_flavor = AUTH_NONE;
499 auth->ah_verf.oa_length = 0;
500 auth->ah_verf.oa_base = NULL;
501
502 auth->ah_private = NULL;
503
504 return auth;
505}
506
507struct AUTH *libnfs_authunix_create(char *host, uint32_t uid, uint32_t gid, uint32_t len, uint32_t *groups)
508{
509 struct AUTH *auth;
510 int size;
511 uint32_t *buf;
512 int idx;
513
514 size = 4 + 4 + ((strlen(host) + 3) & ~3) + 4 + 4 + 4 + len * 4;
515 auth = malloc(sizeof(struct AUTH));
516 memset(auth, 0x00, sizeof(struct AUTH));
517 auth->ah_cred.oa_flavor = AUTH_UNIX;
518 auth->ah_cred.oa_length = size;
519 auth->ah_cred.oa_base = malloc(size);
520
521 memset(auth->ah_cred.oa_base, 0x00, size);
522 buf = (uint32_t *)auth->ah_cred.oa_base;
523 idx = 0;
524 buf[idx++] = htonl(time(NULL));
525 buf[idx++] = htonl(strlen(host));
526 memcpy(&buf[2], host, strlen(host));
527
528 idx += (strlen(host) + 3) >> 2;
529 buf[idx++] = htonl(uid);
530 buf[idx++] = htonl(gid);
531 buf[idx++] = htonl(len);
532 while (len-- > 0) {
533 buf[idx++] = htonl(*groups++);
534 }
535
536 auth->ah_verf.oa_flavor = AUTH_NONE;
537 auth->ah_verf.oa_length = 0;
538 auth->ah_verf.oa_base = NULL;
539
540 auth->ah_private = NULL;
541
542 return auth;
543}
544
545struct AUTH *libnfs_authunix_create_default(void)
546{
547#ifdef WIN32
548 return libnfs_authunix_create("libnfs", 65534, 65534, 0, NULL);
549#else
550 return libnfs_authunix_create("libnfs", getuid(), getgid(), 0, NULL);
551#endif
552}
553
554void libnfs_auth_destroy(struct AUTH *auth)
555{
556 if (auth->ah_cred.oa_base) {
557 free(auth->ah_cred.oa_base);
558 }
559 if (auth->ah_verf.oa_base) {
560 free(auth->ah_verf.oa_base);
561 }
562 free(auth);
563}
564