+ if (nmp->nm_sprinc) {
+ *len = strlen(nmp->nm_sprinc) + 1;
+ MALLOC(svcname, char *, *len, M_TEMP, M_WAITOK);
+ *nt = GSSD_HOSTBASED;
+ if (svcname == NULL)
+ return (NULL);
+ strlcpy(svcname, nmp->nm_sprinc, *len);
+
+ return ((uint8_t *)svcname);
+ }
+
+ *nt = GSSD_HOSTBASED;
+ if (nmp->nm_locations.nl_numlocs && !(NFS_GSS_ISDBG && (NFS_DEBUG_FLAGS & 0x1))) {
+ lindx = nmp->nm_locations.nl_current.nli_loc;
+ sindx = nmp->nm_locations.nl_current.nli_serv;
+ server = nmp->nm_locations.nl_locations[lindx]->nl_servers[sindx]->ns_name;
+ *len = (uint32_t)strlen(server);
+ } else {
+ /* Older binaries using older mount args end up here */
+ server = vfs_statfs(nmp->nm_mountp)->f_mntfromname;
+ NFS_GSS_DBG("nfs getting gss svcname from %s\n", server);
+ d = strchr(server, ':');
+ *len = (uint32_t)(d ? (d - server) : strlen(server));
+ }
+
+ *len += 5; /* "nfs@" plus null */
+ MALLOC(svcname, char *, *len, M_TEMP, M_WAITOK);
+ strlcpy(svcname, "nfs", *len);
+ strlcat(svcname, "@", *len);
+ strlcat(svcname, server, *len);
+ NFS_GSS_DBG("nfs svcname = %s\n", svcname);
+
+ return ((uint8_t *)svcname);
+}
+
+/*
+ * Get a mach port to talk to gssd.
+ * gssd lives in the root bootstrap, so we call gssd's lookup routine
+ * to get a send right to talk to a new gssd instance that launchd has launched
+ * based on the cred's uid and audit session id.
+ */
+
+static mach_port_t
+nfs_gss_clnt_get_upcall_port(kauth_cred_t credp)
+{
+ mach_port_t gssd_host_port, uc_port = IPC_PORT_NULL;
+ kern_return_t kr;
+ au_asid_t asid;
+ uid_t uid;
+
+ kr = host_get_gssd_port(host_priv_self(), &gssd_host_port);
+ if (kr != KERN_SUCCESS) {
+ printf("nfs_gss_get_upcall_port: can't get gssd port, status %x (%d)\n", kr, kr);
+ return (IPC_PORT_NULL);
+ }
+ if (!IPC_PORT_VALID(gssd_host_port)) {
+ printf("nfs_gss_get_upcall_port: gssd port not valid\n");
+ return (IPC_PORT_NULL);
+ }
+
+ asid = kauth_cred_getasid(credp);
+ uid = kauth_cred_getauid(credp);
+ if (uid == AU_DEFAUDITID)
+ uid = kauth_cred_getuid(credp);
+ kr = mach_gss_lookup(gssd_host_port, uid, asid, &uc_port);
+ if (kr != KERN_SUCCESS)
+ printf("nfs_gss_clnt_get_upcall_port: mach_gssd_lookup failed: status %x (%d)\n", kr, kr);
+ host_release_special_port(gssd_host_port);
+
+ return (uc_port);
+}
+
+
+static void
+nfs_gss_clnt_log_error(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp, uint32_t major, uint32_t minor)
+{
+#define GETMAJERROR(x) (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
+ struct nfsmount *nmp = req->r_nmp;
+ char who[] = "client";
+ uint32_t gss_error = GETMAJERROR(cp->gss_clnt_major);
+ const char *procn = "unkown";
+ proc_t proc;
+ pid_t pid = -1;
+ struct timeval now;
+
+ if (req->r_thread) {
+ proc = (proc_t)get_bsdthreadtask_info(req->r_thread);
+ if (proc != NULL && (proc->p_fd == NULL || (proc->p_lflag & P_LVFORK)))
+ proc = NULL;
+ if (proc) {
+ if (*proc->p_comm)
+ procn = proc->p_comm;
+ pid = proc->p_pid;
+ }
+ } else {
+ procn = "kernproc";
+ pid = 0;
+ }
+
+ microuptime(&now);
+ if ((cp->gss_clnt_major != major || cp->gss_clnt_minor != minor ||
+ cp->gss_clnt_ptime + GSS_PRINT_DELAY < now.tv_sec) &&
+ (nmp->nm_state & NFSSTA_MOUNTED)) {
+ /*
+ * Will let gssd do some logging in hopes that it can translate
+ * the minor code.
+ */
+ if (cp->gss_clnt_minor && cp->gss_clnt_minor != minor) {
+ (void) mach_gss_log_error(
+ cp->gss_clnt_mport,
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname,
+ kauth_cred_getuid(cp->gss_clnt_cred),
+ who,
+ cp->gss_clnt_major,
+ cp->gss_clnt_minor);
+ }
+ gss_error = gss_error ? gss_error : cp->gss_clnt_major;
+
+ /*
+ *%%% It would be really nice to get the terminal from the proc or auditinfo_addr struct and print that here.
+ */
+ printf("NFS: gssd auth failure by %s on audit session %d uid %d proc %s/%d for mount %s. Error: major = %d minor = %d\n",
+ cp->gss_clnt_display ? cp->gss_clnt_display : who, kauth_cred_getasid(req->r_cred), kauth_cred_getuid(req->r_cred),
+ procn, pid, vfs_statfs(nmp->nm_mountp)->f_mntfromname, gss_error, (int32_t)cp->gss_clnt_minor);
+ cp->gss_clnt_ptime = now.tv_sec;
+ switch (gss_error) {
+ case 7: printf("NFS: gssd does not have credentials for session %d/%d, (kinit)?\n",
+ kauth_cred_getasid(req->r_cred), kauth_cred_getauid(req->r_cred));
+ break;
+ case 11: printf("NFS: gssd has expired credentals for session %d/%d, (kinit)?\n",
+ kauth_cred_getasid(req->r_cred), kauth_cred_getauid(req->r_cred));
+ break;
+ }
+ } else {
+ NFS_GSS_DBG("NFS: gssd auth failure by %s on audit session %d uid %d proc %s/%d for mount %s. Error: major = %d minor = %d\n",
+ cp->gss_clnt_display ? cp->gss_clnt_display : who, kauth_cred_getasid(req->r_cred), kauth_cred_getuid(req->r_cred),
+ procn, pid, vfs_statfs(nmp->nm_mountp)->f_mntfromname, gss_error, (int32_t)cp->gss_clnt_minor);
+ }