xref: /illumos-gate/usr/src/uts/common/fs/autofs/auto_xdr.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file can not be automatically generated by rpcgen from
30  * autofs_prot.x because of the xdr routines that provide readdir
31  * support, its own implementation of xdr_autofs_netbuf(). rpcgen will
32  * also generate xdr routines with recursion which should not be used
33  * in the kernel.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/kmem.h>
38 #include <sys/errno.h>
39 #include <sys/proc.h>
40 #include <sys/vfs.h>
41 #include <sys/vnode.h>
42 #include <sys/pathname.h>
43 #include <sys/cred.h>
44 #include <sys/mount.h>
45 #include <sys/cmn_err.h>
46 #include <sys/debug.h>
47 #include <sys/systm.h>
48 #include <rpc/types.h>
49 #include <rpc/xdr.h>
50 #include <rpc/auth.h>
51 #include <rpc/clnt.h>
52 #include <sys/ticotsord.h>
53 #include <sys/dirent.h>
54 #include <sys/sysmacros.h>
55 #include <fs/fs_subr.h>
56 #include <sys/fs/autofs.h>
57 
58 bool_t xdr_autofs_netbuf(XDR *, struct netbuf *);
59 bool_t xdr_mounta(XDR *, struct mounta *);
60 
61 bool_t
62 xdr_umntrequest(XDR *xdrs, umntrequest *objp)
63 {
64 	bool_t more_data;
65 
66 	ASSERT(xdrs->x_op == XDR_ENCODE);
67 
68 	for (; objp != NULL; objp = objp->next) {
69 		if (!xdr_bool_t(xdrs, &objp->isdirect))
70 			return (FALSE);
71 		if (!xdr_string(xdrs, &objp->mntresource, AUTOFS_MAXPATHLEN))
72 			return (FALSE);
73 		if (!xdr_string(xdrs, &objp->mntpnt, AUTOFS_MAXPATHLEN))
74 			return (FALSE);
75 		if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
76 			return (FALSE);
77 		if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN))
78 			return (FALSE);
79 
80 		if (objp->next != NULL)
81 			more_data = TRUE;
82 		else
83 			more_data = FALSE;
84 
85 		if (!xdr_bool(xdrs, &more_data))
86 			return (FALSE);
87 	}
88 	return (TRUE);
89 }
90 
91 bool_t
92 xdr_umntres(XDR *xdrs, umntres *objp)
93 {
94 	return (xdr_int(xdrs, &objp->status));
95 }
96 
97 bool_t
98 xdr_autofs_stat(XDR *xdrs, autofs_stat *objp)
99 {
100 	if (!xdr_enum(xdrs, (enum_t *)objp))
101 		return (FALSE);
102 	return (TRUE);
103 }
104 
105 bool_t
106 xdr_autofs_action(XDR *xdrs, autofs_action *objp)
107 {
108 	if (!xdr_enum(xdrs, (enum_t *)objp))
109 		return (FALSE);
110 	return (TRUE);
111 }
112 
113 bool_t
114 xdr_linka(XDR *xdrs, linka *objp)
115 {
116 	if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
117 		return (FALSE);
118 	if (!xdr_string(xdrs, &objp->link, AUTOFS_MAXPATHLEN))
119 		return (FALSE);
120 	return (TRUE);
121 }
122 
123 bool_t
124 xdr_autofs_args(XDR *xdrs, autofs_args *objp)
125 {
126 	if (!xdr_autofs_netbuf(xdrs, &objp->addr))
127 		return (FALSE);
128 	if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
129 		return (FALSE);
130 	if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
131 		return (FALSE);
132 	if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
133 		return (FALSE);
134 	if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
135 		return (FALSE);
136 	if (!xdr_string(xdrs, &objp->key, AUTOFS_MAXCOMPONENTLEN))
137 		return (FALSE);
138 	if (!xdr_int(xdrs, &objp->mount_to))
139 		return (FALSE);
140 	if (!xdr_int(xdrs, &objp->rpc_to))
141 		return (FALSE);
142 	if (!xdr_int(xdrs, &objp->direct))
143 		return (FALSE);
144 	return (TRUE);
145 }
146 
147 bool_t
148 xdr_action_list_entry(XDR *xdrs, action_list_entry *objp)
149 {
150 	if (!xdr_autofs_action(xdrs, &objp->action))
151 		return (FALSE);
152 	switch (objp->action) {
153 	case AUTOFS_MOUNT_RQ:
154 		if (!xdr_mounta(xdrs, &objp->action_list_entry_u.mounta))
155 			return (FALSE);
156 		break;
157 	case AUTOFS_LINK_RQ:
158 		if (!xdr_linka(xdrs, &objp->action_list_entry_u.linka))
159 			return (FALSE);
160 		break;
161 	default:
162 		break;
163 	}
164 	return (TRUE);
165 }
166 
167 bool_t
168 xdr_action_list(XDR *xdrs, action_list *objp)
169 {
170 	bool_t more_data = TRUE;
171 	bool_t status = TRUE;
172 	action_list *p;
173 
174 	ASSERT((xdrs->x_op == XDR_DECODE) || (xdrs->x_op == XDR_FREE));
175 
176 	more_data = (objp != NULL);
177 	p = objp;
178 
179 	if (xdrs->x_op == XDR_FREE)
180 		goto free;
181 
182 	while (more_data) {
183 		if (!xdr_action_list_entry(xdrs, &p->action))
184 			goto free;
185 
186 		if (!xdr_bool(xdrs, &more_data))
187 			goto free;
188 
189 		if (more_data) {
190 			p->next = kmem_zalloc(sizeof (action_list), KM_SLEEP);
191 			p = p->next;
192 			if (p == NULL) {
193 				status = FALSE;
194 				goto free;
195 			}
196 		} else
197 			p->next = NULL;
198 	}
199 	return (TRUE);
200 
201 free:
202 	for (p = objp; p != NULL; ) {
203 		if (!xdr_action_list_entry(xdrs, &objp->action))
204 			cmn_err(CE_WARN, "xdr_action_list: "
205 			    "action_list_entry free failed %p\n",
206 			    (void *)&objp->action);
207 		p = p->next;
208 		kmem_free(objp, sizeof (*objp));
209 		objp = p;
210 	}
211 	objp = NULL;
212 
213 	return (status);
214 }
215 
216 bool_t
217 xdr_autofs_netbuf(XDR *xdrs, struct netbuf *objp)
218 {
219 	bool_t dummy;
220 
221 	if (!xdr_u_int(xdrs, (uint_t *)&objp->maxlen))
222 		return (FALSE);
223 	dummy = xdr_bytes(xdrs, (char **)&(objp->buf),
224 	    (uint_t *)&(objp->len), objp->maxlen);
225 	return (dummy);
226 }
227 
228 bool_t
229 xdr_mounta(XDR *xdrs, struct mounta *objp)
230 {
231 	if (!xdr_string(xdrs, &objp->spec, AUTOFS_MAXPATHLEN))
232 		return (FALSE);
233 	if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
234 		return (FALSE);
235 	if (!xdr_int(xdrs, &objp->flags))
236 		return (FALSE);
237 	if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
238 		return (FALSE);
239 	if (!xdr_pointer(xdrs, (char **)&objp->dataptr, sizeof (autofs_args),
240 	    (xdrproc_t)xdr_autofs_args))
241 		return (FALSE);
242 	/*
243 	 * The length is the original user-land length, not the
244 	 * length of the native kernel autofs_args structure provided
245 	 * after we decode the xdr buffer.  So passing the user's idea of
246 	 * the length is wrong and we need to stuff the length field with
247 	 * the length of the native structure.
248 	 */
249 	if (!xdr_int(xdrs, &objp->datalen))
250 		return (FALSE);
251 	if (xdrs->x_op == XDR_DECODE)
252 		objp->datalen = sizeof (struct autofs_args);
253 	if (!xdr_string(xdrs, &objp->optptr, AUTOFS_MAXOPTSLEN))
254 		return (FALSE);
255 	if (!xdr_int(xdrs, &objp->optlen))
256 		return (FALSE);
257 	ASSERT((xdrs->x_op == XDR_DECODE) || (xdrs->x_op == XDR_FREE));
258 	return (TRUE);
259 }
260 
261 bool_t
262 xdr_autofs_res(XDR *xdrs, autofs_res *objp)
263 {
264 	if (!xdr_enum(xdrs, (enum_t *)objp))
265 		return (FALSE);
266 	return (TRUE);
267 }
268 
269 bool_t
270 xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp)
271 {
272 	if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
273 		return (FALSE);
274 	if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
275 		return (FALSE);
276 	if (!xdr_string(xdrs, &objp->name, AUTOFS_MAXCOMPONENTLEN))
277 		return (FALSE);
278 	if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
279 		return (FALSE);
280 	if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
281 		return (FALSE);
282 	if (!xdr_bool_t(xdrs, &objp->isdirect))
283 		return (FALSE);
284 	if (!xdr_u_int(xdrs, (uint_t *)&objp->uid))
285 		return (FALSE);
286 	return (TRUE);
287 }
288 
289 bool_t
290 xdr_mount_result_type(XDR *xdrs, mount_result_type *objp)
291 {
292 	if (!xdr_autofs_stat(xdrs, &objp->status))
293 		return (FALSE);
294 	switch (objp->status) {
295 	case AUTOFS_ACTION:
296 		if (!xdr_pointer(xdrs,
297 		    (char **)&objp->mount_result_type_u.list,
298 		    sizeof (action_list), (xdrproc_t)xdr_action_list))
299 			return (FALSE);
300 		break;
301 	case AUTOFS_DONE:
302 		if (!xdr_int(xdrs, &objp->mount_result_type_u.error))
303 			return (FALSE);
304 		break;
305 	}
306 	return (TRUE);
307 }
308 
309 bool_t
310 xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp)
311 {
312 	if (!xdr_mount_result_type(xdrs, &objp->mr_type))
313 		return (FALSE);
314 	if (!xdr_int(xdrs, &objp->mr_verbose))
315 		return (FALSE);
316 	return (TRUE);
317 }
318 
319 bool_t
320 xdr_lookup_result_type(XDR *xdrs, lookup_result_type *objp)
321 {
322 	if (!xdr_autofs_action(xdrs, &objp->action))
323 		return (FALSE);
324 	switch (objp->action) {
325 	case AUTOFS_LINK_RQ:
326 		if (!xdr_linka(xdrs, &objp->lookup_result_type_u.lt_linka))
327 			return (FALSE);
328 		break;
329 	default:
330 		break;
331 	}
332 	return (TRUE);
333 }
334 
335 bool_t
336 xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp)
337 {
338 	if (!xdr_autofs_res(xdrs, &objp->lu_res))
339 		return (FALSE);
340 	if (!xdr_lookup_result_type(xdrs, &objp->lu_type))
341 		return (FALSE);
342 	if (!xdr_int(xdrs, &objp->lu_verbose))
343 		return (FALSE);
344 	return (TRUE);
345 }
346 
347 bool_t
348 xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp)
349 {
350 	if (!xdr_string(xdrs, &objp->rda_map, AUTOFS_MAXPATHLEN))
351 		return (FALSE);
352 	if (!xdr_u_int(xdrs, &objp->rda_offset))
353 		return (FALSE);
354 	if (!xdr_u_int(xdrs, &objp->rda_count))
355 		return (FALSE);
356 	if (!xdr_u_int(xdrs, (uint_t *)&objp->uid))
357 		return (FALSE);
358 	return (TRUE);
359 }
360 
361 /*
362  * Directory read reply:
363  * union (enum autofs_res) {
364  *	AUTOFS_OK: entlist;
365  *		 boolean eof;
366  *	default:
367  * }
368  *
369  * Directory entries
370  *	struct  direct {
371  *		off_t   d_off;			* offset of next entry *
372  *		u_long  d_fileno;		* inode number of entry *
373  *		ushort_t d_reclen;		* length of this record *
374  *		ushort_t d_namlen;		* length of string in d_name *
375  *		char    d_name[MAXNAMLEN + 1];	* name no longer than this *
376  *	};
377  * are on the wire as:
378  * union entlist (boolean valid) {
379  * 	TRUE:	struct otw_dirent;
380  *		uint_t nxtoffset;
381  *		union entlist;
382  *	FALSE:
383  * }
384  * where otw_dirent is:
385  * 	struct dirent {
386  *		uint_t	de_fid;
387  *		string	de_name<AUTOFS_MAXPATHLEN>;
388  *	}
389  */
390 
391 #ifdef nextdp
392 #undef nextdp
393 #endif
394 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
395 
396 /*
397  * ENCODE ONLY
398  */
399 bool_t
400 xdr_autofs_putrddirres(XDR *xdrs, struct autofsrddir *rddir, uint_t reqsize)
401 {
402 	struct dirent64 *dp;
403 	char *name;
404 	int size;
405 	uint_t namlen;
406 	bool_t true = TRUE;
407 	bool_t false = FALSE;
408 	int entrysz;
409 	int tofit;
410 	int bufsize;
411 	uint_t ino, off;
412 
413 	bufsize = 1 * BYTES_PER_XDR_UNIT;
414 	for (size = rddir->rddir_size, dp = rddir->rddir_entries;
415 		size > 0;
416 		/* LINTED pointer alignment */
417 		size -= dp->d_reclen, dp = nextdp(dp)) {
418 		if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */)
419 			return (FALSE);
420 		if (dp->d_ino == 0)
421 			continue;
422 		name = dp->d_name;
423 		namlen = (uint_t)strlen(name);
424 		ino = (uint_t)dp->d_ino;
425 		off = (uint_t)dp->d_off;
426 		entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
427 		    roundup(namlen, BYTES_PER_XDR_UNIT);
428 		tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
429 		if (bufsize + tofit > reqsize) {
430 			rddir->rddir_eof = FALSE;
431 			break;
432 		}
433 		if (!xdr_bool(xdrs, &true) ||
434 		    !xdr_u_int(xdrs, &ino) ||
435 		    !xdr_bytes(xdrs, &name, &namlen, AUTOFS_MAXPATHLEN) ||
436 		    !xdr_u_int(xdrs, &off)) {
437 			return (FALSE);
438 		}
439 		bufsize += entrysz;
440 	}
441 	if (!xdr_bool(xdrs, &false))
442 		return (FALSE);
443 	if (!xdr_bool(xdrs, &rddir->rddir_eof))
444 		return (FALSE);
445 	return (TRUE);
446 }
447 
448 
449 /*
450  * DECODE ONLY
451  */
452 bool_t
453 xdr_autofs_getrddirres(XDR *xdrs, struct autofsrddir *rddir)
454 {
455 	struct dirent64 *dp;
456 	uint_t namlen;
457 	int size;
458 	bool_t valid;
459 	uint_t offset;
460 	uint_t fileid;
461 
462 	offset = (uint_t)-1;
463 
464 	size = rddir->rddir_size;
465 	dp = rddir->rddir_entries;
466 	for (;;) {
467 		if (!xdr_bool(xdrs, &valid))
468 			return (FALSE);
469 		if (!valid)
470 			break;
471 		if (!xdr_u_int(xdrs, &fileid) ||
472 		    !xdr_u_int(xdrs, &namlen))
473 			return (FALSE);
474 		if (DIRENT64_RECLEN(namlen) > size) {
475 			rddir->rddir_eof = FALSE;
476 			goto bufovflw;
477 		}
478 		if (!xdr_opaque(xdrs, dp->d_name, namlen)||
479 		    !xdr_u_int(xdrs, &offset))
480 			return (FALSE);
481 		dp->d_ino = fileid;
482 		dp->d_reclen = (ushort_t)DIRENT64_RECLEN(namlen);
483 		bzero(&dp->d_name[namlen],
484 		    DIRENT64_NAMELEN(dp->d_reclen) - namlen);
485 		dp->d_off = offset;
486 		size -= dp->d_reclen;
487 		/* LINTED pointer alignment */
488 		dp = nextdp(dp);
489 	}
490 	if (!xdr_bool(xdrs, &rddir->rddir_eof))
491 		return (FALSE);
492 bufovflw:
493 	rddir->rddir_size = (uint_t)((char *)dp - (char *)rddir->rddir_entries);
494 	rddir->rddir_offset = offset;
495 	return (TRUE);
496 }
497 
498 bool_t
499 xdr_autofs_rddirres(XDR *xdrs, autofs_rddirres *objp)
500 {
501 	if (!xdr_enum(xdrs, (enum_t *)&objp->rd_status))
502 		return (FALSE);
503 	if (objp->rd_status != AUTOFS_OK)
504 		return (TRUE);
505 	if (xdrs->x_op == XDR_ENCODE)
506 		return (xdr_autofs_putrddirres(xdrs,
507 		    (struct autofsrddir *)&objp->rd_rddir, objp->rd_bufsize));
508 	else if (xdrs->x_op == XDR_DECODE)
509 		return (xdr_autofs_getrddirres(xdrs,
510 		    (struct autofsrddir *)&objp->rd_rddir));
511 	return (FALSE);
512 }
513