+
+/*
+ * Removes a mounts context for a credential
+ */
+int
+nfs_gss_clnt_ctx_remove(struct nfsmount *nmp, kauth_cred_t cred)
+{
+ struct nfs_gss_clnt_ctx *cp;
+ struct nfsreq req;
+
+ req.r_nmp = nmp;
+
+ NFS_GSS_DBG("Enter\n");
+ NFS_GSS_CLNT_CTX_DUMP(nmp);
+ lck_mtx_lock(&nmp->nm_lock);
+ TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) {
+ lck_mtx_lock(cp->gss_clnt_mtx);
+ if (nfs_gss_clnt_ctx_cred_match(cp->gss_clnt_cred, cred)) {
+ if (cp->gss_clnt_flags & GSS_CTX_DESTROY) {
+ NFS_GSS_DBG("Found destroyed context %d/%d. refcnt = %d continuing\n",
+ kauth_cred_getasid(cp->gss_clnt_cred),
+ kauth_cred_getauid(cp->gss_clnt_cred),
+ cp->gss_clnt_refcnt);
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ continue;
+ }
+ cp->gss_clnt_refcnt++;
+ cp->gss_clnt_flags |= (GSS_CTX_INVAL | GSS_CTX_DESTROY);
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ req.r_gss_ctx = cp;
+ lck_mtx_unlock(&nmp->nm_lock);
+ /*
+ * Drop the reference to remove it if its
+ * refcount is zero.
+ */
+ NFS_GSS_DBG("Removed context %d/%d refcnt = %d\n",
+ kauth_cred_getasid(cp->gss_clnt_cred),
+ kauth_cred_getuid(cp->gss_clnt_cred),
+ cp->gss_clnt_refcnt);
+ nfs_gss_clnt_ctx_unref(&req);
+ return (0);
+ }
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ }
+
+ lck_mtx_unlock(&nmp->nm_lock);
+
+ NFS_GSS_DBG("Returning ENOENT\n");
+ return (ENOENT);
+}
+
+/*
+ * Sets a mounts principal for a session associated with cred.
+ */
+int
+nfs_gss_clnt_ctx_set_principal(struct nfsmount *nmp, vfs_context_t ctx,
+ uint8_t *principal, uint32_t princlen, uint32_t nametype)
+
+{
+ struct nfsreq req;
+ int error;
+
+ NFS_GSS_DBG("Enter:\n");
+
+ bzero(&req, sizeof(struct nfsreq));
+ req.r_nmp = nmp;
+ req.r_gss_ctx = NULL;
+ req.r_auth = nmp->nm_auth;
+ req.r_thread = vfs_context_thread(ctx);
+ req.r_cred = vfs_context_ucred(ctx);
+
+ error = nfs_gss_clnt_ctx_find_principal(&req, principal, princlen, nametype);
+ NFS_GSS_DBG("nfs_gss_clnt_ctx_find_principal returned %d\n", error);
+ /*
+ * We don't care about auth errors. Those would indicate that the context is in the
+ * neagative cache and if and when the user has credentials for the principal
+ * we should be good to go in that we will select those credentials for this principal.
+ */
+ if (error == EACCES || error == EAUTH || error == ENEEDAUTH)
+ error = 0;
+
+ /* We're done with this request */
+ nfs_gss_clnt_ctx_unref(&req);
+
+ return (error);
+}
+
+/*
+ * Gets a mounts principal from a session associated with cred
+ */
+int
+nfs_gss_clnt_ctx_get_principal(struct nfsmount *nmp, vfs_context_t ctx,
+ struct user_nfs_gss_principal *p)
+{
+ struct nfsreq req;
+ int error = 0;
+ struct nfs_gss_clnt_ctx *cp;
+ kauth_cred_t cred = vfs_context_ucred(ctx);
+ const char *princ;
+ char CTXBUF[NFS_CTXBUFSZ];
+
+ req.r_nmp = nmp;
+ lck_mtx_lock(&nmp->nm_lock);
+ TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) {
+ lck_mtx_lock(cp->gss_clnt_mtx);
+ if (cp->gss_clnt_flags & GSS_CTX_DESTROY) {
+ NFS_GSS_DBG("Found destroyed context %s refcnt = %d continuing\n",
+ NFS_GSS_CTX(&req, cp),
+ cp->gss_clnt_refcnt);
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ continue;
+ }
+ if (nfs_gss_clnt_ctx_cred_match(cp->gss_clnt_cred, cred)) {
+ cp->gss_clnt_refcnt++;
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ goto out;
+ }
+ lck_mtx_unlock(cp->gss_clnt_mtx);
+ }
+
+out:
+ if (cp == NULL) {
+ lck_mtx_unlock(&nmp->nm_lock);
+ p->princlen = 0;
+ p->principal = USER_ADDR_NULL;
+ p->nametype = GSSD_STRING_NAME;
+ p->flags |= NFS_IOC_NO_CRED_FLAG;
+ NFS_GSS_DBG("No context found for session %d by uid %d\n",
+ kauth_cred_getasid(cred), kauth_cred_getuid(cred));
+ return (0);
+ }
+
+ princ = cp->gss_clnt_principal ? (char *)cp->gss_clnt_principal : cp->gss_clnt_display;
+ p->princlen = cp->gss_clnt_principal ? cp->gss_clnt_prinlen :
+ (cp->gss_clnt_display ? strlen(cp->gss_clnt_display) : 0);
+ p->nametype = cp->gss_clnt_prinnt;
+ if (princ) {
+ char *pp;
+
+ MALLOC(pp, char *, p->princlen, M_TEMP, M_WAITOK);
+ if (pp) {
+ bcopy(princ, pp, p->princlen);
+ p->principal = CAST_USER_ADDR_T(pp);
+ }
+ else
+ error = ENOMEM;
+ }
+ lck_mtx_unlock(&nmp->nm_lock);
+
+ req.r_gss_ctx = cp;
+ NFS_GSS_DBG("Found context %s\n", NFS_GSS_CTX(&req, NULL));
+ nfs_gss_clnt_ctx_unref(&req);
+ return (error);
+}