+/*
+ * get the list of supported security flavors
+ *
+ * How we get them depends on what args we are given:
+ *
+ * FH? Name? Action
+ * ----- ----- ------
+ * YES YES Use the fh and name provided
+ * YES NO 4.1-only just use the fh provided
+ * NO YES Use the node's (or root) fh and the name provided
+ * NO NO Use the node's parent and the node's name (4.1 will just use node's fh)
+ */
+int
+nfs4_secinfo_rpc(struct nfsmount *nmp, struct nfsreq_secinfo_args *siap, kauth_cred_t cred, uint32_t *sec, int *seccountp)
+{
+ int error = 0, status, nfsvers, numops, namelen, fhsize;
+ vnode_t dvp = NULLVP;
+ nfsnode_t np, dnp;
+ u_char *fhp;
+ const char *vname = NULL, *name;
+ uint64_t xid;
+ struct nfsm_chain nmreq, nmrep;
+
+ *seccountp = 0;
+ if (!nmp)
+ return (ENXIO);
+ nfsvers = nmp->nm_vers;
+ np = siap->rsia_np;
+
+ nfsm_chain_null(&nmreq);
+ nfsm_chain_null(&nmrep);
+
+ fhp = siap->rsia_fh;
+ fhsize = fhp ? siap->rsia_fhsize : 0;
+ name = siap->rsia_name;
+ namelen = name ? siap->rsia_namelen : 0;
+ if (name && !namelen)
+ namelen = strlen(name);
+ if (!fhp && name) {
+ if (!np) /* use PUTROOTFH */
+ goto gotargs;
+ fhp = np->n_fhp;
+ fhsize = np->n_fhsize;
+ }
+ if (fhp && name)
+ goto gotargs;
+
+ if (!np)
+ return (EIO);
+ nfs_node_lock_force(np);
+ if ((vnode_vtype(NFSTOV(np)) != VDIR) && np->n_sillyrename) {
+ /*
+ * The node's been sillyrenamed, so we need to use
+ * the sillyrename directory/name to do the open.
+ */
+ struct nfs_sillyrename *nsp = np->n_sillyrename;
+ dnp = nsp->nsr_dnp;
+ dvp = NFSTOV(dnp);
+ if ((error = vnode_get(dvp))) {
+ nfs_node_unlock(np);
+ goto nfsmout;
+ }
+ fhp = dnp->n_fhp;
+ fhsize = dnp->n_fhsize;
+ name = nsp->nsr_name;
+ namelen = nsp->nsr_namlen;
+ } else {
+ /*
+ * [sigh] We can't trust VFS to get the parent right for named
+ * attribute nodes. (It likes to reparent the nodes after we've
+ * created them.) Luckily we can probably get the right parent
+ * from the n_parent we have stashed away.
+ */
+ if ((np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) &&
+ (((dvp = np->n_parent)) && (error = vnode_get(dvp))))
+ dvp = NULL;
+ if (!dvp)
+ dvp = vnode_getparent(NFSTOV(np));
+ vname = vnode_getname(NFSTOV(np));
+ if (!dvp || !vname) {
+ if (!error)
+ error = EIO;
+ nfs_node_unlock(np);
+ goto nfsmout;
+ }
+ dnp = VTONFS(dvp);
+ fhp = dnp->n_fhp;
+ fhsize = dnp->n_fhsize;
+ name = vname;
+ namelen = strnlen(vname, MAXPATHLEN);
+ }
+ nfs_node_unlock(np);
+
+gotargs:
+ // PUT(ROOT)FH + SECINFO
+ numops = 2;
+ nfsm_chain_build_alloc_init(error, &nmreq,
+ 4 * NFSX_UNSIGNED + NFSX_FH(nfsvers) + nfsm_rndup(namelen));
+ nfsm_chain_add_compound_header(error, &nmreq, "secinfo", numops);
+ numops--;
+ if (fhp) {
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
+ nfsm_chain_add_fh(error, &nmreq, nfsvers, fhp, fhsize);
+ } else {
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTROOTFH);
+ }
+ numops--;
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_SECINFO);
+ nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
+ nfsm_chain_build_done(error, &nmreq);
+ nfsm_assert(error, (numops == 0), EPROTO);
+ nfsmout_if(error);
+ error = nfs_request2(np, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
+ current_thread(), cred, NULL, 0, &nmrep, &xid, &status);
+ nfsm_chain_skip_tag(error, &nmrep);
+ nfsm_chain_get_32(error, &nmrep, numops);
+ nfsm_chain_op_check(error, &nmrep, fhp ? NFS_OP_PUTFH : NFS_OP_PUTROOTFH);
+ nfsm_chain_op_check(error, &nmrep, NFS_OP_SECINFO);
+ nfsmout_if(error);
+ error = nfsm_chain_get_secinfo(&nmrep, sec, seccountp);
+nfsmout:
+ nfsm_chain_cleanup(&nmreq);
+ nfsm_chain_cleanup(&nmrep);
+ if (vname)
+ vnode_putname(vname);
+ if (dvp != NULLVP)
+ vnode_put(dvp);
+ return (error);
+}
+
+/*
+ * Parse an NFSv4 SECINFO array to an array of pseudo flavors.
+ * (Note: also works for MOUNTv3 security arrays.)
+ */
+int
+nfsm_chain_get_secinfo(struct nfsm_chain *nmc, uint32_t *sec, int *seccountp)
+{
+ int error = 0, secmax, seccount, srvcount;
+ uint32_t flavor, val;
+ u_char oid[12];
+
+ seccount = srvcount = 0;
+ secmax = *seccountp;
+ *seccountp = 0;
+
+ nfsm_chain_get_32(error, nmc, srvcount);
+ while (!error && (srvcount > 0) && (seccount < secmax)) {
+ nfsm_chain_get_32(error, nmc, flavor);
+ nfsmout_if(error);
+ switch (flavor) {
+ case RPCAUTH_NONE:
+ case RPCAUTH_SYS:
+ case RPCAUTH_KRB5:
+ case RPCAUTH_KRB5I:
+ case RPCAUTH_KRB5P:
+ sec[seccount++] = flavor;
+ break;
+ case RPCSEC_GSS:
+ /* we only recognize KRB5, KRB5I, KRB5P */
+ nfsm_chain_get_32(error, nmc, val); /* OID length */
+ nfsmout_if(error);
+ if (val != sizeof(krb5_mech)) {
+ nfsm_chain_adv(error, nmc, val);
+ nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
+ break;
+ }
+ nfsm_chain_get_opaque(error, nmc, val, oid); /* OID bytes */
+ nfsmout_if(error);
+ if (bcmp(oid, krb5_mech, sizeof(krb5_mech))) {
+ nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
+ break;
+ }
+ nfsm_chain_get_32(error, nmc, val); /* QOP */
+ nfsm_chain_get_32(error, nmc, val); /* SERVICE */
+ nfsmout_if(error);
+ switch (val) {
+ case RPCSEC_GSS_SVC_NONE:
+ sec[seccount++] = RPCAUTH_KRB5;
+ break;
+ case RPCSEC_GSS_SVC_INTEGRITY:
+ sec[seccount++] = RPCAUTH_KRB5I;
+ break;
+ case RPCSEC_GSS_SVC_PRIVACY:
+ sec[seccount++] = RPCAUTH_KRB5P;
+ break;
+ }
+ break;
+ }
+ srvcount--;
+ }
+nfsmout:
+ if (!error)
+ *seccountp = seccount;
+ return (error);
+}
+
+
+/*
+ * Fetch the FS_LOCATIONS attribute for the node found at directory/name.
+ */
+int
+nfs4_get_fs_locations(
+ struct nfsmount *nmp,
+ nfsnode_t dnp,
+ u_char *fhp,
+ int fhsize,
+ const char *name,
+ vfs_context_t ctx,
+ struct nfs_fs_locations *nfslsp)
+{
+ int error = 0, numops, status;
+ uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
+ struct nfsreq rq, *req = &rq;
+ struct nfsreq_secinfo_args si;
+ struct nfsm_chain nmreq, nmrep;
+ uint64_t xid;
+
+ if (!fhp && dnp) {
+ fhp = dnp->n_fhp;
+ fhsize = dnp->n_fhsize;
+ }
+ if (!fhp)
+ return (EINVAL);
+
+ nfsm_chain_null(&nmreq);
+ nfsm_chain_null(&nmrep);
+
+ NFSREQ_SECINFO_SET(&si, NULL, fhp, fhsize, name, 0);
+ numops = 3;
+ nfsm_chain_build_alloc_init(error, &nmreq, 18 * NFSX_UNSIGNED);
+ nfsm_chain_add_compound_header(error, &nmreq, "fs_locations", numops);
+ numops--;
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
+ nfsm_chain_add_fh(error, &nmreq, NFS_VER4, fhp, fhsize);
+ numops--;
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUP);
+ nfsm_chain_add_name(error, &nmreq, name, strlen(name), nmp);
+ numops--;
+ nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
+ NFS_CLEAR_ATTRIBUTES(bitmap);
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_FS_LOCATIONS);
+ nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
+ nfsm_chain_build_done(error, &nmreq);
+ nfsm_assert(error, (numops == 0), EPROTO);
+ nfsmout_if(error);
+ error = nfs_request_async(dnp, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
+ vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
+ if (!error)
+ error = nfs_request_async_finish(req, &nmrep, &xid, &status);
+ nfsm_chain_skip_tag(error, &nmrep);
+ nfsm_chain_get_32(error, &nmrep, numops);
+ nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
+ nfsm_chain_op_check(error, &nmrep, NFS_OP_LOOKUP);
+ nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
+ nfsmout_if(error);
+ error = nfs4_parsefattr(&nmrep, NULL, NULL, NULL, NULL, nfslsp);
+nfsmout:
+ nfsm_chain_cleanup(&nmrep);
+ nfsm_chain_cleanup(&nmreq);
+ return (error);
+}
+
+/*
+ * Referral trigger nodes may not have many attributes provided by the
+ * server, so put some default values in place.
+ */
+void
+nfs4_default_attrs_for_referral_trigger(
+ nfsnode_t dnp,
+ char *name,
+ int namelen,
+ struct nfs_vattr *nvap,
+ fhandle_t *fhp)
+{
+ struct timeval now;
+ microtime(&now);
+ int len;
+
+ nvap->nva_flags = NFS_FFLAG_TRIGGER | NFS_FFLAG_TRIGGER_REFERRAL;
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TYPE)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TYPE);
+ nvap->nva_type = VDIR;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FSID)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FSID);
+ nvap->nva_fsid.major = 0;
+ nvap->nva_fsid.minor = 0;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) && dnp) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_OWNER);
+ nvap->nva_uid = dnp->n_vattr.nva_uid;
+ nvap->nva_uuuid = dnp->n_vattr.nva_uuuid;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) && dnp) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP);
+ nvap->nva_gid = dnp->n_vattr.nva_gid;
+ nvap->nva_guuid = dnp->n_vattr.nva_guuid;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_MODE);
+ nvap->nva_mode = 0777;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_SIZE)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_SIZE);
+ nvap->nva_size = 0;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_SPACE_USED)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_SPACE_USED);
+ nvap->nva_bytes = 0;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS);
+ nvap->nva_nlink = 2;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_ACCESS)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_ACCESS);
+ nvap->nva_timesec[NFSTIME_ACCESS] = now.tv_sec;
+ nvap->nva_timensec[NFSTIME_ACCESS] = now.tv_usec * 1000;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY);
+ nvap->nva_timesec[NFSTIME_MODIFY] = now.tv_sec;
+ nvap->nva_timensec[NFSTIME_MODIFY] = now.tv_usec * 1000;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_METADATA)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_METADATA);
+ nvap->nva_timesec[NFSTIME_CHANGE] = now.tv_sec;
+ nvap->nva_timensec[NFSTIME_CHANGE] = now.tv_usec * 1000;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEID)) {
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FILEID);
+ nvap->nva_fileid = 42;
+ }
+ if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEHANDLE) && dnp && name && fhp) {
+ /* Build a fake filehandle made up of parent node pointer and name */
+ NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FILEHANDLE);
+ bcopy(&dnp, &fhp->fh_data[0], sizeof(dnp));
+ len = sizeof(fhp->fh_data) - sizeof(dnp);
+ bcopy(name, &fhp->fh_data[0] + sizeof(dnp), MIN(len, namelen));
+ fhp->fh_len = sizeof(dnp) + namelen;
+ if (fhp->fh_len > (int)sizeof(fhp->fh_data))
+ fhp->fh_len = sizeof(fhp->fh_data);
+ }
+}
+
+/*
+ * Set NFS bitmap according to what's set in vnode_attr (and supported by the server).
+ */
+void
+nfs_vattr_set_bitmap(struct nfsmount *nmp, uint32_t *bitmap, struct vnode_attr *vap)
+{
+ int i;
+
+ NFS_CLEAR_ATTRIBUTES(bitmap);
+ if (VATTR_IS_ACTIVE(vap, va_data_size))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_SIZE);
+ if (VATTR_IS_ACTIVE(vap, va_acl) && (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_ACL);
+ if (VATTR_IS_ACTIVE(vap, va_flags)) {
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_ARCHIVE);
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_HIDDEN);
+ }
+ // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
+ if (VATTR_IS_ACTIVE(vap, va_mode) && !NMFLAG(nmp, ACLONLY))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_MODE);
+ if (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_uuuid))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER);
+ if (VATTR_IS_ACTIVE(vap, va_gid) || VATTR_IS_ACTIVE(vap, va_guuid))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER_GROUP);
+ // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
+ if (vap->va_vaflags & VA_UTIMES_NULL) {
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
+ } else {
+ if (VATTR_IS_ACTIVE(vap, va_access_time))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
+ if (VATTR_IS_ACTIVE(vap, va_modify_time))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
+ }
+ if (VATTR_IS_ACTIVE(vap, va_backup_time))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_BACKUP);
+ if (VATTR_IS_ACTIVE(vap, va_create_time))
+ NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_CREATE);
+ /* and limit to what is supported by server */
+ for (i=0; i < NFS_ATTR_BITMAP_LEN; i++)
+ bitmap[i] &= nmp->nm_fsattr.nfsa_supp_attr[i];
+}
+
+/*
+ * Convert between NFSv4 and VFS ACE types
+ */
+uint32_t
+nfs4_ace_nfstype_to_vfstype(uint32_t nfsacetype, int *errorp)
+{
+ switch (nfsacetype) {
+ case NFS_ACE_ACCESS_ALLOWED_ACE_TYPE:
+ return KAUTH_ACE_PERMIT;
+ case NFS_ACE_ACCESS_DENIED_ACE_TYPE:
+ return KAUTH_ACE_DENY;
+ case NFS_ACE_SYSTEM_AUDIT_ACE_TYPE:
+ return KAUTH_ACE_AUDIT;
+ case NFS_ACE_SYSTEM_ALARM_ACE_TYPE:
+ return KAUTH_ACE_ALARM;
+ }
+ *errorp = EBADRPC;
+ return 0;
+}
+
+uint32_t
+nfs4_ace_vfstype_to_nfstype(uint32_t vfstype, int *errorp)
+{
+ switch (vfstype) {
+ case KAUTH_ACE_PERMIT:
+ return NFS_ACE_ACCESS_ALLOWED_ACE_TYPE;
+ case KAUTH_ACE_DENY:
+ return NFS_ACE_ACCESS_DENIED_ACE_TYPE;
+ case KAUTH_ACE_AUDIT:
+ return NFS_ACE_SYSTEM_AUDIT_ACE_TYPE;
+ case KAUTH_ACE_ALARM:
+ return NFS_ACE_SYSTEM_ALARM_ACE_TYPE;
+ }
+ *errorp = EINVAL;
+ return 0;
+}
+
+/*
+ * Convert between NFSv4 and VFS ACE flags
+ */
+uint32_t
+nfs4_ace_nfsflags_to_vfsflags(uint32_t nfsflags)
+{
+ uint32_t vfsflags = 0;
+
+ if (nfsflags & NFS_ACE_FILE_INHERIT_ACE)
+ vfsflags |= KAUTH_ACE_FILE_INHERIT;
+ if (nfsflags & NFS_ACE_DIRECTORY_INHERIT_ACE)
+ vfsflags |= KAUTH_ACE_DIRECTORY_INHERIT;
+ if (nfsflags & NFS_ACE_NO_PROPAGATE_INHERIT_ACE)
+ vfsflags |= KAUTH_ACE_LIMIT_INHERIT;
+ if (nfsflags & NFS_ACE_INHERIT_ONLY_ACE)
+ vfsflags |= KAUTH_ACE_ONLY_INHERIT;
+ if (nfsflags & NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+ vfsflags |= KAUTH_ACE_SUCCESS;
+ if (nfsflags & NFS_ACE_FAILED_ACCESS_ACE_FLAG)
+ vfsflags |= KAUTH_ACE_FAILURE;
+ if (nfsflags & NFS_ACE_INHERITED_ACE)
+ vfsflags |= KAUTH_ACE_INHERITED;
+
+ return (vfsflags);
+}
+
+uint32_t
+nfs4_ace_vfsflags_to_nfsflags(uint32_t vfsflags)
+{
+ uint32_t nfsflags = 0;
+
+ if (vfsflags & KAUTH_ACE_FILE_INHERIT)
+ nfsflags |= NFS_ACE_FILE_INHERIT_ACE;
+ if (vfsflags & KAUTH_ACE_DIRECTORY_INHERIT)
+ nfsflags |= NFS_ACE_DIRECTORY_INHERIT_ACE;
+ if (vfsflags & KAUTH_ACE_LIMIT_INHERIT)
+ nfsflags |= NFS_ACE_NO_PROPAGATE_INHERIT_ACE;
+ if (vfsflags & KAUTH_ACE_ONLY_INHERIT)
+ nfsflags |= NFS_ACE_INHERIT_ONLY_ACE;
+ if (vfsflags & KAUTH_ACE_SUCCESS)
+ nfsflags |= NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+ if (vfsflags & KAUTH_ACE_FAILURE)
+ nfsflags |= NFS_ACE_FAILED_ACCESS_ACE_FLAG;
+ if (vfsflags & KAUTH_ACE_INHERITED)
+ nfsflags |= NFS_ACE_INHERITED_ACE;
+
+ return (nfsflags);
+}
+
+/*
+ * Convert between NFSv4 ACE access masks and VFS access rights
+ */
+uint32_t
+nfs4_ace_nfsmask_to_vfsrights(uint32_t nfsmask)
+{
+ uint32_t vfsrights = 0;
+
+ if (nfsmask & NFS_ACE_READ_DATA)
+ vfsrights |= KAUTH_VNODE_READ_DATA;
+ if (nfsmask & NFS_ACE_LIST_DIRECTORY)
+ vfsrights |= KAUTH_VNODE_LIST_DIRECTORY;
+ if (nfsmask & NFS_ACE_WRITE_DATA)
+ vfsrights |= KAUTH_VNODE_WRITE_DATA;
+ if (nfsmask & NFS_ACE_ADD_FILE)
+ vfsrights |= KAUTH_VNODE_ADD_FILE;
+ if (nfsmask & NFS_ACE_APPEND_DATA)
+ vfsrights |= KAUTH_VNODE_APPEND_DATA;
+ if (nfsmask & NFS_ACE_ADD_SUBDIRECTORY)
+ vfsrights |= KAUTH_VNODE_ADD_SUBDIRECTORY;
+ if (nfsmask & NFS_ACE_READ_NAMED_ATTRS)
+ vfsrights |= KAUTH_VNODE_READ_EXTATTRIBUTES;
+ if (nfsmask & NFS_ACE_WRITE_NAMED_ATTRS)
+ vfsrights |= KAUTH_VNODE_WRITE_EXTATTRIBUTES;
+ if (nfsmask & NFS_ACE_EXECUTE)
+ vfsrights |= KAUTH_VNODE_EXECUTE;
+ if (nfsmask & NFS_ACE_DELETE_CHILD)
+ vfsrights |= KAUTH_VNODE_DELETE_CHILD;
+ if (nfsmask & NFS_ACE_READ_ATTRIBUTES)
+ vfsrights |= KAUTH_VNODE_READ_ATTRIBUTES;
+ if (nfsmask & NFS_ACE_WRITE_ATTRIBUTES)
+ vfsrights |= KAUTH_VNODE_WRITE_ATTRIBUTES;
+ if (nfsmask & NFS_ACE_DELETE)
+ vfsrights |= KAUTH_VNODE_DELETE;
+ if (nfsmask & NFS_ACE_READ_ACL)
+ vfsrights |= KAUTH_VNODE_READ_SECURITY;
+ if (nfsmask & NFS_ACE_WRITE_ACL)
+ vfsrights |= KAUTH_VNODE_WRITE_SECURITY;
+ if (nfsmask & NFS_ACE_WRITE_OWNER)
+ vfsrights |= KAUTH_VNODE_CHANGE_OWNER;
+ if (nfsmask & NFS_ACE_SYNCHRONIZE)
+ vfsrights |= KAUTH_VNODE_SYNCHRONIZE;
+ if ((nfsmask & NFS_ACE_GENERIC_READ) == NFS_ACE_GENERIC_READ)
+ vfsrights |= KAUTH_ACE_GENERIC_READ;
+ if ((nfsmask & NFS_ACE_GENERIC_WRITE) == NFS_ACE_GENERIC_WRITE)
+ vfsrights |= KAUTH_ACE_GENERIC_WRITE;
+ if ((nfsmask & NFS_ACE_GENERIC_EXECUTE) == NFS_ACE_GENERIC_EXECUTE)
+ vfsrights |= KAUTH_ACE_GENERIC_EXECUTE;
+
+ return (vfsrights);
+}
+
+uint32_t
+nfs4_ace_vfsrights_to_nfsmask(uint32_t vfsrights)
+{
+ uint32_t nfsmask = 0;
+
+ if (vfsrights & KAUTH_VNODE_READ_DATA)
+ nfsmask |= NFS_ACE_READ_DATA;
+ if (vfsrights & KAUTH_VNODE_LIST_DIRECTORY)
+ nfsmask |= NFS_ACE_LIST_DIRECTORY;
+ if (vfsrights & KAUTH_VNODE_WRITE_DATA)
+ nfsmask |= NFS_ACE_WRITE_DATA;
+ if (vfsrights & KAUTH_VNODE_ADD_FILE)
+ nfsmask |= NFS_ACE_ADD_FILE;
+ if (vfsrights & KAUTH_VNODE_APPEND_DATA)
+ nfsmask |= NFS_ACE_APPEND_DATA;
+ if (vfsrights & KAUTH_VNODE_ADD_SUBDIRECTORY)
+ nfsmask |= NFS_ACE_ADD_SUBDIRECTORY;
+ if (vfsrights & KAUTH_VNODE_READ_EXTATTRIBUTES)
+ nfsmask |= NFS_ACE_READ_NAMED_ATTRS;
+ if (vfsrights & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
+ nfsmask |= NFS_ACE_WRITE_NAMED_ATTRS;
+ if (vfsrights & KAUTH_VNODE_EXECUTE)
+ nfsmask |= NFS_ACE_EXECUTE;
+ if (vfsrights & KAUTH_VNODE_DELETE_CHILD)
+ nfsmask |= NFS_ACE_DELETE_CHILD;
+ if (vfsrights & KAUTH_VNODE_READ_ATTRIBUTES)
+ nfsmask |= NFS_ACE_READ_ATTRIBUTES;
+ if (vfsrights & KAUTH_VNODE_WRITE_ATTRIBUTES)
+ nfsmask |= NFS_ACE_WRITE_ATTRIBUTES;
+ if (vfsrights & KAUTH_VNODE_DELETE)
+ nfsmask |= NFS_ACE_DELETE;
+ if (vfsrights & KAUTH_VNODE_READ_SECURITY)
+ nfsmask |= NFS_ACE_READ_ACL;
+ if (vfsrights & KAUTH_VNODE_WRITE_SECURITY)
+ nfsmask |= NFS_ACE_WRITE_ACL;
+ if (vfsrights & KAUTH_VNODE_CHANGE_OWNER)
+ nfsmask |= NFS_ACE_WRITE_OWNER;
+ if (vfsrights & KAUTH_VNODE_SYNCHRONIZE)
+ nfsmask |= NFS_ACE_SYNCHRONIZE;
+ if (vfsrights & KAUTH_ACE_GENERIC_READ)
+ nfsmask |= NFS_ACE_GENERIC_READ;
+ if (vfsrights & KAUTH_ACE_GENERIC_WRITE)
+ nfsmask |= NFS_ACE_GENERIC_WRITE;
+ if (vfsrights & KAUTH_ACE_GENERIC_EXECUTE)
+ nfsmask |= NFS_ACE_GENERIC_EXECUTE;
+ if (vfsrights & KAUTH_ACE_GENERIC_ALL)
+ nfsmask |= (KAUTH_ACE_GENERIC_READ|KAUTH_ACE_GENERIC_WRITE|NFS_ACE_GENERIC_EXECUTE);
+
+ return (nfsmask);
+}
+
+/*
+ * Map an NFSv4 ID string to a VFS guid.
+ *
+ * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
+ */
+int
+nfs4_id2guid(/*const*/ char *id, guid_t *guidp, int isgroup)
+{
+ int error1 = 0, error = 0, compare;
+ guid_t guid1, guid2, *gp;
+ ntsid_t sid;
+ long num, unknown;
+ const char *p, *at;
+
+ *guidp = kauth_null_guid;
+ compare = ((nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) &&
+ (nfs_idmap_ctrl & NFS_IDMAP_CTRL_COMPARE_RESULTS));
+ unknown = (nfs_idmap_ctrl & NFS_IDMAP_CTRL_UNKNOWN_IS_99) ? 99 : -2;
+
+ /*
+ * First check if it is just a simple numeric ID string or a special "XXX@" name.
+ * If it's a number, there's no need trying to ask the IDMAP service to map it.
+ * If it's a special "XXX@" name, we want to make sure to treat it as a group.
+ */
+ num = 1;
+ at = NULL;
+ p = id;
+ while (*p) {
+ if ((*p < '0') || (*p > '9'))
+ num = 0;
+ if (*p == '@')
+ at = p;
+ p++;
+ }
+ if (at && !at[1] && !isgroup)
+ isgroup = 1; /* special "XXX@" names should always be treated as groups */
+ if (num) {
+ /* must be numeric ID (or empty) */
+ num = *id ? strtol(id, NULL, 10) : unknown;
+ gp = guidp;
+ goto gotnumid;
+ }
+
+ if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) {
+ /*
+ * Ask the ID mapping service to map the ID string to a GUID.
+ *
+ * [sigh] this isn't a "pwnam/grnam" it's an NFS ID string!
+ */
+ gp = compare ? &guid1 : guidp;
+ if (isgroup)
+ error = kauth_cred_grnam2guid(id, gp);
+ else
+ error = kauth_cred_pwnam2guid(id, gp);
+ if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
+ printf("nfs4_id2guid: idmap failed for %s %s error %d\n", id, isgroup ? "G" : " ", error);
+ if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
+ printf("nfs4_id2guid: idmap for %s %s got guid "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
+ id, isgroup ? "G" : " ",
+ gp->g_guid[0], gp->g_guid[1], gp->g_guid[2], gp->g_guid[3],
+ gp->g_guid[4], gp->g_guid[5], gp->g_guid[6], gp->g_guid[7],
+ gp->g_guid[8], gp->g_guid[9], gp->g_guid[10], gp->g_guid[11],
+ gp->g_guid[12], gp->g_guid[13], gp->g_guid[14], gp->g_guid[15]);
+ error1 = error;
+ }
+ if (error || compare || !(nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE)) {
+ /*
+ * fallback path... see if we can come up with an answer ourselves.
+ */
+ gp = compare ? &guid2 : guidp;
+
+ if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS) && at && !at[1]) {
+ /* must be a special ACE "who" ID */
+ bzero(&sid, sizeof(sid));
+ sid.sid_kind = 1;
+ sid.sid_authcount = 1;
+ if (!strcmp(id, "OWNER@")) {
+ // S-1-3-0
+ sid.sid_authority[5] = 3;
+ sid.sid_authorities[0] = 0;
+ } else if (!strcmp(id, "GROUP@")) {
+ // S-1-3-1
+ sid.sid_authority[5] = 3;
+ sid.sid_authorities[0] = 1;
+ } else if (!strcmp(id, "EVERYONE@")) {
+ // S-1-1-0
+ sid.sid_authority[5] = 1;
+ sid.sid_authorities[0] = 0;
+ } else if (!strcmp(id, "INTERACTIVE@")) {
+ // S-1-5-4
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 4;
+ } else if (!strcmp(id, "NETWORK@")) {
+ // S-1-5-2
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 2;
+ } else if (!strcmp(id, "DIALUP@")) {
+ // S-1-5-1
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 1;
+ } else if (!strcmp(id, "BATCH@")) {
+ // S-1-5-3
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 3;
+ } else if (!strcmp(id, "ANONYMOUS@")) {
+ // S-1-5-7
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 7;
+ } else if (!strcmp(id, "AUTHENTICATED@")) {
+ // S-1-5-11
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 11;
+ } else if (!strcmp(id, "SERVICE@")) {
+ // S-1-5-6
+ sid.sid_authority[5] = 5;
+ sid.sid_authorities[0] = 6;
+ } else {
+ // S-1-0-0 "NOBODY"
+ sid.sid_authority[5] = 0;
+ sid.sid_authorities[0] = 0;
+ }
+ error = kauth_cred_ntsid2guid(&sid, gp);
+ } else {
+ if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS) && at) {
+ /* must be user@domain */
+ /* try to identify some well-known IDs */
+ if (!strncmp(id, "root@", 5))
+ num = 0;
+ else if (!strncmp(id, "wheel@", 6))
+ num = 0;
+ else if (!strncmp(id, "nobody@", 7))
+ num = -2;
+ else if (!strncmp(id, "nfsnobody@", 10))
+ num = -2;
+ else
+ num = unknown;
+ } else if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS) && !strcmp(id, "nobody")) {
+ num = -2;
+ } else {
+ num = unknown;
+ }
+gotnumid:
+ if (isgroup)
+ error = kauth_cred_gid2guid((gid_t)num, gp);
+ else
+ error = kauth_cred_uid2guid((uid_t)num, gp);
+ }
+ if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
+ printf("nfs4_id2guid: fallback map failed for %s %s error %d\n", id, isgroup ? "G" : " ", error);
+ if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
+ printf("nfs4_id2guid: fallback map for %s %s got guid "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
+ id, isgroup ? "G" : " ",
+ gp->g_guid[0], gp->g_guid[1], gp->g_guid[2], gp->g_guid[3],
+ gp->g_guid[4], gp->g_guid[5], gp->g_guid[6], gp->g_guid[7],
+ gp->g_guid[8], gp->g_guid[9], gp->g_guid[10], gp->g_guid[11],
+ gp->g_guid[12], gp->g_guid[13], gp->g_guid[14], gp->g_guid[15]);
+ }
+
+ if (compare) {
+ /* compare the results, log if different */
+ if (!error1 && !error) {
+ if (!kauth_guid_equal(&guid1, &guid2))
+ printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
+ "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
+ "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
+ id, isgroup ? "G" : " ",
+ guid1.g_guid[0], guid1.g_guid[1], guid1.g_guid[2], guid1.g_guid[3],
+ guid1.g_guid[4], guid1.g_guid[5], guid1.g_guid[6], guid1.g_guid[7],
+ guid1.g_guid[8], guid1.g_guid[9], guid1.g_guid[10], guid1.g_guid[11],
+ guid1.g_guid[12], guid1.g_guid[13], guid1.g_guid[14], guid1.g_guid[15],
+ guid2.g_guid[0], guid2.g_guid[1], guid2.g_guid[2], guid2.g_guid[3],
+ guid2.g_guid[4], guid2.g_guid[5], guid2.g_guid[6], guid2.g_guid[7],
+ guid2.g_guid[8], guid2.g_guid[9], guid2.g_guid[10], guid2.g_guid[11],
+ guid2.g_guid[12], guid2.g_guid[13], guid2.g_guid[14], guid2.g_guid[15]);
+ /* copy idmap result to output guid */
+ *guidp = guid1;
+ } else if (error1 && !error) {
+ printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
+ "idmap error %d "
+ "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
+ id, isgroup ? "G" : " ",
+ error1,
+ guid2.g_guid[0], guid2.g_guid[1], guid2.g_guid[2], guid2.g_guid[3],
+ guid2.g_guid[4], guid2.g_guid[5], guid2.g_guid[6], guid2.g_guid[7],
+ guid2.g_guid[8], guid2.g_guid[9], guid2.g_guid[10], guid2.g_guid[11],
+ guid2.g_guid[12], guid2.g_guid[13], guid2.g_guid[14], guid2.g_guid[15]);
+ /* copy fallback result to output guid */
+ *guidp = guid2;
+ } else if (!error1 && error) {
+ printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
+ "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
+ "fallback error %d\n",
+ id, isgroup ? "G" : " ",
+ guid1.g_guid[0], guid1.g_guid[1], guid1.g_guid[2], guid1.g_guid[3],
+ guid1.g_guid[4], guid1.g_guid[5], guid1.g_guid[6], guid1.g_guid[7],
+ guid1.g_guid[8], guid1.g_guid[9], guid1.g_guid[10], guid1.g_guid[11],
+ guid1.g_guid[12], guid1.g_guid[13], guid1.g_guid[14], guid1.g_guid[15],
+ error);
+ /* copy idmap result to output guid */
+ *guidp = guid1;
+ error = 0;
+ } else {
+ if (error1 != error)
+ printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
+ "idmap error %d fallback error %d\n",
+ id, isgroup ? "G" : " ", error1, error);
+ }
+ }
+
+ return (error);
+}
+
+/*
+ * Map a VFS guid to an NFSv4 ID string.
+ *
+ * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
+ */
+int
+nfs4_guid2id(guid_t *guidp, char *id, int *idlen, int isgroup)
+{
+ int error1 = 0, error = 0, compare;
+ int id1len, id2len, len;
+ char *id1buf, *id1;
+ char numbuf[32];
+ const char *id2 = NULL;
+
+ id1buf = id1 = NULL;
+ id1len = id2len = 0;
+ compare = ((nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) &&
+ (nfs_idmap_ctrl & NFS_IDMAP_CTRL_COMPARE_RESULTS));
+
+ if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) {
+ /*
+ * Ask the ID mapping service to map the GUID to an ID string.
+ *
+ * [sigh] this isn't a "pwnam" it's an NFS id string!
+ */
+
+ /*
+ * Stupid kauth_cred_guid2pwnam() function requires that the buffer
+ * be at least MAXPATHLEN bytes long even though most if not all ID
+ * strings will be much much shorter than that.
+ */
+ if (compare || (*idlen < MAXPATHLEN)) {
+ MALLOC_ZONE(id1buf, char*, MAXPATHLEN, M_NAMEI, M_WAITOK);
+ if (!id1buf)
+ return (ENOMEM);
+ id1 = id1buf;
+ id1len = MAXPATHLEN;
+ } else {
+ id1 = id;
+ id1len = *idlen;
+ }
+
+ if (isgroup)
+ error = kauth_cred_guid2grnam(guidp, id1);
+ else
+ error = kauth_cred_guid2pwnam(guidp, id1);
+ if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
+ printf("nfs4_guid2id: idmap failed for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "error %d\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", error);
+ if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
+ printf("nfs4_guid2id: idmap for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "got ID %s\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", id1);
+ error1 = error;
+ if (!error) {
+ if (compare) {
+ id1len = strnlen(id1, id1len);
+ } else if (id1 == id1buf) {
+ /* copy idmap result to output buffer */
+ len = strlcpy(id, id1, *idlen);
+ if (len >= *idlen)
+ error = ENOSPC;
+ else
+ *idlen = len;
+ }
+ }
+ }
+ if (error || compare || !(nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE)) {
+ /*
+ * fallback path... see if we can come up with an answer ourselves.
+ */
+ ntsid_t sid;
+ uid_t uid;
+
+ if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS)) {
+ error = kauth_cred_guid2ntsid(guidp, &sid);
+ if (!error && (sid.sid_kind == 1) && (sid.sid_authcount == 1)) {
+ /* check if it's one of our well-known ACE WHO names */
+ if (sid.sid_authority[5] == 0) {
+ if (sid.sid_authorities[0] == 0) // S-1-0-0
+ id2 = "nobody@localdomain";
+ } else if (sid.sid_authority[5] == 1) {
+ if (sid.sid_authorities[0] == 0) // S-1-1-0
+ id2 = "EVERYONE@";
+ } else if (sid.sid_authority[5] == 3) {
+ if (sid.sid_authorities[0] == 0) // S-1-3-0
+ id2 = "OWNER@";
+ else if (sid.sid_authorities[0] == 1) // S-1-3-1
+ id2 = "GROUP@";
+ } else if (sid.sid_authority[5] == 5) {
+ if (sid.sid_authorities[0] == ntohl(1)) // S-1-5-1
+ id2 = "DIALUP@";
+ else if (sid.sid_authorities[0] == ntohl(2)) // S-1-5-2
+ id2 = "NETWORK@";
+ else if (sid.sid_authorities[0] == ntohl(3)) // S-1-5-3
+ id2 = "BATCH@";
+ else if (sid.sid_authorities[0] == ntohl(4)) // S-1-5-4
+ id2 = "INTERACTIVE@";
+ else if (sid.sid_authorities[0] == ntohl(6)) // S-1-5-6
+ id2 = "SERVICE@";
+ else if (sid.sid_authorities[0] == ntohl(7)) // S-1-5-7
+ id2 = "ANONYMOUS@";
+ else if (sid.sid_authorities[0] == ntohl(11)) // S-1-5-11
+ id2 = "AUTHENTICATED@";
+ }
+ }
+ }
+ if (!id2) {
+ /* OK, let's just try mapping it to a UID/GID */
+ if (isgroup)
+ error = kauth_cred_guid2gid(guidp, (gid_t*)&uid);
+ else
+ error = kauth_cred_guid2uid(guidp, &uid);
+ if (!error) {
+ if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS)) {
+ /* map well known uid's to strings */
+ if (uid == 0)
+ id2 = isgroup ? "wheel@localdomain" : "root@localdomain";
+ else if (uid == (uid_t)-2)
+ id2 = "nobody@localdomain";
+ }
+ if (!id2) {
+ /* or just use a decimal number string. */
+ snprintf(numbuf, sizeof(numbuf), "%d", uid);
+ id2 = numbuf;
+ }
+ }
+ }
+ if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
+ printf("nfs4_guid2id: fallback map failed for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "error %d\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", error);
+ if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
+ printf("nfs4_guid2id: fallback map for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "got ID %s\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", id2);
+ if (!error && id2) {
+ if (compare) {
+ id2len = strnlen(id2, MAXPATHLEN);
+ } else {
+ /* copy fallback result to output buffer */
+ len = strlcpy(id, id2, *idlen);
+ if (len >= *idlen)
+ error = ENOSPC;
+ else
+ *idlen = len;
+ }
+ }
+ }
+
+ if (compare) {
+ /* compare the results, log if different */
+ if (!error1 && !error) {
+ if ((id1len != id2len) || strncmp(id1, id2, id1len))
+ printf("nfs4_guid2id: idmap/fallback results differ for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "idmap %s fallback %s\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", id1, id2);
+ if (id1 == id1buf) {
+ /* copy idmap result to output buffer */
+ len = strlcpy(id, id1, *idlen);
+ if (len >= *idlen)
+ error = ENOSPC;
+ else
+ *idlen = len;
+ }
+ } else if (error1 && !error) {
+ printf("nfs4_guid2id: idmap/fallback results differ for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "idmap error %d fallback %s\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", error1, id2);
+ /* copy fallback result to output buffer */
+ len = strlcpy(id, id2, *idlen);
+ if (len >= *idlen)
+ error = ENOSPC;
+ else
+ *idlen = len;
+ } else if (!error1 && error) {
+ printf("nfs4_guid2id: idmap/fallback results differ for "
+ "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
+ "idmap %s fallback error %d\n",
+ guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
+ guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
+ guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
+ guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
+ isgroup ? "G" : " ", id1, error);
+ if (id1 == id1buf) {
+ /* copy idmap result to output buffer */
+ len = strlcpy(id, id1, *idlen);
+ if (len >= *idlen)
+ error = ENOSPC;
+ else
+ *idlen = len;
+ }
+ error = 0;
+ } else {
+ if (error1 != error)
+ printf("nfs4_guid2id: idmap/fallback results differ for %s %s - "
+ "idmap error %d fallback error %d\n",
+ id, isgroup ? "G" : " ", error1, error);
+ }
+ }
+ if (id1buf)
+ FREE_ZONE(id1buf, MAXPATHLEN, M_NAMEI);
+ return (error);
+}
+
+