xref: /netbsd-src/external/bsd/am-utils/dist/conf/autofs/autofs_solaris_v1.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: autofs_solaris_v1.c,v 1.1.1.1 2008/09/19 20:07:17 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1999-2003 Ion Badulescu
5  * Copyright (c) 1997-2007 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_v1.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 #ifdef HAVE_FS_AUTOFS
58 
59 /*
60  * MACROS:
61  */
62 #ifndef AUTOFS_NULL
63 # define AUTOFS_NULL	NULLPROC
64 #endif /* not AUTOFS_NULL */
65 
66 /*
67  * STRUCTURES:
68  */
69 
70 /*
71  * VARIABLES:
72  */
73 
74 /* forward declarations */
75 # ifndef HAVE_XDR_MNTREQUEST
76 bool_t xdr_mntrequest(XDR *xdrs, mntrequest *objp);
77 # endif /* not HAVE_XDR_MNTREQUEST */
78 # ifndef HAVE_XDR_MNTRES
79 bool_t xdr_mntres(XDR *xdrs, mntres *objp);
80 # endif /* not HAVE_XDR_MNTRES */
81 # ifndef HAVE_XDR_UMNTREQUEST
82 bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp);
83 # endif /* not HAVE_XDR_UMNTREQUEST */
84 # ifndef HAVE_XDR_UMNTRES
85 bool_t xdr_umntres(XDR *xdrs, umntres *objp);
86 # endif /* not HAVE_XDR_UMNTRES */
87 static int autofs_mount_1_req(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred, SVCXPRT *transp);
88 static int autofs_unmount_1_req(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred, SVCXPRT *transp);
89 
90 /****************************************************************************
91  *** VARIABLES                                                            ***
92  ****************************************************************************/
93 
94 /****************************************************************************
95  *** FUNCTIONS                                                            ***
96  ****************************************************************************/
97 
98 /*
99  * AUTOFS XDR FUNCTIONS:
100  */
101 
102 #ifndef HAVE_XDR_MNTREQUEST
103 bool_t
104 xdr_mntrequest(XDR *xdrs, mntrequest *objp)
105 {
106   if (amuDebug(D_XDRTRACE))
107     plog(XLOG_DEBUG, "xdr_mntrequest:");
108 
109   if (!xdr_string(xdrs, &objp->name, A_MAXNAME))
110     return (FALSE);
111 
112   if (!xdr_string(xdrs, &objp->map, A_MAXNAME))
113     return (FALSE);
114 
115   if (!xdr_string(xdrs, &objp->opts, A_MAXOPTS))
116     return (FALSE);
117 
118   if (!xdr_string(xdrs, &objp->path, A_MAXPATH))
119     return (FALSE);
120 
121   return (TRUE);
122 }
123 #endif /* not HAVE_XDR_MNTREQUEST */
124 
125 
126 #ifndef HAVE_XDR_MNTRES
127 bool_t
128 xdr_mntres(XDR *xdrs, mntres *objp)
129 {
130   if (amuDebug(D_XDRTRACE))
131     plog(XLOG_DEBUG, "xdr_mntres:");
132 
133   if (!xdr_int(xdrs, &objp->status))
134     return (FALSE);
135 
136   return (TRUE);
137 }
138 # endif /* not HAVE_XDR_MNTRES */
139 
140 
141 #ifndef HAVE_XDR_UMNTREQUEST
142 bool_t
143 xdr_umntrequest(XDR *xdrs, umntrequest *objp)
144 {
145   if (amuDebug(D_XDRTRACE))
146     plog(XLOG_DEBUG, "xdr_umntrequest:");
147 
148   if (!xdr_int(xdrs, (int *) &objp->isdirect))
149     return (FALSE);
150 
151   if (!xdr_u_int(xdrs, (u_int *) &objp->devid))
152     return (FALSE);
153 
154 #ifdef HAVE_UMNTREQUEST_RDEVID
155   if (!xdr_u_long(xdrs, &objp->rdevid))
156     return (FALSE);
157 #endif /* HAVE_UMNTREQUEST_RDEVID */
158 
159   if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest), (XDRPROC_T_TYPE) xdr_umntrequest))
160     return (FALSE);
161 
162   return (TRUE);
163 }
164 #endif /* not HAVE_XDR_UMNTREQUEST */
165 
166 
167 #ifndef HAVE_XDR_UMNTRES
168 bool_t
169 xdr_umntres(XDR *xdrs, umntres *objp)
170 {
171   if (amuDebug(D_XDRTRACE))
172     plog(XLOG_DEBUG, "xdr_mntres:");
173 
174   if (!xdr_int(xdrs, &objp->status))
175     return (FALSE);
176 
177   return (TRUE);
178 }
179 #endif /* not HAVE_XDR_UMNTRES */
180 
181 
182 /*
183  * AUTOFS RPC methods
184  */
185 
186 static int
187 autofs_mount_1_req(struct mntrequest *m,
188 		   struct mntres *res,
189 		   struct authunix_parms *cred,
190 		   SVCXPRT *transp)
191 {
192   int err = 0;
193   int isdirect = 0;
194   am_node *mp, *ap;
195   mntfs *mf;
196 
197   dlog("MOUNT REQUEST: name=%s map=%s opts=%s path=%s",
198        m->name, m->map, m->opts, m->path);
199 
200   /* find the effective uid/gid from RPC request */
201   xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid);
202   xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid);
203 
204   mp = find_ap(m->path);
205   if (!mp) {
206     plog(XLOG_ERROR, "map %s not found", m->path);
207     err = ENOENT;
208     goto out;
209   }
210 
211   mf = mp->am_mnt;
212   isdirect = (mf->mf_fsflags & FS_DIRECT) ? 1 : 0;
213   ap = mf->mf_ops->lookup_child(mp, m->name + isdirect, &err, VLOOK_CREATE);
214   if (ap && err < 0)
215     ap = mf->mf_ops->mount_child(ap, &err);
216   if (ap == NULL) {
217     if (err < 0) {
218       /* we're working on it */
219       amd_stats.d_drops++;
220       return 1;
221     }
222     err = ENOENT;
223     goto out;
224   }
225 
226 out:
227   if (err) {
228     if (isdirect) {
229       /* direct mount */
230       plog(XLOG_ERROR, "mount of %s failed", m->path);
231     } else {
232       /* indirect mount */
233       plog(XLOG_ERROR, "mount of %s/%s failed", m->path, m->name);
234     }
235   }
236 
237   dlog("MOUNT REPLY: status=%d (%s)", err, strerror(err));
238 
239   res->status = err;
240   return 0;
241 }
242 
243 
244 static int
245 autofs_unmount_1_req(struct umntrequest *ul,
246 		     struct umntres *res,
247 		     struct authunix_parms *cred,
248 		     SVCXPRT *transp)
249 {
250   int mapno, err;
251   am_node *mp = NULL;
252 
253   dlog("UNMOUNT REQUEST: dev=%lx rdev=%lx %s",
254        (u_long) ul->devid,
255        (u_long) ul->rdevid,
256        ul->isdirect ? "direct" : "indirect");
257 
258   /* by default, and if not found, succeed */
259   res->status = 0;
260 
261   for (mapno = 0; ; mapno++) {
262     mp = get_exported_ap(mapno);
263     if (!mp)
264       break;
265     if (mp->am_dev == ul->devid &&
266 	(ul->rdevid == 0 || mp->am_rdev == ul->rdevid))
267       break;
268   }
269 
270   if (mp) {
271     /* save RPC context */
272     if (!mp->am_transp && transp) {
273       mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
274       *(mp->am_transp) = *transp;
275     }
276 
277     mapno = mp->am_mapno;
278     err = unmount_mp(mp);
279 
280     if (err)
281       /* backgrounded, don't reply yet */
282       return 1;
283 
284     if (get_exported_ap(mapno))
285       /* unmounting failed, tell the kernel */
286       res->status = 1;
287   }
288 
289   dlog("UNMOUNT REPLY: status=%d", res->status);
290   return 0;
291 }
292 
293 
294 /****************************************************************************/
295 /* autofs program dispatcher */
296 static void
297 autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp)
298 {
299   union {
300     mntrequest autofs_mount_1_arg;
301     umntrequest autofs_umount_1_arg;
302   } argument;
303   union {
304     mntres mount_res;
305     umntres umount_res;
306   } result;
307   int ret;
308 
309   bool_t (*xdr_argument)();
310   bool_t (*xdr_result)();
311   int (*local)();
312 
313   current_transp = transp;
314 
315   switch (rqstp->rq_proc) {
316 
317   case AUTOFS_NULL:
318     svc_sendreply(transp,
319 		  (XDRPROC_T_TYPE) xdr_void,
320 		  (SVC_IN_ARG_TYPE) NULL);
321     return;
322 
323   case AUTOFS_MOUNT:
324     xdr_argument = xdr_mntrequest;
325     xdr_result = xdr_mntres;
326     local = autofs_mount_1_req;
327     break;
328 
329   case AUTOFS_UNMOUNT:
330     xdr_argument = xdr_umntrequest;
331     xdr_result = xdr_umntres;
332     local = autofs_unmount_1_req;
333     break;
334 
335   default:
336     svcerr_noproc(transp);
337     return;
338   }
339 
340   memset((char *) &argument, 0, sizeof(argument));
341   if (!svc_getargs(transp,
342 		   (XDRPROC_T_TYPE) xdr_argument,
343 		   (SVC_IN_ARG_TYPE) &argument)) {
344     plog(XLOG_ERROR,
345 	 "AUTOFS xdr decode failed for %d %d %d",
346 	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
347     svcerr_decode(transp);
348     return;
349   }
350 
351   memset((char *)&result, 0, sizeof(result));
352   ret = (*local) (&argument, &result, rqstp, transp);
353 
354   current_transp = NULL;
355 
356   /* send reply only if the RPC method returned 0 */
357   if (!ret) {
358     if (!svc_sendreply(transp,
359 		       (XDRPROC_T_TYPE) xdr_result,
360 		       (SVC_IN_ARG_TYPE) &result)) {
361       svcerr_systemerr(transp);
362     }
363   }
364 
365   if (!svc_freeargs(transp,
366 		    (XDRPROC_T_TYPE) xdr_argument,
367 		    (SVC_IN_ARG_TYPE) &argument)) {
368     plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_1");
369   }
370 }
371 
372 
373 int
374 autofs_get_fh(am_node *mp)
375 {
376   autofs_fh_t *fh;
377   char buf[MAXHOSTNAMELEN];
378   mntfs *mf = mp->am_mnt;
379   struct utsname utsname;
380 
381   plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path);
382   fh = ALLOC(autofs_fh_t);
383   memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */
384 
385   /*
386    * SET MOUNT ARGS
387    */
388   if (uname(&utsname) < 0) {
389     xstrlcpy(buf, "localhost.autofs", sizeof(buf));
390   } else {
391     xstrlcpy(buf, utsname.nodename, sizeof(buf));
392     xstrlcat(buf, ".autofs", sizeof(buf));
393   }
394 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
395   fh->addr.buf = strdup(buf);
396   fh->addr.len = fh->addr.maxlen = strlen(buf);
397 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
398 
399   fh->direct = (mf->mf_fsflags & FS_DIRECT) ? 1 : 0;
400   fh->rpc_to = 1;		/* XXX: arbitrary */
401   fh->mount_to = mp->am_timeo;
402   fh->path = mp->am_path;
403   fh->opts = "";		/* XXX: arbitrary */
404   fh->map = mp->am_path;	/* this is what we get back in readdir */
405 
406   mp->am_autofs_fh = fh;
407   return 0;
408 }
409 
410 
411 void
412 autofs_mounted(am_node *mp)
413 {
414   /* We don't want any timeouts on autofs nodes */
415   mp->am_autofs_ttl = NEVER;
416 }
417 
418 
419 void
420 autofs_release_fh(am_node *mp)
421 {
422   autofs_fh_t *fh = mp->am_autofs_fh;
423 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
424   XFREE(fh->addr.buf);
425 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
426   XFREE(fh);
427   mp->am_autofs_fh = NULL;
428 }
429 
430 
431 void
432 autofs_get_mp(am_node *mp)
433 {
434   /* nothing to do */
435 }
436 
437 
438 void
439 autofs_release_mp(am_node *mp)
440 {
441   /* nothing to do */
442 }
443 
444 
445 void
446 autofs_add_fdset(fd_set *readfds)
447 {
448   /* nothing to do */
449 }
450 
451 
452 int
453 autofs_handle_fdset(fd_set *readfds, int nsel)
454 {
455   /* nothing to do */
456   return nsel;
457 }
458 
459 
460 /*
461  * Create the autofs service for amd
462  */
463 int
464 create_autofs_service(void)
465 {
466   dlog("creating autofs service listener");
467   return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_1);
468 }
469 
470 
471 int
472 destroy_autofs_service(void)
473 {
474   dlog("destroying autofs service listener");
475   return unregister_autofs_service(AUTOFS_CONFTYPE);
476 }
477 
478 
479 int
480 autofs_mount_fs(am_node *mp, mntfs *mf)
481 {
482   int err = 0;
483   char *target, *target2 = NULL;
484   char *space_hack = autofs_strdup_space_hack(mp->am_path);
485   struct stat buf;
486 
487   if (mf->mf_flags & MFF_ON_AUTOFS) {
488     if ((err = mkdir(space_hack, 0555)))
489       goto out;
490   }
491 
492   /*
493    * For sublinks, we could end up here with an already mounted f/s.
494    * Don't do anything in that case.
495    */
496   if (!(mf->mf_flags & MFF_MOUNTED))
497     err = mf->mf_ops->mount_fs(mp, mf);
498 
499   if (err) {
500     if (mf->mf_flags & MFF_ON_AUTOFS)
501       rmdir(space_hack);
502     errno = err;
503     goto out;
504   }
505 
506   /*
507    * Autofs v1 doesn't support symlinks,
508    * so we ignore the CFM_AUTOFS_USE_LOFS flag
509    */
510   if (mf->mf_flags & MFF_ON_AUTOFS)
511     /* Nothing to do */
512     goto out;
513 
514   if (mp->am_link)
515     target = mp->am_link;
516   else
517     target = mf->mf_mount;
518 
519   if (target[0] != '/')
520     target2 = str3cat(NULL, mp->am_parent->am_path, "/", target);
521   else
522     target2 = strdup(target);
523 
524   plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2);
525   /*
526    * we need to stat() the destination, because the bind mount does not
527    * follow symlinks and/or allow for non-existent destinations.
528    *
529    * WARNING: we will deadlock if this function is called from the master
530    * amd process and it happens to trigger another auto mount. Therefore,
531    * this function should be called only from a child amd process, or
532    * at the very least it should not be called from the parent unless we
533    * know for sure that it won't cause a recursive mount. We refuse to
534    * cause the recursive mount anyway if called from the parent amd.
535    */
536   if (!foreground) {
537     if ((err = stat(target2, &buf)))
538       goto out;
539   }
540   if ((err = lstat(target2, &buf)))
541     goto out;
542 
543   if ((err = mkdir(space_hack, 0555)))
544     goto out;
545 
546   if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) {
547     errno = err;
548     goto out;
549   }
550 
551  out:
552   XFREE(space_hack);
553   if (target2)
554     XFREE(target2);
555 
556   if (err)
557     return errno;
558   return 0;
559 }
560 
561 
562 int
563 autofs_umount_fs(am_node *mp, mntfs *mf)
564 {
565   int err = 0;
566   char *space_hack = autofs_strdup_space_hack(mp->am_path);
567 
568   /*
569    * Autofs v1 doesn't support symlinks,
570    * so we ignore the CFM_AUTOFS_USE_LOFS flag
571    */
572   if (!(mf->mf_flags & MFF_ON_AUTOFS)) {
573     err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1);
574     if (err)
575       goto out;
576     rmdir(space_hack);
577   }
578 
579   /*
580    * Multiple sublinks could reference this f/s.
581    * Don't actually unmount it unless we're holding the last reference.
582    */
583   if (mf->mf_refc == 1) {
584     if ((err = mf->mf_ops->umount_fs(mp, mf)))
585       goto out;
586 
587     if (mf->mf_flags & MFF_ON_AUTOFS)
588       rmdir(space_hack);
589   }
590 
591  out:
592   XFREE(space_hack);
593   return err;
594 }
595 
596 
597 int
598 autofs_umount_succeeded(am_node *mp)
599 {
600   umntres res;
601   SVCXPRT *transp = mp->am_transp;
602 
603   if (transp) {
604     res.status = 0;
605 
606     if (!svc_sendreply(transp,
607 		       (XDRPROC_T_TYPE) xdr_umntres,
608 		       (SVC_IN_ARG_TYPE) &res))
609       svcerr_systemerr(transp);
610 
611     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
612     XFREE(transp);
613     mp->am_transp = NULL;
614   }
615 
616   plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path);
617   return 0;
618 }
619 
620 
621 int
622 autofs_umount_failed(am_node *mp)
623 {
624   umntres res;
625   SVCXPRT *transp = mp->am_transp;
626 
627   if (transp) {
628     res.status = 1;
629 
630     if (!svc_sendreply(transp,
631 		       (XDRPROC_T_TYPE) xdr_umntres,
632 		       (SVC_IN_ARG_TYPE) &res))
633       svcerr_systemerr(transp);
634 
635     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
636     XFREE(transp);
637     mp->am_transp = NULL;
638   }
639 
640   plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path);
641   return 0;
642 }
643 
644 
645 void
646 autofs_mount_succeeded(am_node *mp)
647 {
648   SVCXPRT *transp = mp->am_transp;
649   struct stat stb;
650   char *space_hack;
651 
652   if (transp) {
653     /* this was a mount request */
654     mntres res;
655     res.status = 0;
656 
657     if (!svc_sendreply(transp,
658 		       (XDRPROC_T_TYPE) xdr_mntres,
659 		       (SVC_IN_ARG_TYPE) &res))
660       svcerr_systemerr(transp);
661 
662     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
663     XFREE(transp);
664     mp->am_transp = NULL;
665   }
666 
667   space_hack = autofs_strdup_space_hack(mp->am_path);
668   if (!lstat(space_hack, &stb)) {
669     mp->am_dev = stb.st_dev;
670     mp->am_rdev = stb.st_rdev;
671   }
672   XFREE(space_hack);
673   /* don't expire the entries -- the kernel will do it for us */
674   mp->am_flags |= AMF_NOTIMEOUT;
675 
676   plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path);
677 }
678 
679 
680 void
681 autofs_mount_failed(am_node *mp)
682 {
683   SVCXPRT *transp = mp->am_transp;
684 
685   if (transp) {
686     /* this was a mount request */
687     mntres res;
688     res.status = ENOENT;
689 
690     if (!svc_sendreply(transp,
691 		       (XDRPROC_T_TYPE) xdr_mntres,
692 		       (SVC_IN_ARG_TYPE) &res))
693       svcerr_systemerr(transp);
694 
695     dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
696     XFREE(transp);
697     mp->am_transp = NULL;
698   }
699 
700   plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path);
701 }
702 
703 
704 void
705 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh)
706 {
707   xsnprintf(opts, l, "%sdirect",
708 	    fh->direct ? "" : "in");
709 }
710 
711 
712 int
713 autofs_compute_mount_flags(mntent_t *mntp)
714 {
715   /* Must use overlay mounts */
716   return MNT2_GEN_OPT_OVERLAY;
717 }
718 
719 
720 void autofs_timeout_mp(am_node *mp)
721 {
722   /* We don't want any timeouts on autofs nodes */
723   mp->am_autofs_ttl = NEVER;
724 }
725 #endif /* HAVE_FS_AUTOFS */
726