152112Smckusick /* 252112Smckusick * Copyright (c) 1992 The Regents of the University of California. 352112Smckusick * All rights reserved. 452112Smckusick * 552112Smckusick * This code is derived from software contributed to Berkeley by 652112Smckusick * Rick Macklem at The University of Guelph. 752112Smckusick * 852112Smckusick * %sccs.include.redist.c% 952112Smckusick */ 1052112Smckusick 1152112Smckusick #ifndef lint 1252112Smckusick char copyright[] = 1352112Smckusick "@(#) Copyright (c) 1992 The Regents of the University of California.\n\ 1452112Smckusick All rights reserved.\n"; 1552112Smckusick #endif /* not lint */ 1652112Smckusick 1752112Smckusick #ifndef lint 18*53128Storek static char sccsid[] = "@(#)mount_nfs.c 5.4 (Berkeley) 04/03/92"; 1952112Smckusick #endif /* not lint */ 2052112Smckusick 2152112Smckusick #include <stdio.h> 2252112Smckusick #include <signal.h> 2352112Smckusick #include <strings.h> 2452112Smckusick #include <sys/syslog.h> 2552112Smckusick #include <sys/param.h> 2652112Smckusick #include <sys/file.h> 2752112Smckusick #include <sys/errno.h> 2852112Smckusick #include <sys/ucred.h> 2952112Smckusick #include <sys/mount.h> 3052112Smckusick #include <sys/socket.h> 3152112Smckusick #include <sys/socketvar.h> 3252112Smckusick #include <netdb.h> 3352112Smckusick #include <rpc/rpc.h> 3452112Smckusick #include <rpc/pmap_clnt.h> 3552112Smckusick #include <rpc/pmap_prot.h> 3652112Smckusick #ifdef ISO 3752112Smckusick #include <netiso/iso.h> 3852112Smckusick #endif 3952112Smckusick #ifdef KERBEROS 4052112Smckusick #include <kerberosIV/krb.h> 4152112Smckusick #endif 4252112Smckusick #include <nfs/rpcv2.h> 4352112Smckusick #include <nfs/nfsv2.h> 4452112Smckusick #include <nfs/nfs.h> 4552112Smckusick #include <nfs/nqnfs.h> 4652112Smckusick 4752112Smckusick int xdr_dir(), xdr_fh(); 4852112Smckusick struct nfs_args nfsdefargs = { 4952112Smckusick (struct sockaddr *)0, 5052112Smckusick sizeof (struct sockaddr_in), 5152112Smckusick SOCK_DGRAM, 5252112Smckusick 0, 5352112Smckusick (nfsv2fh_t *)0, 5452112Smckusick 0, 5552112Smckusick NFS_WSIZE, 5652112Smckusick NFS_RSIZE, 5752112Smckusick NFS_TIMEO, 5852112Smckusick NFS_RETRANS, 5952112Smckusick NFS_MAXGRPS, 6052112Smckusick NFS_DEFRAHEAD, 6152112Smckusick NQ_DEFLEASE, 6252112Smckusick NQ_DEADTHRESH, 6352112Smckusick (char *)0, 6452112Smckusick }; 6552112Smckusick 6652112Smckusick struct nfhret { 6752112Smckusick u_long stat; 6852112Smckusick nfsv2fh_t nfh; 6952112Smckusick }; 7052112Smckusick #define DEF_RETRY 10000 7152112Smckusick #define BGRND 1 7252112Smckusick #define ISBGRND 2 7352112Smckusick int retrycnt = DEF_RETRY; 7452112Smckusick int opflags = 0; 7552112Smckusick extern int errno; 7652112Smckusick 7752112Smckusick #ifdef ISO 7852112Smckusick struct iso_addr *iso_addr(); 7952112Smckusick #endif 8052112Smckusick 8152112Smckusick #ifdef KERBEROS 8252112Smckusick char inst[INST_SZ]; 8352112Smckusick char realm[REALM_SZ]; 8452112Smckusick KTEXT_ST kt; 8552112Smckusick #endif 8652112Smckusick 8752112Smckusick main(argc, argv, arge) 8852112Smckusick int argc; 8952112Smckusick char **argv; 9052112Smckusick char **arge; 9152112Smckusick { 9252112Smckusick struct nfs_args nfsargs; 9352112Smckusick register int c; 9452112Smckusick register struct nfs_args *nfsargsp = &nfsargs; 9552112Smckusick struct nfsd_cargs ncd; 9652112Smckusick int num, flags = 0, match = 1, i, nfssvc_flag; 9752112Smckusick char *spec, *name; 9852112Smckusick uid_t last_ruid = -1; 9952112Smckusick extern int optind; 10052112Smckusick extern char *optarg; 10152112Smckusick 10252112Smckusick #ifdef KERBEROS 10352112Smckusick strcpy(realm, KRB_REALM); 10452112Smckusick #endif 10552112Smckusick nfsargs = nfsdefargs; 10652112Smckusick retrycnt = DEF_RETRY; 10752112Smckusick if (argc <= 1) 10852112Smckusick Usage(argc, argv); 10952989Smckusick while ((c = getopt(argc, argv, "bsiTpMlqdckPF:R:r:w:t:x:g:a:L:D:Km:")) 11052112Smckusick != EOF) 11152112Smckusick switch (c) { 11252112Smckusick case 'b': 11352112Smckusick opflags |= BGRND; 11452112Smckusick break; 11552112Smckusick case 's': 11652112Smckusick nfsargsp->flags |= NFSMNT_SOFT; 11752112Smckusick break; 11852112Smckusick case 'i': 11952112Smckusick nfsargsp->flags |= NFSMNT_INT; 12052112Smckusick break; 12152112Smckusick case 'T': 12252112Smckusick nfsargsp->sotype = SOCK_STREAM; 12352112Smckusick break; 12452112Smckusick #ifdef ISO 12552112Smckusick case 'p': 12652112Smckusick nfsargsp->sotype = SOCK_SEQPACKET; 12752112Smckusick break; 12852112Smckusick #endif 12952112Smckusick case 'M': 13052112Smckusick nfsargsp->flags |= NFSMNT_MYWRITE; 13152112Smckusick break; 13252112Smckusick case 'l': 13352112Smckusick nfsargsp->flags |= NFSMNT_RDIRALOOK; 13452112Smckusick break; 13552112Smckusick case 'q': 13652112Smckusick nfsargsp->flags |= NFSMNT_NQNFS; 13752112Smckusick break; 13852112Smckusick case 'd': 13952112Smckusick nfsargsp->flags |= NFSMNT_DUMBTIMR; 14052112Smckusick break; 14152112Smckusick case 'c': 14252112Smckusick nfsargsp->flags |= NFSMNT_NOCONN; 14352112Smckusick break; 14452112Smckusick case 'k': 14552112Smckusick nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 14652112Smckusick break; 14752989Smckusick case 'P': 14852989Smckusick nfsargsp->flags |= NFSMNT_RESVPORT; 14952989Smckusick break; 15052112Smckusick case 'F': 15152112Smckusick if ((num = atoi(optarg)) != 0) 15252112Smckusick flags = num; 15352112Smckusick break; 15452112Smckusick case 'R': 15552112Smckusick if ((num = atoi(optarg)) > 0) 15652112Smckusick retrycnt = num; 15752112Smckusick break; 15852112Smckusick case 'r': 15952112Smckusick if ((num = atoi(optarg)) > 0) { 16052112Smckusick nfsargsp->rsize = num; 16152112Smckusick nfsargsp->flags |= NFSMNT_RSIZE; 16252112Smckusick } 16352112Smckusick break; 16452112Smckusick case 'w': 16552112Smckusick if ((num = atoi(optarg)) > 0) { 16652112Smckusick nfsargsp->wsize = num; 16752112Smckusick nfsargsp->flags |= NFSMNT_WSIZE; 16852112Smckusick } 16952112Smckusick break; 17052112Smckusick case 't': 17152112Smckusick if ((num = atoi(optarg)) > 0) { 17252112Smckusick nfsargsp->timeo = num; 17352112Smckusick nfsargsp->flags |= NFSMNT_TIMEO; 17452112Smckusick } 17552112Smckusick break; 17652112Smckusick case 'x': 17752112Smckusick if ((num = atoi(optarg)) > 0) { 17852112Smckusick nfsargsp->retrans = num; 17952112Smckusick nfsargsp->flags |= NFSMNT_RETRANS; 18052112Smckusick } 18152112Smckusick break; 18252112Smckusick case 'g': 18352112Smckusick if ((num = atoi(optarg)) > 0) { 18452991Smckusick set_rpc_maxgrouplist(num); 18552112Smckusick nfsargsp->maxgrouplist = num; 18652112Smckusick nfsargsp->flags |= NFSMNT_MAXGRPS; 18752112Smckusick } 18852112Smckusick break; 18952112Smckusick case 'a': 19052112Smckusick if ((num = atoi(optarg)) >= 0) { 19152112Smckusick nfsargsp->readahead = num; 19252112Smckusick nfsargsp->flags |= NFSMNT_READAHEAD; 19352112Smckusick } 19452112Smckusick break; 19552112Smckusick case 'L': 19652112Smckusick if ((num = atoi(optarg)) >= 2) { 19752112Smckusick nfsargsp->leaseterm = num; 19852112Smckusick nfsargsp->flags |= NFSMNT_LEASETERM; 19952112Smckusick } 20052112Smckusick break; 20152112Smckusick case 'D': 20252112Smckusick if ((num = atoi(optarg)) > 0) { 20352112Smckusick nfsargsp->deadthresh = num; 20452112Smckusick nfsargsp->flags |= NFSMNT_DEADTHRESH; 20552112Smckusick } 20652112Smckusick break; 20752112Smckusick #ifdef KERBEROS 20852112Smckusick case 'K': 20952112Smckusick nfsargsp->flags |= NFSMNT_KERB; 21052112Smckusick break; 21152112Smckusick case 'm': 21252112Smckusick strncpy(realm, optarg, REALM_SZ - 1); 21352112Smckusick realm[REALM_SZ - 1] = '\0'; 21452112Smckusick break; 21552112Smckusick #endif /* KERBEROS */ 21652112Smckusick default: 21752112Smckusick Usage(argc, argv); 21852112Smckusick }; 21952112Smckusick if ((argc - optind) == 2) { 22052112Smckusick spec = argv[optind]; 22152112Smckusick name = argv[optind + 1]; 22252112Smckusick } else 22352112Smckusick Usage(argc, argv); 22452112Smckusick if (getnfsargs(spec, nfsargsp)) { 22552112Smckusick if (mount(MOUNT_NFS, name, flags, nfsargsp)) 22652112Smckusick exit(1); 22752112Smckusick if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 22852112Smckusick if ((opflags & ISBGRND) == 0) { 22952112Smckusick if (i = fork()) { 23052112Smckusick if (i == -1) { 23152112Smckusick perror("nqnfs"); 23252112Smckusick exit(1); 23352112Smckusick } 234*53128Storek exit(0); 23552112Smckusick } 23652112Smckusick (void) setsid(); 23752112Smckusick (void) close(0); 23852112Smckusick (void) close(1); 23952112Smckusick (void) close(2); 24052112Smckusick (void) chdir("/"); 24152112Smckusick } 24252112Smckusick openlog("mount_nfs:", LOG_PID, LOG_DAEMON); 24352112Smckusick nfssvc_flag = NFSSVC_MNTD; 24452112Smckusick ncd.ncd_dirp = name; 24552112Smckusick while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 24652112Smckusick if (errno == ENEEDAUTH) { 24752112Smckusick syslog(LOG_ERR, "in eacces"); 24852112Smckusick nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH | 24952112Smckusick NFSSVC_AUTHINFAIL; 25052112Smckusick #ifdef KERBEROS 25152112Smckusick syslog(LOG_ERR,"Callin krb uid=%d inst=%s realm=%s",ncd.ncd_authuid,inst,realm); 25252112Smckusick /* 25352112Smckusick * Set up as ncd_authuid for the kerberos call. 25452112Smckusick * Must set ruid to ncd_authuid and reset the 25552112Smckusick * ticket name iff ncd_authuid is not the same 25652112Smckusick * as last time, so that the right ticket file 25752112Smckusick * is found. 25852112Smckusick */ 25952112Smckusick if (ncd.ncd_authuid != last_ruid) { 26052112Smckusick krb_set_tkt_string(""); 26152112Smckusick last_ruid = ncd.ncd_authuid; 26252112Smckusick } 26352112Smckusick setreuid(ncd.ncd_authuid, 0); 26452112Smckusick if (krb_mk_req(&kt, "rcmd", inst, realm, 0) == 26552112Smckusick KSUCCESS && 26652112Smckusick kt.length <= (RPCAUTH_MAXSIZ - 2*NFSX_UNSIGNED)) { 26752112Smckusick syslog(LOG_ERR,"Got it\n"); 26852112Smckusick ncd.ncd_authtype = RPCAUTH_NQNFS; 26952112Smckusick ncd.ncd_authlen = kt.length; 27052112Smckusick ncd.ncd_authstr = (char *)kt.dat; 27152112Smckusick nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 27252112Smckusick } 27352112Smckusick setreuid(0, 0); 27452112Smckusick syslog(LOG_ERR,"ktlen=%d\n", kt.length); 27552112Smckusick #endif /* KERBEROS */ 27652112Smckusick } else 27752112Smckusick syslog(LOG_ERR, "nfssvc err %m"); 27852112Smckusick } 27952112Smckusick } 280*53128Storek exit(0); 28152112Smckusick } else 28252112Smckusick exit(1); 28352112Smckusick } 28452112Smckusick 28552112Smckusick getnfsargs(spec, nfsargsp) 28652112Smckusick char *spec; 28752112Smckusick struct nfs_args *nfsargsp; 28852112Smckusick { 28952112Smckusick register CLIENT *clp; 29052112Smckusick struct hostent *hp; 29152112Smckusick static struct sockaddr_in saddr; 29252112Smckusick #ifdef ISO 29352112Smckusick static struct sockaddr_iso isoaddr; 29452112Smckusick struct iso_addr *isop; 29552112Smckusick #endif 29652112Smckusick struct timeval pertry, try; 29752112Smckusick enum clnt_stat clnt_stat; 29852112Smckusick int so = RPC_ANYSOCK, isoflag = 0, i; 29952112Smckusick char *hostp, *delimp, *cp; 30052112Smckusick u_short tport; 30152112Smckusick static struct nfhret nfhret; 30252112Smckusick static char nam[MNAMELEN + 1]; 30352112Smckusick 30452112Smckusick strncpy(nam, spec, MNAMELEN); 30552112Smckusick nam[MNAMELEN] = '\0'; 30652112Smckusick if ((delimp = index(spec, '@')) != NULL) { 30752112Smckusick hostp = delimp + 1; 30852112Smckusick } else if ((delimp = index(spec, ':')) != NULL) { 30952112Smckusick hostp = spec; 31052112Smckusick spec = delimp + 1; 31152112Smckusick } else { 31252112Smckusick fprintf(stderr, 31352112Smckusick "No <host>:<dirpath> or <dirpath>@<host> spec\n"); 31452112Smckusick return (0); 31552112Smckusick } 31652112Smckusick *delimp = '\0'; 31752112Smckusick /* 31852112Smckusick * DUMB!! Until the mount protocol works on iso transport, we must 31952112Smckusick * supply both an iso and an inet address for the host. 32052112Smckusick */ 32152112Smckusick #ifdef ISO 32252112Smckusick if (!strncmp(hostp, "iso=", 4)) { 32352112Smckusick u_short isoport; 32452112Smckusick 32552112Smckusick hostp += 4; 32652112Smckusick isoflag++; 32752112Smckusick if ((delimp = index(hostp, '+')) == NULL) { 32852112Smckusick fprintf(stderr, "No iso+inet address\n"); 32952112Smckusick return (0); 33052112Smckusick } 33152112Smckusick *delimp = '\0'; 33252112Smckusick if ((isop = iso_addr(hostp)) == NULL) { 33352112Smckusick fprintf(stderr, "Bad iso address\n"); 33452112Smckusick return (0); 33552112Smckusick } 33652112Smckusick bzero((caddr_t)&isoaddr, sizeof (isoaddr)); 33752112Smckusick bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr, 33852112Smckusick sizeof (struct iso_addr)); 33952112Smckusick isoaddr.siso_len = sizeof (isoaddr); 34052112Smckusick isoaddr.siso_family = AF_ISO; 34152112Smckusick isoaddr.siso_tlen = 2; 34252112Smckusick isoport = htons(NFS_PORT); 34352112Smckusick bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen); 34452112Smckusick hostp = delimp + 1; 34552112Smckusick } 34652112Smckusick #endif /* ISO */ 34752112Smckusick 34852112Smckusick /* 34952112Smckusick * Handle an internet host address and reverse resolve it if 35052112Smckusick * doing Kerberos. 35152112Smckusick */ 35252112Smckusick if (isdigit(*hostp)) { 35352112Smckusick if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) { 35452112Smckusick fprintf(stderr, "Bad net addr %s\n", hostp); 35552112Smckusick return (0); 35652112Smckusick } 35752112Smckusick if ((nfsargsp->flags & NFSMNT_KERB) && 35852112Smckusick (hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, 35952112Smckusick sizeof (u_long), AF_INET)) == (struct hostent *)0) { 36052112Smckusick fprintf(stderr, "Can't reverse resolve net addr\n"); 36152112Smckusick return (0); 36252112Smckusick } 36352112Smckusick } else if ((hp = gethostbyname(hostp)) == NULL) { 36452112Smckusick fprintf(stderr, "Can't get net id for host\n"); 36552112Smckusick return (0); 36652112Smckusick } 36752112Smckusick #ifdef KERBEROS 36852112Smckusick if (nfsargsp->flags & NFSMNT_KERB) { 36952112Smckusick strncpy(inst, hp->h_name, INST_SZ); 37052112Smckusick inst[INST_SZ - 1] = '\0'; 37152112Smckusick if (cp = index(inst, '.')) 37252112Smckusick *cp = '\0'; 37352112Smckusick } 37452112Smckusick #endif /* KERBEROS */ 37552112Smckusick 37652112Smckusick bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 37752112Smckusick nfhret.stat = EACCES; /* Mark not yet successful */ 37852112Smckusick while (retrycnt > 0) { 37952112Smckusick saddr.sin_family = AF_INET; 38052112Smckusick saddr.sin_port = htons(PMAPPORT); 38152112Smckusick if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 38252112Smckusick NFS_VER2, IPPROTO_UDP)) == 0) { 38352112Smckusick if ((opflags & ISBGRND) == 0) 38452112Smckusick clnt_pcreateerror("NFS Portmap"); 38552112Smckusick } else { 38652112Smckusick saddr.sin_port = 0; 38752112Smckusick pertry.tv_sec = 10; 38852112Smckusick pertry.tv_usec = 0; 38952112Smckusick if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 39052112Smckusick RPCMNT_VER1, pertry, &so)) == NULL) { 39152112Smckusick if ((opflags & ISBGRND) == 0) 39252112Smckusick clnt_pcreateerror("Cannot MNT PRC"); 39352112Smckusick } else { 39452112Smckusick clp->cl_auth = authunix_create_default(); 39552112Smckusick try.tv_sec = 10; 39652112Smckusick try.tv_usec = 0; 39752112Smckusick clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 39852112Smckusick xdr_dir, spec, xdr_fh, &nfhret, try); 39952112Smckusick if (clnt_stat != RPC_SUCCESS) { 40052112Smckusick if ((opflags & ISBGRND) == 0) 40152112Smckusick clnt_perror(clp, "Bad MNT RPC"); 40252112Smckusick } else { 40352112Smckusick auth_destroy(clp->cl_auth); 40452112Smckusick clnt_destroy(clp); 40552112Smckusick retrycnt = 0; 40652112Smckusick } 40752112Smckusick } 40852112Smckusick } 40952112Smckusick if (--retrycnt > 0) { 41052112Smckusick if (opflags & BGRND) { 41152112Smckusick opflags &= ~BGRND; 41252112Smckusick if (i = fork()) { 41352112Smckusick if (i == -1) { 41452112Smckusick perror("nqnfs"); 41552112Smckusick exit(1); 41652112Smckusick } 417*53128Storek exit(0); 41852112Smckusick } 41952112Smckusick (void) setsid(); 42052112Smckusick (void) close(0); 42152112Smckusick (void) close(1); 42252112Smckusick (void) close(2); 42352112Smckusick (void) chdir("/"); 42452112Smckusick opflags |= ISBGRND; 42552112Smckusick } 42652112Smckusick sleep(60); 42752112Smckusick } 42852112Smckusick } 42952112Smckusick if (nfhret.stat) { 43052112Smckusick if (opflags & ISBGRND) 43152112Smckusick exit(1); 43252112Smckusick fprintf(stderr, "Can't access %s: ", spec); 43352112Smckusick errno = nfhret.stat; 43452112Smckusick perror(NULL); 43552112Smckusick return (0); 43652112Smckusick } 43752112Smckusick saddr.sin_port = htons(tport); 43852112Smckusick #ifdef ISO 43952112Smckusick if (isoflag) { 44052112Smckusick nfsargsp->addr = (struct sockaddr *) &isoaddr; 44152112Smckusick nfsargsp->addrlen = sizeof (isoaddr); 44252112Smckusick } else 44352112Smckusick #endif /* ISO */ 44452112Smckusick { 44552112Smckusick nfsargsp->addr = (struct sockaddr *) &saddr; 44652112Smckusick nfsargsp->addrlen = sizeof (saddr); 44752112Smckusick } 44852112Smckusick nfsargsp->fh = &nfhret.nfh; 44952112Smckusick nfsargsp->hostname = nam; 45052112Smckusick return (1); 45152112Smckusick } 45252112Smckusick 45352112Smckusick /* 45452112Smckusick * xdr routines for mount rpc's 45552112Smckusick */ 45652112Smckusick xdr_dir(xdrsp, dirp) 45752112Smckusick XDR *xdrsp; 45852112Smckusick char *dirp; 45952112Smckusick { 46052112Smckusick return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 46152112Smckusick } 46252112Smckusick 46352112Smckusick xdr_fh(xdrsp, np) 46452112Smckusick XDR *xdrsp; 46552112Smckusick struct nfhret *np; 46652112Smckusick { 46752112Smckusick if (!xdr_u_long(xdrsp, &(np->stat))) 46852112Smckusick return (0); 46952112Smckusick if (np->stat) 47052112Smckusick return (1); 47152112Smckusick return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 47252112Smckusick } 47352112Smckusick 47452112Smckusick Usage(argc, argv) 47552112Smckusick int argc; 47652112Smckusick char *argv[]; 47752112Smckusick { 47852112Smckusick register int i; 47952112Smckusick 48052112Smckusick for (i = 0; i < argc; i++) 48152112Smckusick fprintf(stderr, "%s ", argv[i]); 48252112Smckusick fprintf(stderr, "\nBad mount_nfs arg\n"); 48352112Smckusick exit(1); 48452112Smckusick } 485