static nss_status_t copy_output(void *outdata, int outdlen, nss_pheader_t *phdr, nss_pheader_t *outphdr) { void *dp; nss_status_t ret = NSS_SUCCESS; char *me = "copy_output"; if (outdata != NULL && phdr->data_off > 0 && phdr->data_len > 0) { if (phdr->data_len <= outdlen) { dp = (char *)phdr + phdr->data_off; (void) memmove(outdata, dp, phdr->data_len); } else { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "output buffer not large enough " " should be > %d but is %d\n", phdr->data_len, outdlen); if (outphdr != NULL) { NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_INVALID_ARGUMENT); NSCD_COPY_STATUS(outphdr, phdr); } ret = NSS_NSCD_PRIV; } } return (ret); }
nss_status_t _nscd_doorcall_data(int callnum, void *indata, int indlen, void *outdata, int outdlen, nss_pheader_t *phdr) { void *uptr; size_t buflen; void *dptr; void *datap; size_t ndata; size_t adata; nss_pheader_t *phdr_d; int ret; char *me = "_nscd_doorcall_data"; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "processing door call %d ...\n", callnum); /* allocate door buffer from the stack */ NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); dptr = uptr; ndata = buflen; adata = buflen; datap = NSCD_N2N_DOOR_DATA(void, dptr); if (indata != NULL) (void) memmove(datap, indata, indlen); ret = _nsc_trydoorcall(&dptr, &ndata, &adata); phdr_d = (nss_pheader_t *)dptr; if (ret != NSS_SUCCESS) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door call (%d) failed (status = %d, error = %s)\n", callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d))); } else { if (phdr != NULL) { NSCD_COPY_STATUS(phdr, phdr_d); } ret = copy_output(outdata, outdlen, phdr_d, phdr); } /* if new buffer allocated for this door call, free it */ if (dptr != uptr) (void) munmap(dptr, ndata); return (ret); }
void _nscd_proc_alt_get( void *buf, int *door) { int errnum; uid_t set2uid; gid_t set2gid; nss_pheader_t *phdr = (nss_pheader_t *)buf; char *me = "_nscd_proc_alt_get"; ucred_t *uc = NULL; child_t *ch; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "getting an alternate door ...\n"); /* make sure there is a door to talk to the forker */ if (forking_door == -1) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) (me, "no door to talk to the forker\n"); NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_FORKER); } /* get door client's credential information */ if (door_ucred(&uc) != 0) { errnum = errno; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "door_ucred failed: %s\n", strerror(errnum)); NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, NSCD_DOOR_UCRED_ERROR); } /* get door client's effective uid and effective gid */ set2uid = ucred_geteuid(uc); set2gid = ucred_getegid(uc); ucred_free(uc); uc = NULL; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "child uid = %d, gid = %d\n", set2uid, set2gid); /* is a slot available ? if not, no one to serve */ if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "no child slot available (child array = %p, slot = %d)\n", child, ch->child_slot); NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_CHILD_SLOT); } /* create the per user nscd if necessary */ if (ch->child_state != CHILD_STATE_PIDKNOWN) { nss_pheader_t phdr1; NSCD_CLEAR_STATUS(&phdr1); (void) mutex_lock(ch->mutex); if (ch->child_state == CHILD_STATE_UIDKNOWN) { /* ask forker to fork a new child */ selfcred_fork(&phdr1, forking_door, ch->child_slot, set2uid, set2gid); if (NSCD_STATUS_IS_NOT_OK(&phdr1)) { (void) mutex_unlock(ch->mutex); NSCD_COPY_STATUS(phdr, &phdr1); return; } ch->child_state = CHILD_STATE_FORKSENT; } _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "waiting for door (slot = %d, uid = %d, gid = %d)\n", ch->child_slot, set2uid, set2gid); /* wait for the per user nscd to become available */ while (ch->child_state == CHILD_STATE_FORKSENT) { timestruc_t to; int err; int ttl = 5; to.tv_sec = ttl; to.tv_nsec = 0; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "cond_reltimedwait %d seconds\n", ttl); err = cond_reltimedwait(ch->cond, ch->mutex, &to); if (err == ETIME) { ch->child_state = CHILD_STATE_UIDKNOWN; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "door wait timedout (slot = %d)\n", ch->child_slot); break; } } (void) mutex_unlock(ch->mutex); } if (ch->child_state != CHILD_STATE_PIDKNOWN) { NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_INVALID_SLOT_STATE); } *door = ch->child_door; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "returning door %d for slot %d, uid %d, gid = %d\n", *door, ch->child_slot, set2uid, set2gid); NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0); }
nss_status_t _nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen, void *outdata, int outdlen, nss_pheader_t *phdr) { void *uptr; void *dptr; void *datap; size_t ndata; size_t adata; size_t buflen; door_arg_t param; int ret, errnum; nss_pheader_t *phdr_d; char *me = "_nscd_doorcall_fd"; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "processing door call %d (fd = %d)...\n", callnum, fd); /* allocate door buffer from the stack */ NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); dptr = uptr; ndata = buflen; adata = buflen; datap = NSCD_N2N_DOOR_DATA(void, dptr); if (indata != NULL) (void) memmove(datap, indata, indlen); param.rbuf = (char *)dptr; param.rsize = ndata; param.data_ptr = (char *)dptr; param.data_size = adata; param.desc_ptr = NULL; param.desc_num = 0; ret = door_call(fd, ¶m); if (ret < 0) { errnum = errno; /* * door call did not get through, return errno * if requested */ if (phdr != NULL) { NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); } _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door call (%d to %d) did not get through (%s)\n", callnum, fd, strerror(errnum)); return (NSS_ERROR); } ndata = param.rsize; dptr = (void *)param.data_ptr; /* * door call got through, check if operation failed. * if so, return error info if requested */ phdr_d = (nss_pheader_t *)dptr; ret = NSCD_GET_STATUS(phdr_d); if (ret != NSS_SUCCESS) { if (phdr != NULL) { NSCD_COPY_STATUS(phdr, phdr_d); } _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door call (%d to %d) failed: p_status = %d, " "p_errno = %s, nscd status = %d\n", callnum, fd, ret, strerror(NSCD_GET_ERRNO(phdr_d)), NSCD_GET_NSCD_STATUS(phdr_d)); } else ret = copy_output(outdata, outdlen, phdr_d, phdr); /* if new buffer allocated for this door call, free it */ if (dptr != uptr) (void) munmap(dptr, param.rsize); return (ret); }