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 2006 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 	return (TRUE);
285 }
286 
287 bool_t
288 xdr_mount_result_type(XDR *xdrs, mount_result_type *objp)
289 {
290 	if (!xdr_autofs_stat(xdrs, &objp->status))
291 		return (FALSE);
292 	switch (objp->status) {
293 	case AUTOFS_ACTION:
294 		if (!xdr_pointer(xdrs,
295 		    (char **)&objp->mount_result_type_u.list,
296 		    sizeof (action_list), (xdrproc_t)xdr_action_list))
297 			return (FALSE);
298 		break;
299 	case AUTOFS_DONE:
300 		if (!xdr_int(xdrs, &objp->mount_result_type_u.error))
301 			return (FALSE);
302 		break;
303 	}
304 	return (TRUE);
305 }
306 
307 bool_t
308 xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp)
309 {
310 	if (!xdr_mount_result_type(xdrs, &objp->mr_type))
311 		return (FALSE);
312 	if (!xdr_int(xdrs, &objp->mr_verbose))
313 		return (FALSE);
314 	return (TRUE);
315 }
316 
317 bool_t
318 xdr_lookup_result_type(XDR *xdrs, lookup_result_type *objp)
319 {
320 	if (!xdr_autofs_action(xdrs, &objp->action))
321 		return (FALSE);
322 	switch (objp->action) {
323 	case AUTOFS_LINK_RQ:
324 		if (!xdr_linka(xdrs, &objp->lookup_result_type_u.lt_linka))
325 			return (FALSE);
326 		break;
327 	default:
328 		break;
329 	}
330 	return (TRUE);
331 }
332 
333 bool_t
334 xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp)
335 {
336 	if (!xdr_autofs_res(xdrs, &objp->lu_res))
337 		return (FALSE);
338 	if (!xdr_lookup_result_type(xdrs, &objp->lu_type))
339 		return (FALSE);
340 	if (!xdr_int(xdrs, &objp->lu_verbose))
341 		return (FALSE);
342 	return (TRUE);
343 }
344 
345 bool_t
346 xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp)
347 {
348 	if (!xdr_string(xdrs, &objp->rda_map, AUTOFS_MAXPATHLEN))
349 		return (FALSE);
350 	if (!xdr_u_int(xdrs, &objp->rda_offset))
351 		return (FALSE);
352 	if (!xdr_u_int(xdrs, &objp->rda_count))
353 		return (FALSE);
354 	return (TRUE);
355 }
356 
357 /*
358  * Directory read reply:
359  * union (enum autofs_res) {
360  *	AUTOFS_OK: entlist;
361  *		 boolean eof;
362  *	default:
363  * }
364  *
365  * Directory entries
366  *	struct  direct {
367  *		off_t   d_off;			* offset of next entry *
368  *		u_long  d_fileno;		* inode number of entry *
369  *		ushort_t d_reclen;		* length of this record *
370  *		ushort_t d_namlen;		* length of string in d_name *
371  *		char    d_name[MAXNAMLEN + 1];	* name no longer than this *
372  *	};
373  * are on the wire as:
374  * union entlist (boolean valid) {
375  * 	TRUE:	struct otw_dirent;
376  *		uint_t nxtoffset;
377  *		union entlist;
378  *	FALSE:
379  * }
380  * where otw_dirent is:
381  * 	struct dirent {
382  *		uint_t	de_fid;
383  *		string	de_name<AUTOFS_MAXPATHLEN>;
384  *	}
385  */
386 
387 #ifdef nextdp
388 #undef nextdp
389 #endif
390 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
391 
392 /*
393  * ENCODE ONLY
394  */
395 bool_t
396 xdr_autofs_putrddirres(XDR *xdrs, struct autofsrddir *rddir, uint_t reqsize)
397 {
398 	struct dirent64 *dp;
399 	char *name;
400 	int size;
401 	uint_t namlen;
402 	bool_t true = TRUE;
403 	bool_t false = FALSE;
404 	int entrysz;
405 	int tofit;
406 	int bufsize;
407 	uint_t ino, off;
408 
409 	bufsize = 1 * BYTES_PER_XDR_UNIT;
410 	for (size = rddir->rddir_size, dp = rddir->rddir_entries;
411 		size > 0;
412 		/* LINTED pointer alignment */
413 		size -= dp->d_reclen, dp = nextdp(dp)) {
414 		if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */)
415 			return (FALSE);
416 		if (dp->d_ino == 0)
417 			continue;
418 		name = dp->d_name;
419 		namlen = (uint_t)strlen(name);
420 		ino = (uint_t)dp->d_ino;
421 		off = (uint_t)dp->d_off;
422 		entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
423 		    roundup(namlen, BYTES_PER_XDR_UNIT);
424 		tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
425 		if (bufsize + tofit > reqsize) {
426 			rddir->rddir_eof = FALSE;
427 			break;
428 		}
429 		if (!xdr_bool(xdrs, &true) ||
430 		    !xdr_u_int(xdrs, &ino) ||
431 		    !xdr_bytes(xdrs, &name, &namlen, AUTOFS_MAXPATHLEN) ||
432 		    !xdr_u_int(xdrs, &off)) {
433 			return (FALSE);
434 		}
435 		bufsize += entrysz;
436 	}
437 	if (!xdr_bool(xdrs, &false))
438 		return (FALSE);
439 	if (!xdr_bool(xdrs, &rddir->rddir_eof))
440 		return (FALSE);
441 	return (TRUE);
442 }
443 
444 
445 /*
446  * DECODE ONLY
447  */
448 bool_t
449 xdr_autofs_getrddirres(XDR *xdrs, struct autofsrddir *rddir)
450 {
451 	struct dirent64 *dp;
452 	uint_t namlen;
453 	int size;
454 	bool_t valid;
455 	uint_t offset;
456 	uint_t fileid;
457 
458 	offset = (uint_t)-1;
459 
460 	size = rddir->rddir_size;
461 	dp = rddir->rddir_entries;
462 	for (;;) {
463 		if (!xdr_bool(xdrs, &valid))
464 			return (FALSE);
465 		if (!valid)
466 			break;
467 		if (!xdr_u_int(xdrs, &fileid) ||
468 		    !xdr_u_int(xdrs, &namlen))
469 			return (FALSE);
470 		if (DIRENT64_RECLEN(namlen) > size) {
471 			rddir->rddir_eof = FALSE;
472 			goto bufovflw;
473 		}
474 		if (!xdr_opaque(xdrs, dp->d_name, namlen)||
475 		    !xdr_u_int(xdrs, &offset))
476 			return (FALSE);
477 		dp->d_ino = fileid;
478 		dp->d_reclen = (ushort_t)DIRENT64_RECLEN(namlen);
479 		bzero(&dp->d_name[namlen],
480 		    DIRENT64_NAMELEN(dp->d_reclen) - namlen);
481 		dp->d_off = offset;
482 		size -= dp->d_reclen;
483 		/* LINTED pointer alignment */
484 		dp = nextdp(dp);
485 	}
486 	if (!xdr_bool(xdrs, &rddir->rddir_eof))
487 		return (FALSE);
488 bufovflw:
489 	rddir->rddir_size = (uint_t)((char *)dp - (char *)rddir->rddir_entries);
490 	rddir->rddir_offset = offset;
491 	return (TRUE);
492 }
493 
494 bool_t
495 xdr_autofs_rddirres(XDR *xdrs, autofs_rddirres *objp)
496 {
497 	if (!xdr_enum(xdrs, (enum_t *)&objp->rd_status))
498 		return (FALSE);
499 	if (objp->rd_status != AUTOFS_OK)
500 		return (TRUE);
501 	if (xdrs->x_op == XDR_ENCODE)
502 		return (xdr_autofs_putrddirres(xdrs,
503 		    (struct autofsrddir *)&objp->rd_rddir, objp->rd_bufsize));
504 	else if (xdrs->x_op == XDR_DECODE)
505 		return (xdr_autofs_getrddirres(xdrs,
506 		    (struct autofsrddir *)&objp->rd_rddir));
507 	return (FALSE);
508 }
509