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