static int parse_sec(char *sec, int *pseudoflavour) { int i, num_flavour = 0; for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) { if (num_flavour >= MAX_USER_FLAVOUR) { nfs_error(_("%s: maximum number of security flavors " "exceeded"), progname); return 0; } for (i = 0; i < flav_map_size; i++) { if (strcmp(sec, flav_map[i].flavour) == 0) { pseudoflavour[num_flavour++] = flav_map[i].fnum; break; } } if (i == flav_map_size) { nfs_error(_("%s: unknown security type %s\n"), progname, sec); return 0; } } if (!num_flavour) nfs_error(_("%s: no security flavors passed to sec= option"), progname); return num_flavour; }
void afsusrdir::nfs_symlink (svccb *sbp) { if (!chkaid (sbp)) // XXX - redundant (handled by afsroot) return; str name, contents; if (sbp->vers () == 2) { symlinkargs *argp = sbp->Xtmpl getarg<symlinkargs> (); name = argp->from.name; contents = argp->to; } else { symlink3args *argp = sbp->Xtmpl getarg<symlink3args> (); name = argp->where.name; contents = argp->symlink.symlink_data; } afsnode *e = afsdir::lookup (name, aid); if (e && e->type != NF3LNK) nfs_error (sbp, NFSERR_EXIST); if (mkulink (contents, name)) dirop_reply (sbp, afsdir::lookup (name, aid)); else nfs_error (sbp, NFSERR_ACCES); }
void afsusrroot::nfs_lookup (svccb *sbp, str name) { afsnode *e = lookup (name, aid); if (e) { if (int err = srvinfo::geterr (name)) nfs_error (sbp, err); else lookup_reply (sbp, e); return; } else if ((!sfs_parsepath (name) && (!namedprotrx.match (name) /*|| !nptab[namedprotrx[1]]*/)) || terminating) { nfs_error (sbp, ENOENT); return; } ref<delaypt> dpt = delaypt::alloc (); ref<setupstate> ss = New refcounted<setupstate> (name, dpt); link (dpt, name); if (ptr<aclnt> ch = agentc ()) ch->timedcall (agent_timeout, AGENTCB_REVOKED, &name, &ss->revres, wrap (mkref (this), &afsusrroot::revcb, ss)); else { ss->revdone = true; finish (ss, NFS_OK); } lookup_reply (sbp, afsdir::lookup (name, aid)); }
/** * nfs_present_sockaddr - convert sockaddr to string * @sap: pointer to socket address to convert * @salen: length of socket address * @buf: pointer to buffer to fill in * @buflen: length of buffer * * Convert the passed-in sockaddr-style address to presentation format. * The presentation format address is placed in @buf and is * '\0'-terminated. * * Returns 1 if successful; otherwise zero. * * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details * on presenting IPv6 addresses as text strings. */ int nfs_present_sockaddr(const struct sockaddr *sap, const socklen_t salen, char *buf, const size_t buflen) { #ifdef HAVE_GETNAMEINFO int result; result = getnameinfo(sap, salen, buf, buflen, NULL, 0, NI_NUMERICHOST); if (!result) return 1; nfs_error(_("%s: invalid server address: %s"), progname, gai_strerror(result)); return 0; #else /* HAVE_GETNAMEINFO */ char *addr; if (sap->sa_family == AF_INET) { addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr); if (addr && strlen(addr) < buflen) { strcpy(buf, addr); return 1; } } nfs_error(_("%s: invalid server address"), progname); return 0; #endif /* HAVE_GETNAMEINFO */ }
nfsreaddirres * nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) { static nfsreaddirres res; static nfsentry e_res[MAX_READDIR_ENTRIES]; am_node *mp; int retry; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "readdir:"); mp = fh_to_mp3(&argp->rda_fhandle, &retry, VLOOK_CREATE); if (mp == NULL) { if (retry < 0) { amd_stats.d_drops++; return 0; } res.rdr_status = nfs_error(retry); } else { if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); res.rdr_status = nfs_error((*mp->am_al->al_mnt->mf_ops->readdir) (mp, argp->rda_cookie, &res.rdr_u.rdr_reply_u, e_res, argp->rda_count)); mp->am_stats.s_readdir++; } return &res; }
static int nfsmnt_check_compat(const struct pmap *nfs_pmap, const struct pmap *mnt_pmap) { unsigned int max_nfs_vers = (nfs_mount_data_version >= 4) ? 3 : 2; unsigned int max_mnt_vers = (nfs_mount_data_version >= 4) ? 3 : 2; if (nfs_pmap->pm_vers == 4) { nfs_error(_("%s: Please use '-t nfs4' " "instead of '-o vers=4'"), progname); goto out_bad; } if (nfs_pmap->pm_vers) { if (nfs_pmap->pm_vers > max_nfs_vers || nfs_pmap->pm_vers < 2) { nfs_error(_("%s: NFS version %ld is not supported"), progname, nfs_pmap->pm_vers); goto out_bad; } } if (mnt_pmap->pm_vers > max_mnt_vers) { nfs_error(_("%s: NFS mount version %ld is not supported"), progname, mnt_pmap->pm_vers); goto out_bad; } return 1; out_bad: return 0; }
nfsdiropres * nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) { static nfsdiropres res; am_node *mp; int retry; uid_t uid; gid_t gid; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "lookup:"); /* finally, find the effective uid/gid from RPC request */ if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0) plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials"); xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid); xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid); mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_CREATE); if (mp == NULL) { if (retry < 0) { amd_stats.d_drops++; return 0; } res.dr_status = nfs_error(retry); } else { int error; am_node *ap; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, argp->da_name); ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, argp->da_name, &error, VLOOK_CREATE); if (ap && error < 0) ap = mp->am_al->al_mnt->mf_ops->mount_child(ap, &error); if (ap == 0) { if (error < 0) { amd_stats.d_drops++; return 0; } res.dr_status = nfs_error(error); } else { /* * XXX: EXPERIMENTAL! Delay unmount of what was looked up. This * should reduce the chance for race condition between unmounting an * entry synchronously, and re-mounting it asynchronously. */ if (ap->am_ttl < mp->am_ttl) ap->am_ttl = mp->am_ttl; mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle); res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr; res.dr_status = NFS_OK; } mp->am_stats.s_lookup++; /* reschedule_timeout_mp(); */ } return &res; }
nfsdiropres * nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp) { static nfsdiropres res; if (!fh_to_mp(&argp->ca_where.da_fhandle)) res.dr_status = nfs_error(ESTALE); else res.dr_status = nfs_error(EROFS); return &res; }
nfsattrstat * nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp) { static nfsattrstat res; if (!fh_to_mp(&argp->wra_fhandle)) res.ns_status = nfs_error(ESTALE); else res.ns_status = nfs_error(EROFS); return &res; }
nfsstat * nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp) { static nfsstat res; if (!fh_to_mp(&argp->sla_from.da_fhandle)) res = nfs_error(ESTALE); else res = nfs_error(EROFS); return &res; }
void afsroot::nfs_mkdir (svccb *sbp) { str name = sbp->vers () == 2 ? str (sbp->Xtmpl getarg<createargs> ()->where.name) : str (sbp->Xtmpl getarg<mkdir3args> ()->where.name); if (entries[name]) nfs_error (sbp, nfsstat (NFSERR_EXIST)); else if (usrinfo *u = usrtab[sbp2aid (sbp)]) u->root->nfs_mkdir (sbp); else nfs_error (sbp, nfsstat (NFSERR_ACCES)); }
void afsroot::nfs_symlink (svccb *sbp) { str name = sbp->vers () == 2 ? str (sbp->Xtmpl getarg<symlinkargs> ()->from.name) : str (sbp->Xtmpl getarg<symlink3args> ()->where.name); if (entries[name]) nfs_error (sbp, NFSERR_EXIST); else if (usrinfo *u = usrtab[sbp2aid (sbp)]) u->root->nfs_symlink (sbp); else nfs_error (sbp, NFSERR_ACCES); }
static int nfs_verify_lock_option(struct mount_options *options) { if (po_rightmost(options, nfs_lock_opttbl) == 0) return 1; if (!start_statd()) { nfs_error(_("%s: rpc.statd is not running but is " "required for remote locking."), progname); nfs_error(_("%s: Either use '-o nolock' to keep " "locks local, or start statd."), progname); return 0; } return 1; }
/** * nfsmount_string - Mount an NFS file system using C string options * @spec: C string specifying remote share to mount ("hostname:path") * @node: C string pathname of local mounted-on directory * @type: C string that represents file system type ("nfs" or "nfs4") * @flags: MS_ style mount flags * @extra_opts: pointer to C string containing fs-specific mount options * (input and output argument) * @fake: flag indicating whether to carry out the whole operation * @child: one if this is a mount daemon (bg) * * Returns a valid mount command exit code. */ int nfsmount_string(const char *spec, const char *node, const char *type, int flags, char **extra_opts, int fake, int child) { struct nfsmount_info mi = { .spec = spec, .node = node, .address = NULL, .type = type, .extra_opts = extra_opts, .flags = flags, .fake = fake, .child = child, .local_ip = NULL, }; int retval = EX_FAIL; mi.options = po_split(*extra_opts); if (mi.options) { retval = nfsmount_start(&mi); po_destroy(mi.options); } else nfs_error(_("%s: internal option parsing error"), progname); freeaddrinfo(mi.address); free(mi.hostname); free(mi.local_ip); return retval; }
void afsroot::nfs_remove (svccb *sbp) { str name = sbp->vers () == 2 ? str (sbp->Xtmpl getarg<diropargs> ()->name) : str (sbp->Xtmpl getarg<diropargs3> ()->name); if (srvinfo *si = srvinfo::lookup (name)) { si->unmount (0); nfs_error (sbp, nfsstat (EINPROGRESS)); } else if (afsdir *d = userdir (sbp)) d->nfs_remove (sbp); else nfs_error (sbp, NFSERR_ACCES); }
/* * Determine whether to append a 'mountaddr=' option. The option is needed if: * * 1. "mounthost=" was specified, or * 2. The address families for proto= and mountproto= are different. */ static int nfs_fix_mounthost_option(struct mount_options *options, const char *nfs_hostname) { union nfs_sockaddr address; struct sockaddr *sap = &address.sa; socklen_t salen = sizeof(address); sa_family_t nfs_family, mnt_family; char *mounthost; if (!nfs_nfs_proto_family(options, &nfs_family)) return 0; if (!nfs_mount_proto_family(options, &mnt_family)) return 0; mounthost = po_get(options, "mounthost"); if (mounthost == NULL) { if (nfs_family == mnt_family) return 1; mounthost = (char *)nfs_hostname; } if (!nfs_lookup(mounthost, mnt_family, sap, &salen)) { nfs_error(_("%s: unable to determine mount server's address"), progname); return 0; } return nfs_append_generic_address_option(sap, salen, "mountaddr", options); }
/* * Convert the passed-in sockaddr-style address to presentation * format, then append an option of the form "keyword=address". * * Returns 1 if the option was appended successfully; otherwise zero. */ static int nfs_append_generic_address_option(const struct sockaddr *sap, const socklen_t salen, const char *keyword, struct mount_options *options) { char address[NI_MAXHOST]; char new_option[512]; int len; if (!nfs_present_sockaddr(sap, salen, address, sizeof(address))) goto out_err; len = snprintf(new_option, sizeof(new_option), "%s=%s", keyword, address); if (len < 0 || (size_t)len >= sizeof(new_option)) goto out_err; if (po_append(options, new_option) != PO_SUCCEEDED) goto out_err; return 1; out_err: nfs_error(_("%s: failed to construct %s option"), progname, keyword); return 0; }
/* * Read /etc/mtab. If that fails, try /proc/mounts. * This produces a linked list. The list head mounttable is a dummy. * Return 0 on success. */ static void read_mounttable() { mntFILE *mfp; const char *fnam; struct mntentchn *mc = &mounttable; got_mtab = 1; mc->nxt = mc->prev = NULL; fnam = MOUNTED; mfp = nfs_setmntent (fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; fnam = PROC_MOUNTS; mfp = nfs_setmntent (fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { nfs_error(_("warning: can't open %s: %s"), MOUNTED, strerror (errsv)); return; } if (verbose) printf(_("%s: could not open %s; using %s instead\n"), progname, MOUNTED, PROC_MOUNTS); } read_mntentchn(mfp, fnam, mc); }
/* * Obtain a retry timeout value based on the value of the "retry=" option. * * Returns a time_t timeout timestamp, in seconds. */ static time_t nfs_parse_retry_option(struct mount_options *options, const time_t default_timeout) { time_t timeout_minutes; long tmp; timeout_minutes = default_timeout; switch (po_get_numeric(options, "retry", &tmp)) { case PO_NOT_FOUND: break; case PO_FOUND: if (tmp >= 0) { timeout_minutes = tmp; break; } /*FALLTHROUGH*/ case PO_BAD_VALUE: if (verbose) nfs_error(_("%s: invalid retry timeout was specified; " "using default timeout"), progname); break; } return time(NULL) + (timeout_minutes * 60); }
nfsreadlinkres * nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) { static nfsreadlinkres res; am_node *mp; int retry; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "readlink:"); mp = fh_to_mp3(argp, &retry, VLOOK_CREATE); if (mp == NULL) { readlink_retry: if (retry < 0) { amd_stats.d_drops++; return 0; } res.rlr_status = nfs_error(retry); } else { char *ln = do_readlink(mp, &retry); if (ln == 0) goto readlink_retry; res.rlr_status = NFS_OK; if (amuDebug(D_TRACE) && ln) plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); res.rlr_u.rlr_data_u = ln; mp->am_stats.s_readlink++; } return &res; }
int main(int argc, char *argv[]) { struct libmnt_context *cxt; int rc; mnt_init_debug(0); cxt = mnt_new_context(); if (!cxt) { nfs_error(_("Can't initilize libmount: %s"), strerror(errno)); rc = EX_FAIL; goto done; } progname = basename(argv[0]); nfs_mount_data_version = discover_nfs_mount_data_version(&string); if(strncmp(progname, "umount", 6) == 0) rc = umount_main(cxt, argc, argv); else rc = mount_main(cxt, argc, argv); done: mnt_free_context(cxt); return rc; }
static nfsstat * unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp) { static nfsstat res; int retry; am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE); if (mp == NULL) { if (retry < 0) { amd_stats.d_drops++; return 0; } res = nfs_error(retry); goto out; } if (mp->am_fattr.na_type != NFDIR) { res = nfs_error(ENOTDIR); goto out; } if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name); mp = mp->am_al->al_mnt->mf_ops->lookup_child(mp, argp->da_name, &retry, VLOOK_DELETE); if (mp == NULL) { /* * Ignore retries... */ if (retry < 0) retry = 0; /* * Usual NFS workaround... */ else if (retry == ENOENT) retry = 0; res = nfs_error(retry); } else { forcibly_timeout_mp(mp); res = NFS_OK; } out: return &res; }
void afsaidfile::nfs3_access (svccb *sbp) { const sfs_aid aid = sbp2aid (sbp); if (aid != owner) nfs_error (sbp, NFSERR_STALE); else afsnode::nfs3_access (sbp); }
/** * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address * @hostname: pointer to C string containing DNS hostname to resolve * @af_hint: hint to restrict resolution to one address family * @sap: pointer to buffer to fill with socket address * @len: IN: size of buffer to fill; OUT: size of socket address * * Returns 1 and places a socket address at @sap if successful; * otherwise zero. */ int nfs_name_to_address(const char *hostname, const sa_family_t af_hint, struct sockaddr *sap, socklen_t *salen) { struct addrinfo *gai_results; struct addrinfo gai_hint = { .ai_family = af_hint, .ai_flags = AI_ADDRCONFIG, }; socklen_t len = *salen; int error, ret = 0; if (af_hint == AF_INET6) gai_hint.ai_flags |= AI_V4MAPPED|AI_ALL; *salen = 0; error = getaddrinfo(hostname, NULL, &gai_hint, &gai_results); if (error) { nfs_error(_("%s: DNS resolution failed for %s: %s"), progname, hostname, (error == EAI_SYSTEM ? strerror(errno) : gai_strerror(error))); return ret; } switch (gai_results->ai_addr->sa_family) { case AF_INET: case AF_INET6: if (len >= gai_results->ai_addrlen) { *salen = gai_results->ai_addrlen; memcpy(sap, gai_results->ai_addr, *salen); ret = 1; } break; default: /* things are really broken if we get here, so warn */ nfs_error(_("%s: unrecognized DNS resolution results for %s"), progname, hostname); break; } freeaddrinfo(gai_results); return ret; }
nfsreadres * nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp) { static nfsreadres res; memset((char *) &res, 0, sizeof(res)); res.rr_status = nfs_error(EACCES); return &res; }
static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) { struct hostent *hp; addr->sin_family = AF_INET; if (inet_aton(hostname, &addr->sin_addr)) return 0; if ((hp = gethostbyname(hostname)) == NULL) { nfs_error(_("%s: can't get address for %s\n"), progname, hostname); return -1; } if (hp->h_length > sizeof(struct in_addr)) { nfs_error(_("%s: got bad hp->h_length"), progname); hp->h_length = sizeof(struct in_addr); } memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); return 0; }
bool afsusrdir::chkaid (svccb *sbp) { const sfs_aid rqaid = sbp2aid (sbp); if (rqaid != aid) { nfs_error (sbp, NFSERR_STALE); return false; } return true; }
void afsusrdir::nfs_mkdir (svccb *sbp) { str name = sbp->vers () == 2 ? str (sbp->Xtmpl getarg<createargs> ()->where.name) : str (sbp->Xtmpl getarg<mkdir3args> ()->where.name); if (entries[name]) { nfs_error (sbp, NFSERR_EXIST); return; } if (!nameok (name)) { nfs_error (sbp, nfsstat (NFSERR_ACCES)); return; } clrulink (name); ptr<afsnode> e = mkdir (name); dirop_reply (sbp, e); }
nfsstatfsres * nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) { static nfsstatfsres res; am_node *mp; int retry; mntent_t mnt; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "statfs:"); mp = fh_to_mp3(argp, &retry, VLOOK_CREATE); if (mp == NULL) { if (retry < 0) { amd_stats.d_drops++; return 0; } res.sfr_status = nfs_error(retry); } else { nfsstatfsokres *fp; if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); /* * just return faked up file system information */ fp = &res.sfr_u.sfr_reply_u; fp->sfrok_tsize = 1024; fp->sfrok_bsize = 1024; /* check if map is browsable and show_statfs_entries=yes */ if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) && mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) { mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts; if (amu_hasmntopt(&mnt, "browsable")) { count_map_entries(mp, &fp->sfrok_blocks, &fp->sfrok_bfree, &fp->sfrok_bavail); } } else { fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */ fp->sfrok_bfree = 0; fp->sfrok_bavail = 0; } res.sfr_status = NFS_OK; mp->am_stats.s_statfs++; } return &res; }
nfsstat * nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp) { static nfsstat res; if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle)) res = nfs_error(ESTALE); /* * If the kernel is doing clever things with referenced files * then let it pretend... */ else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4)) res = NFS_OK; /* * otherwise a failure */ else res = nfs_error(EROFS); return &res; }