autofs_solaris_v2_v3.c revision 1.1.1.2
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
68struct amd_rddirres {
69  enum autofs_res rd_status;
70  u_long rd_bufsize;
71  nfsdirlist rd_dl;
72};
73typedef struct amd_rddirres amd_rddirres;
74
75/*
76 * VARIABLES:
77 */
78
79SVCXPRT *autofs_xprt = NULL;
80
81/* forward declarations */
82bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp);
83bool_t xdr_umntres(XDR *xdrs, umntres *objp);
84bool_t xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp);
85bool_t xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp);
86bool_t xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp);
87bool_t xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp);
88static 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
94bool_t xdr_postumntreq(XDR *xdrs, postumntreq *objp);
95bool_t xdr_postumntres(XDR *xdrs, postumntres *objp);
96bool_t xdr_postmountreq(XDR *xdrs, postmountreq *objp);
97bool_t xdr_postmountres(XDR *xdrs, postmountres *objp);
98#endif /* AUTOFS_POSTUMOUNT */
99
100/*
101 * AUTOFS XDR FUNCTIONS:
102 */
103
104bool_t
105xdr_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
113bool_t
114xdr_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
122bool_t
123xdr_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
133bool_t
134xdr_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
146bool_t
147xdr_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
171bool_t
172xdr_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
191bool_t
192xdr_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
212bool_t
213xdr_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
224bool_t
225xdr_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
255bool_t
256xdr_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
271bool_t
272xdr_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
286bool_t
287xdr_postumntres(XDR *xdrs, postumntres *objp)
288{
289  if (!xdr_int(xdrs, &objp->status))
290    return (FALSE);
291  return (TRUE);
292}
293
294
295bool_t
296xdr_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
312bool_t
313xdr_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
322bool_t
323xdr_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
331bool_t
332xdr_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
353bool_t
354xdr_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
374bool_t
375xdr_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
389bool_t
390xdr_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
406bool_t
407xdr_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
419bool_t
420xdr_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 */
438static bool_t
439xdr_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
482static bool_t
483xdr_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
497static int
498autofs_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
546static void
547autofs_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
565static int
566autofs_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
627out:
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
654static void
655autofs_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
693static int
694autofs_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 */
760static int
761autofs_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 */
781static int
782autofs_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
799static int
800autofs_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
831out:
832  dlog("READDIR REPLY: status=%d", res->rd_status);
833  return 0;
834}
835
836
837/****************************************************************************/
838/* autofs program dispatcher */
839static void
840autofs_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
963int
964autofs_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
1006void
1007autofs_mounted(am_node *mp)
1008{
1009  /* We don't want any timeouts on autofs nodes */
1010  mp->am_autofs_ttl = NEVER;
1011}
1012
1013
1014void
1015autofs_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
1026void
1027autofs_get_mp(am_node *mp)
1028{
1029  /* nothing to do */
1030}
1031
1032
1033void
1034autofs_release_mp(am_node *mp)
1035{
1036  /* nothing to do */
1037}
1038
1039
1040void
1041autofs_add_fdset(fd_set *readfds)
1042{
1043  /* nothing to do */
1044}
1045
1046
1047int
1048autofs_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 */
1058int
1059create_autofs_service(void)
1060{
1061  dlog("creating autofs service listener");
1062  return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_2);
1063}
1064
1065
1066int
1067destroy_autofs_service(void)
1068{
1069  dlog("destroying autofs service listener");
1070  return unregister_autofs_service(AUTOFS_CONFTYPE);
1071}
1072
1073
1074int
1075autofs_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
1145int
1146autofs_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
1166int
1167autofs_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
1190int
1191autofs_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
1214void
1215autofs_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
1253void
1254autofs_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
1278void
1279autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh)
1280{
1281  xsnprintf(opts, l, "%sdirect",
1282	    fh->direct ? "" : "in");
1283}
1284
1285
1286int
1287autofs_compute_mount_flags(mntent_t *mntp)
1288{
1289  /* Must use overlay mounts */
1290  return MNT2_GEN_OPT_OVERLAY;
1291}
1292
1293
1294void 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