/* ARGSUSED */ static int pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) { int rc = 0; PPPT_GLOBAL_LOCK(); switch (pppt_global.global_svc_state) { case PSS_ENABLED: pppt_global.global_svc_state = PSS_DISABLING; PPPT_GLOBAL_UNLOCK(); pppt_disable_svc(); PPPT_GLOBAL_LOCK(); pppt_global.global_svc_state = PSS_DISABLED; /* * release the door to the daemon */ mutex_enter(&pppt_global.global_door_lock); if (pppt_global.global_door != NULL) { door_ki_rele(pppt_global.global_door); pppt_global.global_door = NULL; } mutex_exit(&pppt_global.global_door_lock); break; default: rc = EFAULT; break; } PPPT_GLOBAL_UNLOCK(); return (rc); }
void nfscmd_args(uint_t did) { mutex_enter(&nfscmd_lock); if (nfscmd_dh) door_ki_rele(nfscmd_dh); nfscmd_dh = door_ki_lookup(did); mutex_exit(&nfscmd_lock); }
void mountd_args(uint_t did) { mutex_enter(&mountd_lock); if (mountd_dh) door_ki_rele(mountd_dh); mountd_dh = door_ki_lookup(did); mutex_exit(&mountd_lock); }
static uint64_t allocids(int flag, int nuids, int ngids) { rval_t r; uid_t su = 0; gid_t sg = 0; struct door_info di; door_handle_t dh; int err; zone_t *zone = crgetzone(CRED()); dh = idmap_get_door(zone); if (dh == NULL) return (set_errno(EPERM)); if ((err = door_ki_info(dh, &di)) != 0) { door_ki_rele(dh); return (set_errno(err)); } door_ki_rele(dh); if (curproc->p_pid != di.di_target) return (set_errno(EPERM)); if (flag) idmap_purge_cache(zone); if (nuids < 0 || ngids < 0) return (set_errno(EINVAL)); if (flag != 0 || nuids > 0) err = eph_uid_alloc(zone, flag, &su, nuids); if (err == 0 && (flag != 0 || ngids > 0)) err = eph_gid_alloc(zone, flag, &sg, ngids); if (err != 0) return (set_errno(EOVERFLOW)); r.r_val1 = su; r.r_val2 = sg; return (r.r_vals); }
/* * iscsi_door_unbind * * This function releases the current door handle. */ void iscsi_door_unbind(void) { rw_enter(&iscsi_door_lock, RW_WRITER); if (iscsi_door_handle != NULL) { door_ki_rele(iscsi_door_handle); iscsi_door_handle = NULL; } rw_exit(&iscsi_door_lock); }
void klpd_rele(klpd_reg_t *p) { if (atomic_dec_32_nv(&p->klpd_ref) == 0) { if (p->klpd_refp != NULL) klpd_unlink(p); if (p->klpd_cred != NULL) crfree(p->klpd_cred); door_ki_rele(p->klpd_door); kmem_free(p, sizeof (*p)); } }
static int idmap_unreg(int did) { door_handle_t dh = door_ki_lookup(did); int res; zone_t *zone; if (dh == NULL) return (set_errno(EINVAL)); zone = crgetzone(CRED()); res = idmap_unreg_dh(zone, dh); door_ki_rele(dh); if (res != 0) return (set_errno(res)); return (0); }
/* * log_event_upcall_lookup - Establish door connection with user event * daemon (syseventd) */ static int log_event_upcall_lookup() { int error; if (event_door) { /* Release our previous hold (if any) */ door_ki_rele(event_door); } event_door = NULL; /* * Locate the door used for upcalls */ if ((error = door_ki_open(logevent_door_upcall_filename, &event_door)) != 0) { return (error); } return (0); }
/* * iscsi_door_bind * * This function tries to connect the iscsi_door. If it succeeds * it keeps the vnode. */ boolean_t iscsi_door_bind( int did ) { door_handle_t new_handle; new_handle = door_ki_lookup(did); if (new_handle == NULL) { /* The lookup failed. */ return (B_FALSE); } /* The new handle is stored. If we had one, it is released. */ rw_enter(&iscsi_door_lock, RW_WRITER); if (iscsi_door_handle != NULL) { door_ki_rele(iscsi_door_handle); } iscsi_door_handle = new_handle; rw_exit(&iscsi_door_lock); return (B_TRUE); }
/*ARGSUSED*/ static void autofs_zone_destructor(zoneid_t zoneid, void *arg) { struct autofs_globals *fngp = arg; vnode_t *vp; if (fngp == NULL) return; ASSERT(fngp->fng_fnnode_count == 1); ASSERT(fngp->fng_unmount_threads == 0); if (fngp->fng_autofs_daemon_dh != NULL) door_ki_rele(fngp->fng_autofs_daemon_dh); /* * vn_alloc() initialized the rootnode with a count of 1; we need to * make this 0 to placate auto_freefnnode(). */ vp = fntovn(fngp->fng_rootfnnodep); ASSERT(vp->v_count == 1); vp->v_count--; auto_freefnnode(fngp->fng_rootfnnodep); mutex_destroy(&fngp->fng_unmount_threads_lock); kmem_free(fngp, sizeof (*fngp)); }
int klpd_unreg(int did, idtype_t type, id_t id) { door_handle_t dh; int res = 0; proc_t *p; pid_t pid; projid_t proj; kproject_t *kpp = NULL; credklpd_t *ckp; switch (type) { case P_PID: pid = (pid_t)id; break; case P_PROJID: proj = (projid_t)id; kpp = project_hold_by_id(proj, crgetzone(CRED()), PROJECT_HOLD_FIND); if (kpp == NULL) return (set_errno(ESRCH)); break; default: return (set_errno(ENOTSUP)); } dh = door_ki_lookup(did); if (dh == NULL) { if (kpp != NULL) project_rele(kpp); return (set_errno(EINVAL)); } if (kpp != NULL) { mutex_enter(&klpd_mutex); if (kpp->kpj_klpd == NULL) res = ESRCH; else klpd_freelist(&kpp->kpj_klpd); mutex_exit(&klpd_mutex); project_rele(kpp); goto out; } else if ((int)pid > 0) { mutex_enter(&pidlock); p = prfind(pid); if (p == NULL) { mutex_exit(&pidlock); door_ki_rele(dh); return (set_errno(ESRCH)); } mutex_enter(&p->p_crlock); mutex_exit(&pidlock); } else if (pid == 0) { p = curproc; mutex_enter(&p->p_crlock); } else { res = klpd_unreg_dh(dh); goto out; } ckp = crgetcrklpd(p->p_cred); if (ckp != NULL) { crklpd_setreg(ckp, NULL); } else { res = ESRCH; } mutex_exit(&p->p_crlock); out: door_ki_rele(dh); if (res != 0) return (set_errno(res)); return (0); }
/* * Callup to the mountd to get access information in the kernel. */ static bool_t nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, struct netbuf *addr, int *access, uid_t clnt_uid, gid_t clnt_gid, uint_t clnt_gids_cnt, const gid_t *clnt_gids, uid_t *srv_uid, gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids) { varg_t varg = {0}; nfsauth_res_t res = {0}; XDR xdrs; size_t absz; caddr_t abuf; int last = 0; door_arg_t da; door_info_t di; door_handle_t dh; uint_t ntries = 0; /* * No entry in the cache for this client/flavor * so we need to call the nfsauth service in the * mount daemon. */ varg.vers = V_PROTO; varg.arg_u.arg.cmd = NFSAUTH_ACCESS; varg.arg_u.arg.areq.req_client.n_len = addr->len; varg.arg_u.arg.areq.req_client.n_bytes = addr->buf; varg.arg_u.arg.areq.req_netid = req_netid; varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; varg.arg_u.arg.areq.req_flavor = flavor; varg.arg_u.arg.areq.req_clnt_uid = clnt_uid; varg.arg_u.arg.areq.req_clnt_gid = clnt_gid; varg.arg_u.arg.areq.req_clnt_gids.len = clnt_gids_cnt; varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)clnt_gids; DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); /* * Setup the XDR stream for encoding the arguments. Notice that * in addition to the args having variable fields (req_netid and * req_path), the argument data structure is itself versioned, * so we need to make sure we can size the arguments buffer * appropriately to encode all the args. If we can't get sizing * info _or_ properly encode the arguments, there's really no * point in continuting, so we fail the request. */ if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) { *access = NFSAUTH_DENIED; return (FALSE); } abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE); if (!xdr_varg(&xdrs, &varg)) { XDR_DESTROY(&xdrs); goto fail; } XDR_DESTROY(&xdrs); /* * Prepare the door arguments * * We don't know the size of the message the daemon * will pass back to us. By setting rbuf to NULL, * we force the door code to allocate a buf of the * appropriate size. We must set rsize > 0, however, * else the door code acts as if no response was * expected and doesn't pass the data to us. */ da.data_ptr = (char *)abuf; da.data_size = absz; da.desc_ptr = NULL; da.desc_num = 0; da.rbuf = NULL; da.rsize = 1; retry: mutex_enter(&mountd_lock); dh = mountd_dh; if (dh != NULL) door_ki_hold(dh); mutex_exit(&mountd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet! * This could mean that either mountd(1m) has not yet * been started or that _this_ routine nuked the door * handle after receiving an EINTR for a REVOKED door. * * Returning NFSAUTH_DROP will cause the NFS client * to retransmit the request, so let's try to be more * rescillient and attempt for ntries before we bail. */ if (++ntries % NFSAUTH_DR_TRYCNT) { delay(hz); goto retry; } kmem_free(abuf, absz); sys_log("nfsauth: mountd has not established door"); *access = NFSAUTH_DROP; return (FALSE); } ntries = 0; /* * Now that we've got what we need, place the call. */ switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { case 0: /* Success */ door_ki_rele(dh); if (da.data_ptr == NULL && da.data_size == 0) { /* * The door_return that contained the data * failed! We're here because of the 2nd * door_return (w/o data) such that we can * get control of the thread (and exit * gracefully). */ DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, door_arg_t *, &da); goto fail; } break; case EAGAIN: /* * Server out of resources; back off for a bit */ door_ki_rele(dh); delay(hz); goto retry; /* NOTREACHED */ case EINTR: if (!door_ki_info(dh, &di)) { door_ki_rele(dh); if (di.di_attributes & DOOR_REVOKED) { /* * The server barfed and revoked * the (existing) door on us; we * want to wait to give smf(5) a * chance to restart mountd(1m) * and establish a new door handle. */ mutex_enter(&mountd_lock); if (dh == mountd_dh) { door_ki_rele(mountd_dh); mountd_dh = NULL; } mutex_exit(&mountd_lock); delay(hz); goto retry; } /* * If the door was _not_ revoked on us, * then more than likely we took an INTR, * so we need to fail the operation. */ goto fail; } /* * The only failure that can occur from getting * the door info is EINVAL, so we let the code * below handle it. */ /* FALLTHROUGH */ case EBADF: case EINVAL: default: /* * If we have a stale door handle, give smf a last * chance to start it by sleeping for a little bit. * If we're still hosed, we'll fail the call. * * Since we're going to reacquire the door handle * upon the retry, we opt to sleep for a bit and * _not_ to clear mountd_dh. If mountd restarted * and was able to set mountd_dh, we should see * the new instance; if not, we won't get caught * up in the retry/DELAY loop. */ door_ki_rele(dh); if (!last) { delay(hz); last++; goto retry; } sys_log("nfsauth: stale mountd door handle"); goto fail; }
/* * nfscmd_send(arg, result) * * Send a command to the daemon listening on the door. The result is * returned in the result pointer if the function return value is * NFSCMD_ERR_SUCCESS. Otherwise it is the error value. */ int nfscmd_send(nfscmd_arg_t *arg, nfscmd_res_t *res) { door_handle_t dh; door_arg_t da; door_info_t di; int ntries = 0; int last = 0; retry: mutex_enter(&nfscmd_lock); dh = nfscmd_dh; if (dh != NULL) door_ki_hold(dh); mutex_exit(&nfscmd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet ! * This could mean that either mountd(1m) has not yet * been started or that _this_ routine nuked the door * handle after receiving an EINTR for a REVOKED door. * * Returning NFSAUTH_DROP will cause the NFS client * to retransmit the request, so let's try to be more * rescillient and attempt for ntries before we bail. */ if (++ntries % NFSCMD_DR_TRYCNT) { delay(hz); goto retry; } return (NFSCMD_ERR_DROP); } da.data_ptr = (char *)arg; da.data_size = sizeof (nfscmd_arg_t); da.desc_ptr = NULL; da.desc_num = 0; da.rbuf = (char *)res; da.rsize = sizeof (nfscmd_res_t); switch (door_ki_upcall(dh, &da)) { case 0: /* Success */ break; case EAGAIN: /* Need to retry a couple of times */ door_ki_rele(dh); delay(hz); goto retry; /* NOTREACHED */ case EINTR: if (!door_ki_info(dh, &di)) { if (di.di_attributes & DOOR_REVOKED) { /* * The server barfed and revoked * the (existing) door on us; we * want to wait to give smf(5) a * chance to restart mountd(1m) * and establish a new door handle. */ mutex_enter(&nfscmd_lock); if (dh == nfscmd_dh) nfscmd_dh = NULL; mutex_exit(&nfscmd_lock); door_ki_rele(dh); delay(hz); goto retry; } /* * If the door was _not_ revoked on us, * then more than likely we took an INTR, * so we need to fail the operation. */ door_ki_rele(dh); } /* * The only failure that can occur from getting * the door info is EINVAL, so we let the code * below handle it. */ /* FALLTHROUGH */ case EBADF: case EINVAL: default: /* * If we have a stale door handle, give smf a last * chance to start it by sleeping for a little bit. * If we're still hosed, we'll fail the call. * * Since we're going to reacquire the door handle * upon the retry, we opt to sleep for a bit and * _not_ to clear mountd_dh. If mountd restarted * and was able to set mountd_dh, we should see * the new instance; if not, we won't get caught * up in the retry/DELAY loop. */ door_ki_rele(dh); if (!last) { delay(hz); last++; goto retry; } res->error = NFSCMD_ERR_FAIL; break; } return (res->error); }
/* * Get the access information from the cache or callup to the mountd * to get and cache the access information in the kernel. */ int nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor) { struct netbuf addr; struct netbuf *claddr; struct auth_cache **head; struct auth_cache *ap; int access; varg_t varg = {0}; nfsauth_res_t res = {0}; XDR xdrs_a; XDR xdrs_r; size_t absz; caddr_t abuf; size_t rbsz = (size_t)(BYTES_PER_XDR_UNIT * 2); char result[BYTES_PER_XDR_UNIT * 2] = {0}; caddr_t rbuf = (caddr_t)&result; int last = 0; door_arg_t da; door_info_t di; door_handle_t dh; uint_t ntries = 0; /* * Now check whether this client already * has an entry for this flavor in the cache * for this export. * Get the caller's address, mask off the * parts of the address that do not identify * the host (port number, etc), and then hash * it to find the chain of cache entries. */ claddr = svc_getrpccaller(req->rq_xprt); addr = *claddr; addr.buf = kmem_alloc(addr.len, KM_SLEEP); bcopy(claddr->buf, addr.buf, claddr->len); addrmask(&addr, svc_getaddrmask(req->rq_xprt)); head = &exi->exi_cache[hash(&addr)]; rw_enter(&exi->exi_cache_lock, RW_READER); for (ap = *head; ap; ap = ap->auth_next) { if (EQADDR(&addr, &ap->auth_addr) && flavor == ap->auth_flavor) break; } if (ap) { /* cache hit */ access = ap->auth_access; ap->auth_time = gethrestime_sec(); nfsauth_cache_hit++; } rw_exit(&exi->exi_cache_lock); if (ap) { kmem_free(addr.buf, addr.len); return (access); } nfsauth_cache_miss++; /* * No entry in the cache for this client/flavor * so we need to call the nfsauth service in the * mount daemon. */ retry: mutex_enter(&mountd_lock); dh = mountd_dh; if (dh) door_ki_hold(dh); mutex_exit(&mountd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet ! * This could mean that either mountd(1m) has not yet * been started or that _this_ routine nuked the door * handle after receiving an EINTR for a REVOKED door. * * Returning NFSAUTH_DROP will cause the NFS client * to retransmit the request, so let's try to be more * rescillient and attempt for ntries before we bail. */ if (++ntries % NFSAUTH_DR_TRYCNT) { delay(hz); goto retry; } sys_log("nfsauth: mountd has not established door"); kmem_free(addr.buf, addr.len); return (NFSAUTH_DROP); } ntries = 0; varg.vers = V_PROTO; varg.arg_u.arg.cmd = NFSAUTH_ACCESS; varg.arg_u.arg.areq.req_client.n_len = addr.len; varg.arg_u.arg.areq.req_client.n_bytes = addr.buf; varg.arg_u.arg.areq.req_netid = svc_getnetid(req->rq_xprt); varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; varg.arg_u.arg.areq.req_flavor = flavor; /* * Setup the XDR stream for encoding the arguments. Notice that * in addition to the args having variable fields (req_netid and * req_path), the argument data structure is itself versioned, * so we need to make sure we can size the arguments buffer * appropriately to encode all the args. If we can't get sizing * info _or_ properly encode the arguments, there's really no * point in continuting, so we fail the request. */ DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) { door_ki_rele(dh); kmem_free(addr.buf, addr.len); return (NFSAUTH_DENIED); } abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE); if (!xdr_varg(&xdrs_a, &varg)) { door_ki_rele(dh); goto fail; } XDR_DESTROY(&xdrs_a); /* * The result (nfsauth_res_t) is always two int's, so we don't * have to dynamically size (or allocate) the results buffer. * Now that we've got what we need, we prep the door arguments * and place the call. */ da.data_ptr = (char *)abuf; da.data_size = absz; da.desc_ptr = NULL; da.desc_num = 0; da.rbuf = (char *)rbuf; da.rsize = rbsz; switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { case 0: /* Success */ if (da.data_ptr != da.rbuf && da.data_size == 0) { /* * The door_return that contained the data * failed ! We're here because of the 2nd * door_return (w/o data) such that we can * get control of the thread (and exit * gracefully). */ DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, door_arg_t *, &da); door_ki_rele(dh); goto fail; } else if (rbuf != da.rbuf) {
/* * This function is not MultiThread safe. The caller has to make sure only one * thread calls this function. */ void smb_kshare_door_fini(door_handle_t dhdl) { if (dhdl) door_ki_rele(dhdl); }
/* ARGSUSED */ static int pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred, int *retval) { int rc; void *buf; size_t buf_size; pppt_iocdata_t iocd; door_handle_t new_handle; if (drv_priv(cred) != 0) { return (EPERM); } rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag); if (rc) return (EFAULT); if (iocd.pppt_version != PPPT_VERSION_1) return (EINVAL); switch (cmd) { case PPPT_MESSAGE: /* XXX limit buf_size ? */ buf_size = (size_t)iocd.pppt_buf_size; buf = kmem_alloc(buf_size, KM_SLEEP); if (buf == NULL) return (ENOMEM); rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf, buf, buf_size, flag); if (rc) { kmem_free(buf, buf_size); return (EFAULT); } stmf_ic_rx_msg(buf, buf_size); kmem_free(buf, buf_size); break; case PPPT_INSTALL_DOOR: new_handle = door_ki_lookup((int)iocd.pppt_door_fd); if (new_handle == NULL) return (EINVAL); mutex_enter(&pppt_global.global_door_lock); ASSERT(pppt_global.global_svc_state == PSS_ENABLED); if (pppt_global.global_door != NULL) { /* * There can only be one door installed */ mutex_exit(&pppt_global.global_door_lock); door_ki_rele(new_handle); return (EBUSY); } pppt_global.global_door = new_handle; mutex_exit(&pppt_global.global_door_lock); break; } return (rc); }
/* * log_event_upcall - Perform the upcall to syseventd for event buffer delivery. * Check for rebinding errors * This buffer is reused to by the syseventd door_return * to hold the result code */ static int log_event_upcall(log_event_upcall_arg_t *arg) { int error; size_t size; sysevent_t *ev; door_arg_t darg, save_arg; int retry; int neagain = 0; int neintr = 0; int nticks = LOG_EVENT_MIN_PAUSE; /* Initialize door args */ ev = (sysevent_t *)&arg->buf; size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev); darg.rbuf = (char *)arg; darg.data_ptr = (char *)arg; darg.rsize = size; darg.data_size = size; darg.desc_ptr = NULL; darg.desc_num = 0; LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n", (longlong_t)SE_SEQ((sysevent_t *)&arg->buf))); save_arg = darg; for (retry = 0; ; retry++) { mutex_enter(&event_door_mutex); if (event_door == NULL) { mutex_exit(&event_door_mutex); return (EBADF); } if ((error = door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0)) == 0) { mutex_exit(&event_door_mutex); break; } /* * EBADF is handled outside the switch below because we need to * hold event_door_mutex a bit longer */ if (error == EBADF) { /* Server died */ door_ki_rele(event_door); event_door = NULL; mutex_exit(&event_door_mutex); return (error); } mutex_exit(&event_door_mutex); /* * The EBADF case is already handled above with event_door_mutex * held */ switch (error) { case EINTR: neintr++; log_event_pause(2); darg = save_arg; break; case EAGAIN: /* cannot deliver upcall - process may be forking */ neagain++; log_event_pause(nticks); nticks <<= 1; if (nticks > LOG_EVENT_MAX_PAUSE) nticks = LOG_EVENT_MAX_PAUSE; darg = save_arg; break; default: cmn_err(CE_CONT, "log_event_upcall: door_ki_upcall error %d\n", error); return (error); } } if (neagain > 0 || neintr > 0) { LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n", neagain, neintr, nticks)); } LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t" "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n", error, (void *)arg, (void *)darg.rbuf, (void *)darg.data_ptr, *((int *)(darg.rbuf)), *((int *)(darg.data_ptr)))); if (!error) { /* * upcall was successfully executed. Check return code. */ error = *((int *)(darg.rbuf)); } return (error); }