xref: /netbsd-src/external/bsd/am-utils/dist/conf/autofs/autofs_solaris_v2_v3.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: autofs_solaris_v2_v3.c,v 1.1.1.2 2009/03/20 20:26:51 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1999-2003 Ion Badulescu
5  * Copyright (c) 1997-2009 Erez Zadok
6  * Copyright (c) 1990 Jan-Simon Pendry
7  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
8  * Copyright (c) 1990 The Regents of the University of California.
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to Berkeley by
12  * Jan-Simon Pendry at Imperial College, London.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgment:
24  *      This product includes software developed by the University of
25  *      California, Berkeley and its contributors.
26  * 4. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *
43  * File: am-utils/conf/autofs/autofs_solaris_v2_v3.c
44  *
45  */
46 
47 /*
48  * Automounter filesystem
49  */
50 
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif /* HAVE_CONFIG_H */
54 #include <am_defs.h>
55 #include <amd.h>
56 
57 /*
58  * MACROS:
59  */
60 #ifndef AUTOFS_NULL
61 # define AUTOFS_NULL	NULLPROC
62 #endif /* not AUTOFS_NULL */
63 
64 /*
65  * STRUCTURES:
66  */
67 
68 struct amd_rddirres {
69   enum autofs_res rd_status;
70   u_long rd_bufsize;
71   nfsdirlist rd_dl;
72 };
73 typedef struct amd_rddirres amd_rddirres;
74 
75 /*
76  * VARIABLES:
77  */
78 
79 SVCXPRT *autofs_xprt = NULL;
80 
81 /* forward declarations */
82 bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp);
83 bool_t xdr_umntres(XDR *xdrs, umntres *objp);
84 bool_t xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp);
85 bool_t xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp);
86 bool_t xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp);
87 bool_t xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp);
88 static bool_t xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp);
89 
90 /*
91  * These exist only in the AutoFS V2 protocol.
92  */
93 #ifdef AUTOFS_POSTUNMOUNT
94 bool_t xdr_postumntreq(XDR *xdrs, postumntreq *objp);
95 bool_t xdr_postumntres(XDR *xdrs, postumntres *objp);
96 bool_t xdr_postmountreq(XDR *xdrs, postmountreq *objp);
97 bool_t xdr_postmountres(XDR *xdrs, postmountres *objp);
98 #endif /* AUTOFS_POSTUMOUNT */
99 
100 /*
101  * AUTOFS XDR FUNCTIONS:
102  */
103 
104 bool_t
105 xdr_autofs_stat(XDR *xdrs, autofs_stat *objp)
106 {
107   if (!xdr_enum(xdrs, (enum_t *)objp))
108     return (FALSE);
109   return (TRUE);
110 }
111 
112 
113 bool_t
114 xdr_autofs_action(XDR *xdrs, autofs_action *objp)
115 {
116   if (!xdr_enum(xdrs, (enum_t *)objp))
117     return (FALSE);
118   return (TRUE);
119 }
120 
121 
122 bool_t
123 xdr_linka(XDR *xdrs, linka *objp)
124 {
125   if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
126     return (FALSE);
127   if (!xdr_string(xdrs, &objp->link, AUTOFS_MAXPATHLEN))
128     return (FALSE);
129   return (TRUE);
130 }
131 
132 
133 bool_t
134 xdr_autofs_netbuf(XDR *xdrs, struct netbuf *objp)
135 {
136   bool_t dummy;
137 
138   if (!xdr_u_long(xdrs, (u_long *) &objp->maxlen))
139     return (FALSE);
140   dummy = xdr_bytes(xdrs, (char **)&(objp->buf),
141 		    (u_int *)&(objp->len), objp->maxlen);
142   return (dummy);
143 }
144 
145 
146 bool_t
147 xdr_autofs_args(XDR *xdrs, autofs_args *objp)
148 {
149   if (!xdr_autofs_netbuf(xdrs, &objp->addr))
150     return (FALSE);
151   if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
152     return (FALSE);
153   if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
154     return (FALSE);
155   if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
156     return (FALSE);
157   if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
158     return (FALSE);
159   if (!xdr_string(xdrs, &objp->key, AUTOFS_MAXCOMPONENTLEN))
160     return (FALSE);
161   if (!xdr_int(xdrs, &objp->mount_to))
162     return (FALSE);
163   if (!xdr_int(xdrs, &objp->rpc_to))
164     return (FALSE);
165   if (!xdr_int(xdrs, &objp->direct))
166     return (FALSE);
167   return (TRUE);
168 }
169 
170 
171 bool_t
172 xdr_mounta(XDR *xdrs, struct mounta *objp)
173 {
174   if (!xdr_string(xdrs, &objp->spec, AUTOFS_MAXPATHLEN))
175     return (FALSE);
176   if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
177     return (FALSE);
178   if (!xdr_int(xdrs, &objp->flags))
179     return (FALSE);
180   if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
181     return (FALSE);
182   if (!xdr_pointer(xdrs, (char **)&objp->dataptr, sizeof(autofs_args),
183 		   (XDRPROC_T_TYPE) xdr_autofs_args))
184     return (FALSE);
185   if (!xdr_int(xdrs, &objp->datalen))
186     return (FALSE);
187   return (TRUE);
188 }
189 
190 
191 bool_t
192 xdr_action_list_entry(XDR *xdrs, action_list_entry *objp)
193 {
194   if (!xdr_autofs_action(xdrs, &objp->action))
195     return (FALSE);
196   switch (objp->action) {
197   case AUTOFS_MOUNT_RQ:
198     if (!xdr_mounta(xdrs, &objp->action_list_entry_u.mounta))
199       return (FALSE);
200     break;
201   case AUTOFS_LINK_RQ:
202     if (!xdr_linka(xdrs, &objp->action_list_entry_u.linka))
203       return (FALSE);
204     break;
205   default:
206     break;
207   }
208   return (TRUE);
209 }
210 
211 
212 bool_t
213 xdr_action_list(XDR *xdrs, action_list *objp)
214 {
215   if (!xdr_action_list_entry(xdrs, &objp->action))
216     return (FALSE);
217   if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof(action_list),
218 		   (XDRPROC_T_TYPE) xdr_action_list))
219     return (FALSE);
220   return (TRUE);
221 }
222 
223 
224 bool_t
225 xdr_umntrequest(XDR *xdrs, umntrequest *objp)
226 {
227   if (amuDebug(D_XDRTRACE))
228     plog(XLOG_DEBUG, "xdr_umntrequest:");
229 
230   if (!xdr_bool_t(xdrs, &objp->isdirect))
231     return (FALSE);
232 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
233   if (!xdr_dev_t(xdrs, &objp->devid))
234     return (FALSE);
235   if (!xdr_dev_t(xdrs, &objp->rdevid))
236     return (FALSE);
237 #else  /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
238   if (!xdr_string(xdrs, &objp->mntresource, AUTOFS_MAXPATHLEN))
239     return (FALSE);
240   if (!xdr_string(xdrs, &objp->mntpnt, AUTOFS_MAXPATHLEN))
241     return (FALSE);
242   if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
243     return (FALSE);
244   if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN))
245     return (FALSE);
246 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
247   if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest),
248 		   (XDRPROC_T_TYPE) xdr_umntrequest))
249     return (FALSE);
250 
251   return (TRUE);
252 }
253 
254 
255 bool_t
256 xdr_umntres(XDR *xdrs, umntres *objp)
257 {
258   if (amuDebug(D_XDRTRACE))
259     plog(XLOG_DEBUG, "xdr_mntres:");
260 
261   if (!xdr_int(xdrs, &objp->status))
262     return (FALSE);
263   return (TRUE);
264 }
265 
266 
267 /*
268  * These exist only in the AutoFS V2 protocol.
269  */
270 #ifdef AUTOFS_POSTUNMOUNT
271 bool_t
272 xdr_postumntreq(XDR *xdrs, postumntreq *objp)
273 {
274   if (!xdr_dev_t(xdrs, &objp->devid))
275     return (FALSE);
276   if (!xdr_dev_t(xdrs, &objp->rdevid))
277     return (FALSE);
278   if (!xdr_pointer(xdrs, (char **)&objp->next,
279 		   sizeof(struct postumntreq),
280 		   (XDRPROC_T_TYPE) xdr_postumntreq))
281     return (FALSE);
282   return (TRUE);
283 }
284 
285 
286 bool_t
287 xdr_postumntres(XDR *xdrs, postumntres *objp)
288 {
289   if (!xdr_int(xdrs, &objp->status))
290     return (FALSE);
291   return (TRUE);
292 }
293 
294 
295 bool_t
296 xdr_postmountreq(XDR *xdrs, postmountreq *objp)
297 {
298   if (!xdr_string(xdrs, &objp->special, AUTOFS_MAXPATHLEN))
299     return (FALSE);
300   if (!xdr_string(xdrs, &objp->mountp, AUTOFS_MAXPATHLEN))
301     return (FALSE);
302   if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
303     return (FALSE);
304   if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN))
305     return (FALSE);
306   if (!xdr_dev_t(xdrs, &objp->devid))
307     return (FALSE);
308   return (TRUE);
309 }
310 
311 
312 bool_t
313 xdr_postmountres(XDR *xdrs, postmountres *objp)
314 {
315   if (!xdr_int(xdrs, &objp->status))
316     return (FALSE);
317   return (TRUE);
318 }
319 #endif /* AUTOFS_POSTUNMOUNT */
320 
321 
322 bool_t
323 xdr_autofs_res(XDR *xdrs, autofs_res *objp)
324 {
325   if (!xdr_enum(xdrs, (enum_t *)objp))
326     return (FALSE);
327   return (TRUE);
328 }
329 
330 
331 bool_t
332 xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp)
333 {
334   if (amuDebug(D_XDRTRACE))
335     plog(XLOG_DEBUG, "xdr_autofs_lookupargs:");
336 
337   if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
338     return (FALSE);
339   if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
340     return (FALSE);
341   if (!xdr_string(xdrs, &objp->name, AUTOFS_MAXCOMPONENTLEN))
342     return (FALSE);
343   if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
344     return (FALSE);
345   if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
346     return (FALSE);
347   if (!xdr_bool_t(xdrs, &objp->isdirect))
348     return (FALSE);
349   return (TRUE);
350 }
351 
352 
353 bool_t
354 xdr_mount_result_type(XDR *xdrs, mount_result_type *objp)
355 {
356   if (!xdr_autofs_stat(xdrs, &objp->status))
357     return (FALSE);
358   switch (objp->status) {
359   case AUTOFS_ACTION:
360     if (!xdr_pointer(xdrs,
361 		     (char **)&objp->mount_result_type_u.list,
362 		     sizeof(action_list), (XDRPROC_T_TYPE) xdr_action_list))
363       return (FALSE);
364     break;
365   case AUTOFS_DONE:
366     if (!xdr_int(xdrs, &objp->mount_result_type_u.error))
367       return (FALSE);
368     break;
369   }
370   return (TRUE);
371 }
372 
373 
374 bool_t
375 xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp)
376 {
377   if (amuDebug(D_XDRTRACE))
378     plog(XLOG_DEBUG, "xdr_mntres:");
379 
380   if (!xdr_mount_result_type(xdrs, &objp->mr_type))
381     return (FALSE);
382   if (!xdr_int(xdrs, &objp->mr_verbose))
383     return (FALSE);
384 
385   return (TRUE);
386 }
387 
388 
389 bool_t
390 xdr_lookup_result_type(XDR *xdrs, lookup_result_type *objp)
391 {
392   if (!xdr_autofs_action(xdrs, &objp->action))
393     return (FALSE);
394   switch (objp->action) {
395   case AUTOFS_LINK_RQ:
396     if (!xdr_linka(xdrs, &objp->lookup_result_type_u.lt_linka))
397       return (FALSE);
398     break;
399   default:
400     break;
401   }
402   return (TRUE);
403 }
404 
405 
406 bool_t
407 xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp)
408 {
409   if (!xdr_autofs_res(xdrs, &objp->lu_res))
410     return (FALSE);
411   if (!xdr_lookup_result_type(xdrs, &objp->lu_type))
412     return (FALSE);
413   if (!xdr_int(xdrs, &objp->lu_verbose))
414     return (FALSE);
415   return (TRUE);
416 }
417 
418 
419 bool_t
420 xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp)
421 {
422   if (!xdr_string(xdrs, &objp->rda_map, AUTOFS_MAXPATHLEN))
423     return (FALSE);
424   if (!xdr_u_int(xdrs, (u_int *) &objp->rda_offset))
425     return (FALSE);
426   if (!xdr_u_int(xdrs, (u_int *) &objp->rda_count))
427     return (FALSE);
428   return (TRUE);
429 }
430 
431 
432 /*
433  * ENCODE ONLY
434  *
435  * Solaris automountd uses struct autofsrddir to pass the results.
436  * We use the traditional nfsreaddirres and do the conversion ourselves.
437  */
438 static bool_t
439 xdr_amd_putrddirres(XDR *xdrs, nfsdirlist *dp, ulong reqsize)
440 {
441   nfsentry *ep;
442   char *name;
443   u_int namlen;
444   bool_t true = TRUE;
445   bool_t false = FALSE;
446   int entrysz;
447   int tofit;
448   int bufsize;
449   u_long ino, off;
450 
451   bufsize = 1 * BYTES_PER_XDR_UNIT;
452   for (ep = dp->dl_entries; ep; ep = ep->ne_nextentry) {
453     name = ep->ne_name;
454     namlen = strlen(name);
455     ino = (u_long) ep->ne_fileid;
456     off = (u_long) ep->ne_cookie + AUTOFS_DAEMONCOOKIE;
457     entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
458       roundup(namlen, BYTES_PER_XDR_UNIT);
459     tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
460     if (bufsize + tofit > reqsize) {
461       dp->dl_eof = FALSE;
462       break;
463     }
464     if (!xdr_bool(xdrs, &true) ||
465 	!xdr_u_long(xdrs, &ino) ||
466 	!xdr_bytes(xdrs, &name, &namlen, AUTOFS_MAXPATHLEN) ||
467 	!xdr_u_long(xdrs, &off)) {
468       return (FALSE);
469     }
470     bufsize += entrysz;
471   }
472   if (!xdr_bool(xdrs, &false)) {
473     return (FALSE);
474   }
475   if (!xdr_bool(xdrs, &dp->dl_eof)) {
476     return (FALSE);
477   }
478   return (TRUE);
479 }
480 
481 
482 static bool_t
483 xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp)
484 {
485   if (!xdr_enum(xdrs, (enum_t *)&objp->rd_status))
486     return (FALSE);
487   if (objp->rd_status != AUTOFS_OK)
488     return (TRUE);
489   return (xdr_amd_putrddirres(xdrs, &objp->rd_dl, objp->rd_bufsize));
490 }
491 
492 
493 /*
494  * AUTOFS RPC methods
495  */
496 
497 static int
498 autofs_lookup_2_req(autofs_lookupargs *m,
499 		    autofs_lookupres *res,
500 		    struct authunix_parms *cred,
501 		    SVCXPRT *transp)
502 {
503   int err;
504   am_node *mp, *new_mp;
505   mntfs *mf;
506 
507   dlog("LOOKUP REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d",
508        m->name, m->subdir, m->map, m->opts,
509        m->path, m->isdirect);
510 
511   /* find the effective uid/gid from RPC request */
512   xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid);
513   xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid);
514 
515   mp = find_ap(m->path);
516   if (!mp) {
517     plog(XLOG_ERROR, "map %s not found", m->path);
518     err = AUTOFS_NOENT;
519     goto out;
520   }
521 
522   mf = mp->am_mnt;
523   new_mp = mf->mf_ops->lookup_child(mp, m->name, &err, VLOOK_LOOKUP);
524   if (!new_mp) {
525     err = AUTOFS_NOENT;
526     goto out;
527   }
528 
529   if (err == 0) {
530     plog(XLOG_ERROR, "autofs requests to mount an already mounted node???");
531   } else {
532     free_map(new_mp);
533   }
534   err = AUTOFS_OK;
535   res->lu_type.action = AUTOFS_NONE;
536 
537  out:
538   res->lu_res = err;
539   res->lu_verbose = 1;
540 
541   dlog("LOOKUP REPLY: status=%d", res->lu_res);
542   return 0;
543 }
544 
545 
546 static void
547 autofs_lookup_2_free(autofs_lookupres *res)
548 {
549   struct linka link;
550 
551   if ((res->lu_res == AUTOFS_OK) &&
552       (res->lu_type.action == AUTOFS_LINK_RQ)) {
553     /*
554      * Free link information
555      */
556     link = res->lu_type.lookup_result_type_u.lt_linka;
557     if (link.dir)
558       XFREE(link.dir);
559     if (link.link)
560       XFREE(link.link);
561   }
562 }
563 
564 
565 static int
566 autofs_mount_2_req(autofs_lookupargs *m,
567 		   autofs_mountres *res,
568 		   struct authunix_parms *cred,
569 		   SVCXPRT *transp)
570 {
571   int err = AUTOFS_OK;
572   am_node *mp, *new_mp;
573   mntfs *mf;
574 
575   dlog("MOUNT REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d",
576        m->name, m->subdir, m->map, m->opts,
577        m->path, m->isdirect);
578 
579   /* find the effective uid/gid from RPC request */
580   xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid);
581   xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid);
582 
583   mp = find_ap(m->path);
584   if (!mp) {
585     plog(XLOG_ERROR, "map %s not found", m->path);
586     res->mr_type.status = AUTOFS_DONE;
587     res->mr_type.mount_result_type_u.error = AUTOFS_NOENT;
588     goto out;
589   }
590 
591   mf = mp->am_mnt;
592   new_mp = mf->mf_ops->lookup_child(mp, m->name + m->isdirect, &err, VLOOK_CREATE);
593   if (new_mp && err < 0) {
594     /* new_mp->am_transp = transp; */
595     new_mp = mf->mf_ops->mount_child(new_mp, &err);
596   }
597   if (new_mp == NULL) {
598     if (err < 0) {
599       /* we're working on it */
600       amd_stats.d_drops++;
601       return 1;
602     }
603     res->mr_type.status = AUTOFS_DONE;
604     res->mr_type.mount_result_type_u.error = AUTOFS_NOENT;
605     goto out;
606   }
607 
608   if (gopt.flags & CFM_AUTOFS_USE_LOFS ||
609       new_mp->am_mnt->mf_flags & MFF_ON_AUTOFS) {
610     res->mr_type.status = AUTOFS_DONE;
611     res->mr_type.mount_result_type_u.error = AUTOFS_OK;
612   } else {
613     struct action_list *list = malloc(sizeof(struct action_list));
614     char *target;
615     if (new_mp->am_link)
616       target = new_mp->am_link;
617     else
618       target = new_mp->am_mnt->mf_mount;
619     list->action.action = AUTOFS_LINK_RQ;
620     list->action.action_list_entry_u.linka.dir = strdup(new_mp->am_name);
621     list->action.action_list_entry_u.linka.link = strdup(target);
622     list->next = NULL;
623     res->mr_type.status = AUTOFS_ACTION;
624     res->mr_type.mount_result_type_u.list = list;
625   }
626 
627 out:
628   res->mr_verbose = 1;
629 
630   switch (res->mr_type.status) {
631   case AUTOFS_ACTION:
632     dlog("MOUNT REPLY: status=%d, AUTOFS_ACTION", err);
633     break;
634   case AUTOFS_DONE:
635     dlog("MOUNT REPLY: status=%d, AUTOFS_DONE", err);
636     break;
637   default:
638     dlog("MOUNT REPLY: status=%d, UNKNOWN(%d)", err, res->mr_type.status);
639   }
640 
641   if (err) {
642     if (m->isdirect) {
643       /* direct mount */
644       plog(XLOG_ERROR, "mount of %s failed", m->path);
645     } else {
646       /* indirect mount */
647       plog(XLOG_ERROR, "mount of %s/%s failed", m->path, m->name);
648     }
649   }
650   return 0;
651 }
652 
653 
654 static void
655 autofs_mount_2_free(struct autofs_mountres *res)
656 {
657   if (res->mr_type.status == AUTOFS_ACTION &&
658       res->mr_type.mount_result_type_u.list != NULL) {
659     autofs_action action;
660     dlog("freeing action list");
661     action = res->mr_type.mount_result_type_u.list->action.action;
662     if (action == AUTOFS_LINK_RQ) {
663       /*
664        * Free link information
665        */
666       struct linka *link;
667       link = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.linka);
668       if (link->dir)
669 	XFREE(link->dir);
670       if (link->link)
671 	XFREE(link->link);
672     } else if (action == AUTOFS_MOUNT_RQ) {
673       struct mounta *mnt;
674       mnt = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.mounta);
675       if (mnt->spec)
676 	XFREE(mnt->spec);
677       if (mnt->dir)
678 	XFREE(mnt->dir);
679       if (mnt->fstype)
680 	XFREE(mnt->fstype);
681       if (mnt->dataptr)
682 	XFREE(mnt->dataptr);
683 #ifdef HAVE_MOUNTA_OPTPTR
684       if (mnt->optptr)
685 	XFREE(mnt->optptr);
686 #endif /* HAVE_MOUNTA_OPTPTR */
687     }
688     XFREE(res->mr_type.mount_result_type_u.list);
689   }
690 }
691 
692 
693 static int
694 autofs_unmount_2_req(umntrequest *ul,
695 		     umntres *res,
696 		     struct authunix_parms *cred,
697 		     SVCXPRT *transp)
698 {
699   int mapno, err;
700   am_node *mp = NULL;
701 
702 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
703   dlog("UNMOUNT REQUEST: dev=%lx rdev=%lx %s",
704        (u_long) ul->devid,
705        (u_long) ul->rdevid,
706        ul->isdirect ? "direct" : "indirect");
707 #else  /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
708   dlog("UNMOUNT REQUEST: mntresource='%s' mntpnt='%s' fstype='%s' mntopts='%s' %s",
709        ul->mntresource,
710        ul->mntpnt,
711        ul->fstype,
712        ul->mntopts,
713        ul->isdirect ? "direct" : "indirect");
714 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
715 
716   /* by default, and if not found, succeed */
717   res->status = 0;
718 
719 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
720   for (mp = get_first_exported_ap(&mapno);
721        mp;
722        mp = get_next_exported_ap(&mapno)) {
723     if (mp->am_dev == ul->devid &&
724 	mp->am_rdev == ul->rdevid)
725       break;
726   }
727 #else  /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
728   mp = find_ap(ul->mntpnt);
729 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
730 
731   if (mp) {
732     /* save RPC context */
733     if (!mp->am_transp && transp) {
734       mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
735       *(mp->am_transp) = *transp;
736     }
737 
738     mapno = mp->am_mapno;
739     err = unmount_mp(mp);
740 
741     if (err)
742       /* backgrounded, don't reply yet */
743       return 1;
744 
745     if (get_exported_ap(mapno))
746       /* unmounting failed, tell the kernel */
747       res->status = 1;
748   }
749 
750   dlog("UNMOUNT REPLY: status=%d", res->status);
751   return 0;
752 }
753 
754 
755 /*
756  * These exist only in the AutoFS V2 protocol.
757  */
758 #ifdef AUTOFS_POSTUNMOUNT
759 /* XXX not implemented */
760 static int
761 autofs_postunmount_2_req(postumntreq *req,
762 			 postumntres *res,
763 			 struct authunix_parms *cred,
764 			 SVCXPRT *transp)
765 {
766   postumntreq *ul = req;
767 
768   dlog("POSTUNMOUNT REQUEST: dev=%lx rdev=%lx",
769        (u_long) ul->devid,
770        (u_long) ul->rdevid);
771 
772   /* succeed unconditionally */
773   res->status = 0;
774 
775   dlog("POSTUNMOUNT REPLY: status=%d", res->status);
776   return 0;
777 }
778 
779 
780 /* XXX not implemented */
781 static int
782 autofs_postmount_2_req(postmountreq *req,
783 		       postmountres *res,
784 		       struct authunix_parms *cred,
785 		       SVCXPRT *transp)
786 {
787   dlog("POSTMOUNT REQUEST: %s\tdev=%lx\tspecial=%s %s",
788        req->mountp, (u_long) req->devid, req->special, req->mntopts);
789 
790   /* succeed unconditionally */
791   res->status = 0;
792 
793   dlog("POSTMOUNT REPLY: status=%d", res->status);
794   return 0;
795 }
796 #endif /* AUTOFS_POSTUNMOUNT */
797 
798 
799 static int
800 autofs_readdir_2_req(struct autofs_rddirargs *req,
801 		     struct amd_rddirres *res,
802 		     struct authunix_parms *cred,
803 		     SVCXPRT *transp)
804 {
805   am_node *mp;
806   int err;
807   static nfsentry e_res[MAX_READDIR_ENTRIES];
808 
809   dlog("READDIR REQUEST: %s @ %d",
810        req->rda_map, (int) req->rda_offset);
811 
812   mp = find_ap(req->rda_map);
813   if (!mp) {
814     plog(XLOG_ERROR, "map %s not found", req->rda_map);
815     res->rd_status = AUTOFS_NOENT;
816     goto out;
817   }
818 
819   mp->am_stats.s_readdir++;
820   req->rda_offset -= AUTOFS_DAEMONCOOKIE;
821   err = mp->am_mnt->mf_ops->readdir(mp, (char *)&req->rda_offset,
822 				    &res->rd_dl, e_res, req->rda_count);
823   if (err) {
824     res->rd_status = AUTOFS_ECOMM;
825     goto out;
826   }
827 
828   res->rd_status = AUTOFS_OK;
829   res->rd_bufsize = req->rda_count;
830 
831 out:
832   dlog("READDIR REPLY: status=%d", res->rd_status);
833   return 0;
834 }
835 
836 
837 /****************************************************************************/
838 /* autofs program dispatcher */
839 static void
840 autofs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
841 {
842   union {
843     autofs_lookupargs autofs_mount_2_arg;
844     autofs_lookupargs autofs_lookup_2_arg;
845     umntrequest autofs_umount_2_arg;
846     autofs_rddirargs autofs_readdir_2_arg;
847 #ifdef AUTOFS_POSTUNMOUNT
848     postmountreq autofs_postmount_2_arg;
849     postumntreq autofs_postumnt_2_arg;
850 #endif /* AUTOFS_POSTUNMOUNT */
851   } argument;
852 
853   union {
854     autofs_mountres mount_res;
855     autofs_lookupres lookup_res;
856     umntres umount_res;
857     amd_rddirres readdir_res;
858 #ifdef AUTOFS_POSTUNMOUNT
859     postumntres postumnt_res;
860     postmountres postmnt_res;
861 #endif /* AUTOFS_POSTUNMOUNT */
862   } result;
863   int ret;
864 
865   bool_t (*xdr_argument)();
866   bool_t (*xdr_result)();
867   int (*local)();
868   void (*local_free)() = NULL;
869 
870   current_transp = transp;
871 
872   switch (rqstp->rq_proc) {
873 
874   case AUTOFS_NULL:
875     svc_sendreply(transp,
876 		  (XDRPROC_T_TYPE) xdr_void,
877 		  (SVC_IN_ARG_TYPE) NULL);
878     return;
879 
880   case AUTOFS_LOOKUP:
881     xdr_argument = xdr_autofs_lookupargs;
882     xdr_result = xdr_autofs_lookupres;
883     local = autofs_lookup_2_req;
884     local_free = autofs_lookup_2_free;
885     break;
886 
887   case AUTOFS_MOUNT:
888     xdr_argument = xdr_autofs_lookupargs;
889     xdr_result = xdr_autofs_mountres;
890     local = autofs_mount_2_req;
891     local_free = autofs_mount_2_free;
892     break;
893 
894   case AUTOFS_UNMOUNT:
895     xdr_argument = xdr_umntrequest;
896     xdr_result = xdr_umntres;
897     local = autofs_unmount_2_req;
898     break;
899 
900 /*
901  * These exist only in the AutoFS V2 protocol.
902  */
903 #ifdef AUTOFS_POSTUNMOUNT
904   case AUTOFS_POSTUNMOUNT:
905     xdr_argument = xdr_postumntreq;
906     xdr_result = xdr_postumntres;
907     local = autofs_postunmount_2_req;
908     break;
909 
910   case AUTOFS_POSTMOUNT:
911     xdr_argument = xdr_postmountreq;
912     xdr_result = xdr_postmountres;
913     local = autofs_postmount_2_req;
914     break;
915 #endif /* AUTOFS_POSTUNMOUNT */
916 
917   case AUTOFS_READDIR:
918     xdr_argument = xdr_autofs_rddirargs;
919     xdr_result = xdr_amd_rddirres;
920     local = autofs_readdir_2_req;
921     break;
922 
923   default:
924     svcerr_noproc(transp);
925     return;
926   }
927 
928   memset((char *) &argument, 0, sizeof(argument));
929   if (!svc_getargs(transp,
930 		   (XDRPROC_T_TYPE) xdr_argument,
931 		   (SVC_IN_ARG_TYPE) &argument)) {
932     plog(XLOG_ERROR, "AUTOFS xdr decode failed for %d %d %d",
933 	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
934     svcerr_decode(transp);
935     return;
936   }
937 
938   memset((char *)&result, 0, sizeof(result));
939   ret = (*local) (&argument, &result, rqstp->rq_clntcred, transp);
940 
941   current_transp = NULL;
942 
943   /* send reply only if the RPC method returned 0 */
944   if (!ret) {
945     if (!svc_sendreply(transp,
946 		       (XDRPROC_T_TYPE) xdr_result,
947 		       (SVC_IN_ARG_TYPE) &result)) {
948       svcerr_systemerr(transp);
949     }
950   }
951 
952   if (!svc_freeargs(transp,
953 		    (XDRPROC_T_TYPE) xdr_argument,
954 		    (SVC_IN_ARG_TYPE) &argument)) {
955     plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_2");
956   }
957 
958   if (local_free)
959     (*local_free)(&result);
960 }
961 
962 
963 int
964 autofs_get_fh(am_node *mp)
965 {
966   autofs_fh_t *fh;
967   char buf[MAXHOSTNAMELEN];
968   mntfs *mf = mp->am_mnt;
969   struct utsname utsname;
970 
971   plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path);
972   fh = ALLOC(autofs_fh_t);
973   memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */
974 
975   /*
976    * SET MOUNT ARGS
977    */
978   if (uname(&utsname) < 0) {
979     xstrlcpy(buf, "localhost.autofs", sizeof(buf));
980   } else {
981     xstrlcpy(buf, utsname.nodename, sizeof(buf));
982     xstrlcat(buf, ".autofs", sizeof(buf));
983   }
984 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
985   fh->addr.buf = strdup(buf);
986   fh->addr.len = fh->addr.maxlen = strlen(buf);
987 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
988 
989   fh->direct = ((mf->mf_ops->autofs_fs_flags & FS_DIRECT) == FS_DIRECT);
990   fh->rpc_to = 1;		/* XXX: arbitrary */
991   fh->mount_to = mp->am_timeo;
992   fh->path = mp->am_path;
993   fh->opts = "";		/* XXX: arbitrary */
994   fh->map = mp->am_path;	/* this is what we get back in readdir */
995   fh->subdir = "";
996   if (fh->direct)
997     fh->key = mp->am_name;
998   else
999     fh->key = "";
1000 
1001   mp->am_autofs_fh = fh;
1002   return 0;
1003 }
1004 
1005 
1006 void
1007 autofs_mounted(am_node *mp)
1008 {
1009   /* We don't want any timeouts on autofs nodes */
1010   mp->am_autofs_ttl = NEVER;
1011 }
1012 
1013 
1014 void
1015 autofs_release_fh(am_node *mp)
1016 {
1017   autofs_fh_t *fh = mp->am_autofs_fh;
1018 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
1019   XFREE(fh->addr.buf);
1020 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
1021   XFREE(fh);
1022   mp->am_autofs_fh = NULL;
1023 }
1024 
1025 
1026 void
1027 autofs_get_mp(am_node *mp)
1028 {
1029   /* nothing to do */
1030 }
1031 
1032 
1033 void
1034 autofs_release_mp(am_node *mp)
1035 {
1036   /* nothing to do */
1037 }
1038 
1039 
1040 void
1041 autofs_add_fdset(fd_set *readfds)
1042 {
1043   /* nothing to do */
1044 }
1045 
1046 
1047 int
1048 autofs_handle_fdset(fd_set *readfds, int nsel)
1049 {
1050   /* nothing to do */
1051   return nsel;
1052 }
1053 
1054 
1055 /*
1056  * Create the autofs service for amd
1057  */
1058 int
1059 create_autofs_service(void)
1060 {
1061   dlog("creating autofs service listener");
1062   return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_2);
1063 }
1064 
1065 
1066 int
1067 destroy_autofs_service(void)
1068 {
1069   dlog("destroying autofs service listener");
1070   return unregister_autofs_service(AUTOFS_CONFTYPE);
1071 }
1072 
1073 
1074 int
1075 autofs_mount_fs(am_node *mp, mntfs *mf)
1076 {
1077   int err = 0;
1078   char *target, *target2 = NULL;
1079   struct stat buf;
1080 
1081   /*
1082    * For sublinks, we could end up here with an already mounted f/s.
1083    * Don't do anything in that case.
1084    */
1085   if (!(mf->mf_flags & MFF_MOUNTED))
1086     err = mf->mf_ops->mount_fs(mp, mf);
1087 
1088   if (err || mf->mf_flags & MFF_ON_AUTOFS)
1089     /* Nothing else to do */
1090     return err;
1091 
1092   if (!(gopt.flags & CFM_AUTOFS_USE_LOFS))
1093     /* Symlinks will be requested in autofs_mount_succeeded */
1094     return 0;
1095 
1096   if (mp->am_link)
1097     target = mp->am_link;
1098   else
1099     target = mf->mf_mount;
1100 
1101   if (target[0] != '/')
1102     target2 = str3cat(NULL, mp->am_parent->am_path, "/", target);
1103   else
1104     target2 = strdup(target);
1105 
1106   plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2);
1107 
1108   /*
1109    * we need to stat() the destination, because the bind mount does not
1110    * follow symlinks and/or allow for non-existent destinations.
1111    * we fall back to symlinks if there are problems.
1112    *
1113    * we need to temporarily change pgrp, otherwise our stat() won't
1114    * trigger whatever cascading mounts are needed.
1115    *
1116    * WARNING: we will deadlock if this function is called from the master
1117    * amd process and it happens to trigger another auto mount. Therefore,
1118    * this function should be called only from a child amd process, or
1119    * at the very least it should not be called from the parent unless we
1120    * know for sure that it won't cause a recursive mount. We refuse to
1121    * cause the recursive mount anyway if called from the parent amd.
1122    */
1123   if (!foreground) {
1124     if ((err = stat(target2, &buf)))
1125       goto out;
1126   }
1127   if ((err = lstat(target2, &buf)))
1128     goto out;
1129 
1130   if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) {
1131     errno = err;
1132     goto out;
1133   }
1134 
1135  out:
1136   if (target2)
1137     XFREE(target2);
1138 
1139   if (err)
1140     return errno;
1141   return 0;
1142 }
1143 
1144 
1145 int
1146 autofs_umount_fs(am_node *mp, mntfs *mf)
1147 {
1148   int err = 0;
1149   if (!(mf->mf_flags & MFF_ON_AUTOFS) &&
1150       gopt.flags & CFM_AUTOFS_USE_LOFS) {
1151     err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1);
1152     if (err)
1153       return err;
1154   }
1155 
1156   /*
1157    * Multiple sublinks could reference this f/s.
1158    * Don't actually unmount it unless we're holding the last reference.
1159    */
1160   if (mf->mf_refc == 1)
1161     err = mf->mf_ops->umount_fs(mp, mf);
1162   return err;
1163 }
1164 
1165 
1166 int
1167 autofs_umount_succeeded(am_node *mp)
1168 {
1169   umntres res;
1170   SVCXPRT *transp = mp->am_transp;
1171 
1172   if (transp) {
1173     res.status = 0;
1174 
1175     if (!svc_sendreply(transp,
1176 		       (XDRPROC_T_TYPE) xdr_umntres,
1177 		       (SVC_IN_ARG_TYPE) &res))
1178       svcerr_systemerr(transp);
1179 
1180     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
1181     XFREE(transp);
1182     mp->am_transp = NULL;
1183   }
1184 
1185   plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path);
1186   return 0;
1187 }
1188 
1189 
1190 int
1191 autofs_umount_failed(am_node *mp)
1192 {
1193   umntres res;
1194   SVCXPRT *transp = mp->am_transp;
1195 
1196   if (transp) {
1197     res.status = 1;
1198 
1199     if (!svc_sendreply(transp,
1200 		       (XDRPROC_T_TYPE) xdr_umntres,
1201 		       (SVC_IN_ARG_TYPE) &res))
1202       svcerr_systemerr(transp);
1203 
1204     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
1205     XFREE(transp);
1206     mp->am_transp = NULL;
1207   }
1208 
1209   plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path);
1210   return 0;
1211 }
1212 
1213 
1214 void
1215 autofs_mount_succeeded(am_node *mp)
1216 {
1217   SVCXPRT *transp = mp->am_transp;
1218   struct stat stb;
1219 
1220   /*
1221    * Store dev and rdev -- but not for symlinks
1222    */
1223   if (gopt.flags & CFM_AUTOFS_USE_LOFS ||
1224       mp->am_mnt->mf_flags & MFF_ON_AUTOFS) {
1225     if (!lstat(mp->am_path, &stb)) {
1226       mp->am_dev = stb.st_dev;
1227       mp->am_rdev = stb.st_rdev;
1228     }
1229     /* don't expire the entries -- the kernel will do it for us */
1230     mp->am_flags |= AMF_NOTIMEOUT;
1231   }
1232 
1233   if (transp) {
1234     autofs_mountres res;
1235     res.mr_type.status = AUTOFS_DONE;
1236     res.mr_type.mount_result_type_u.error = AUTOFS_OK;
1237     res.mr_verbose = 1;
1238 
1239     if (!svc_sendreply(transp,
1240 		       (XDRPROC_T_TYPE) xdr_autofs_mountres,
1241 		       (SVC_IN_ARG_TYPE) &res))
1242       svcerr_systemerr(transp);
1243 
1244     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
1245     XFREE(transp);
1246     mp->am_transp = NULL;
1247   }
1248 
1249   plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path);
1250 }
1251 
1252 
1253 void
1254 autofs_mount_failed(am_node *mp)
1255 {
1256   SVCXPRT *transp = mp->am_transp;
1257 
1258   if (transp) {
1259     autofs_mountres res;
1260     res.mr_type.status = AUTOFS_DONE;
1261     res.mr_type.mount_result_type_u.error = AUTOFS_NOENT;
1262     res.mr_verbose = 1;
1263 
1264     if (!svc_sendreply(transp,
1265 		       (XDRPROC_T_TYPE) xdr_autofs_mountres,
1266 		       (SVC_IN_ARG_TYPE) &res))
1267       svcerr_systemerr(transp);
1268 
1269     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
1270     XFREE(transp);
1271     mp->am_transp = NULL;
1272   }
1273 
1274   plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path);
1275 }
1276 
1277 
1278 void
1279 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh)
1280 {
1281   xsnprintf(opts, l, "%sdirect",
1282 	    fh->direct ? "" : "in");
1283 }
1284 
1285 
1286 int
1287 autofs_compute_mount_flags(mntent_t *mntp)
1288 {
1289   /* Must use overlay mounts */
1290   return MNT2_GEN_OPT_OVERLAY;
1291 }
1292 
1293 
1294 void autofs_timeout_mp(am_node *mp)
1295 {
1296   /* We don't want any timeouts on autofs nodes */
1297   mp->am_autofs_ttl = NEVER;
1298 }
1299