void _nscd_APP_check_cred( void *buf, pid_t *pidp, char *dc_str, int log_comp, int log_level) { nss_pheader_t *phdr = (nss_pheader_t *)buf; ucred_t *uc = NULL; uid_t ruid; uid_t euid; pid_t pid; int errnum; char *me = "_nscd_APP_check_cred"; if (door_ucred(&uc) != 0) { errnum = errno; _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR) (me, "door_ucred: %s\n", strerror(errno)); NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); } NSCD_SET_STATUS_SUCCESS(phdr); pid = ucred_getpid(uc); if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc), euid = ucred_geteuid(uc))) { if (pidp != NULL) { if (*pidp == (pid_t)-1) *pidp = pid; else if (*pidp != pid) { NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); } } } else { NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); } ucred_free(uc); if (NSCD_STATUS_IS_NOT_OK(phdr)) { _NSCD_LOG(log_comp, log_level) (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, " "euid %d, header ruid %d, header euid %d\n", dc_str, pid, (pidp != NULL) ? *pidp : -1, ruid, euid, ((nss_pheader_t *)(buf))->p_ruid, ((nss_pheader_t *)(buf))->p_euid); } }
static void send_doorfd(void **dptr, size_t *ndata, size_t *adata, door_desc_t *pdesc) { nss_pheader_t *phdr = (nss_pheader_t *)*dptr; door_arg_t param; int ret; int doorfd; int errnum; char *me = "send_doorfd"; initdoor(*dptr, &doorfd); if (NSCD_STATUS_IS_NOT_OK(phdr)) return; param.rbuf = (char *)*dptr; param.rsize = *ndata; param.data_ptr = (char *)*dptr; param.data_size = *adata; param.desc_ptr = pdesc; param.desc_num = 1; ret = door_call(doorfd, ¶m); if (ret < 0) { errnum = errno; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door call (to fd %d) failed (%s)\n", doorfd, strerror(errnum)); (void) close(doorfd); NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); return; } *adata = param.data_size; *ndata = param.rsize; *dptr = (void *)param.data_ptr; if (*adata == 0 || *dptr == NULL) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "no data\n"); NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTCONN); } (void) close(doorfd); }
static void initdoor(void *buf, int *doorfd) { nss_pheader_t *phdr = (nss_pheader_t *)buf; door_info_t doori; char *me = "initdoor"; *doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0); _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door is %s (fd is %d)\n", NAME_SERVICE_DOOR, *doorfd); if (*doorfd == -1) { NSCD_SET_STATUS(phdr, NSS_ERROR, errno); return; } if (door_info(*doorfd, &doori) < 0 || (doori.di_attributes & DOOR_REVOKED) || doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { /* * we should close doorfd because we just opened it */ (void) close(*doorfd); _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door %d not valid\n", *doorfd); NSCD_SET_STATUS(phdr, NSS_ERROR, ECONNREFUSED); return; } NSCD_SET_STATUS_SUCCESS(phdr); }
/* * Check to see if all conditions are met for processing per-user * requests. Returns 1 if yes, -1 if backend is not configured, * 0 otherwise. */ static int need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist) { nss_pheader_t *phdr = (nss_pheader_t *)buf; NSCD_SET_STATUS_SUCCESS(phdr); /* if already a per-user nscd, no need to get per-user door */ if (whoami == NSCD_CHILD) return (0); /* forker shouldn't be asked */ if (whoami == NSCD_FORKER) { NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); return (0); } /* if door client is root, no need for a per-user door */ if (uid == 0) return (0); /* * if per-user lookup is not configured, no per-user * door available */ if (_nscd_is_self_cred_on(0, dblist) == 0) return (-1); /* * if per-user lookup is not configured for the db, * don't bother */ if (is_db_per_user(phdr, *dblist) == 0) return (0); return (1); }
/* log error and return -1 when an invalid packed buffer header is found */ static int pheader_error(nss_pheader_t *phdr, uint32_t call_number) { char *call_num_str; switch (call_number) { case NSCD_SEARCH: call_num_str = "NSCD_SEARCH"; break; case NSCD_SETENT: call_num_str = "NSCD_SETENT"; break; case NSCD_GETENT: call_num_str = "NSCD_GETENT"; break; case NSCD_ENDENT: call_num_str = "NSCD_ENDENT"; break; case NSCD_PUT: call_num_str = "NSCD_PUT"; break; case NSCD_GETHINTS: call_num_str = "NSCD_GETHINTS"; break; default: call_num_str = "UNKNOWN"; break; } _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) ("pheader_error", "call number %s: invalid packed buffer header\n", call_num_str); NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); return (-1); }
void _nscd_proc_iamhere( void *buf, door_desc_t *dp, uint_t n_desc, int iam) { int cslot; child_t *ch; int errnum; ucred_t *uc = NULL; uid_t uid; nscd_imhere_t *ih; nss_pheader_t *phdr = (nss_pheader_t *)buf; char *me = "_nscd_proc_iamhere"; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "%d receives iamhere from %d\n", _whoami, iam); 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); } uid = ucred_geteuid(uc); switch (iam) { case NSCD_MAIN: if (_whoami == NSCD_MAIN || uid != main_uid) { /* * I'm main, or uid from door is not correct, * this must be an imposter */ _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "MAIN IMPOSTER CAUGHT!\n"); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_MAIN_IMPOSTER); } break; case NSCD_FORKER: if (_whoami == NSCD_FORKER || uid != forker_uid) { /* * I'm forker, or uid from door is not correct, * this must be an imposter */ _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "FORKER IMPOSTER CAUGHT!\n"); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_FORKER_IMPOSTER); break; } /* only main needs to know the forker */ if (_whoami != NSCD_MAIN) { NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_WRONG_NSCD); break; } if (ucred_getpid(uc) != forker_pid) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n", ucred_getpid(uc), forker_pid); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_FORKER_IMPOSTER); break; } if (n_desc < 1) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "BAD FORKER, NO DOOR!\n"); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_DOOR); break; } if ((dp->d_attributes & DOOR_DESCRIPTOR) && dp->d_data.d_desc.d_descriptor > 0 && dp->d_data.d_desc.d_id != 0) { (void) mutex_lock(&forking_lock); if (forking_door != -1) (void) close(forking_door); forking_door = dp->d_data.d_desc.d_descriptor; (void) mutex_unlock(&forking_lock); _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "forking door is %d\n", forking_door); NSCD_SET_STATUS_SUCCESS(phdr); } else { NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); break; } /* monitor the forker nscd */ (void) thr_create(NULL, 0, forker_monitor, NULL, THR_DETACHED, NULL); break; case NSCD_CHILD: if (_whoami != NSCD_MAIN) { /* child nscd can only talk to the main nscd */ _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "CHILD IMPOSTER CAUGHT!\n"); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_CHILD_IMPOSTER); break; } /* get the main nscd assigned slot number */ ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf); cslot = ih->slot; (void) mutex_lock(&child_lock); if (cslot < 0 || cslot >= max_pu_nscd) ch = NULL; else ch = child[cslot]; (void) mutex_unlock(&child_lock); if (ch == NULL) { /* Bad slot number */ _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "bad slot number %d\n", cslot); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_INVALID_SLOT_NUMBER); break; } if (uid != ch->child_uid) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n", uid, ch->child_uid); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_CHILD_IMPOSTER); break; } if (ch->child_state != CHILD_STATE_UIDKNOWN && ch->child_state != CHILD_STATE_FORKSENT) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "invalid slot/child state (%d) for uid %d\n", ch->child_state, uid); NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_INVALID_SLOT_STATE); break; } _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "d_descriptor = %d, d_id = %lld\n", dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id); if ((dp->d_attributes & DOOR_DESCRIPTOR) && dp->d_data.d_desc.d_descriptor > 0 && dp->d_data.d_desc.d_id != 0) { (void) mutex_lock(ch->mutex); if (ch->child_door != -1) (void) close(ch->child_door); ch->child_door = dp->d_data.d_desc.d_descriptor; ch->child_pid = ucred_getpid(uc); ch->child_state = CHILD_STATE_PIDKNOWN; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "child in slot %d has door %d\n", cslot, ch->child_door); /* * let waiters know that the child is ready to * serve */ (void) cond_broadcast(ch->cond); (void) mutex_unlock(ch->mutex); /* monitor the child nscd */ (void) thr_create(NULL, 0, child_monitor, ch, THR_DETACHED, NULL); NSCD_SET_STATUS_SUCCESS(phdr); break; } else { NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); } break; } ucred_free(uc); uc = NULL; }
/*ARGSUSED*/ static void switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, uint_t n_desc) { int iam; pid_t ent_pid = -1; nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); void *uptr; int len; size_t buflen; int callnum; char *me = "switcher"; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "switcher ...\n"); if (argp == DOOR_UNREF_DATA) { (void) printf("Door Slam... exiting\n"); exit(0); } if (argp == NULL) { /* empty door call */ (void) door_return(NULL, 0, 0, 0); /* return the favor */ } /* * need to restart if main nscd and config file(s) changed */ if (_whoami == NSCD_MAIN) _nscd_restart_if_cfgfile_changed(); if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { /* make sure the packed buffer header is good */ if (validate_pheader(argp, arg_size, phdr->nsc_callnumber) == -1) (void) door_return(argp, arg_size, NULL, 0); switch (phdr->nsc_callnumber) { case NSCD_SEARCH: /* if a fallback to main nscd, skip per-user setup */ if (phdr->p_status != NSS_ALTRETRY) if_selfcred_return_per_user_door(argp, arg_size, dp, _whoami); lookup(argp, arg_size); break; case NSCD_SETENT: _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT", NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT); if (NSCD_STATUS_IS_OK(phdr)) { if_selfcred_return_per_user_door(argp, arg_size, dp, _whoami); nss_psetent(argp, arg_size, ent_pid); } break; case NSCD_GETENT: getent(argp, arg_size); break; case NSCD_ENDENT: nss_pendent(argp, arg_size); break; case NSCD_PUT: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door call NSCD_PUT not supported yet\n"); NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); break; case NSCD_GETHINTS: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door call NSCD_GETHINTS not supported yet\n"); NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "Unknown name service door call op %x\n", phdr->nsc_callnumber); NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); break; } (void) door_return(argp, arg_size, NULL, 0); } iam = NSCD_MAIN; callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; if (callnum == NSCD_IMHERE || callnum == NSCD_PULSE || callnum == NSCD_FORK) iam = phdr->nsc_callnumber & NSCD_WHOAMI; else callnum = phdr->nsc_callnumber; /* nscd -> nscd v2 calls */ /* make sure the buffer is good */ if (validate_N2Nbuf(argp, arg_size, callnum) == -1) (void) door_return(argp, arg_size, NULL, 0); switch (callnum) { case NSCD_PING: NSCD_SET_STATUS_SUCCESS(phdr); break; case NSCD_IMHERE: _nscd_proc_iamhere(argp, dp, n_desc, iam); break; case NSCD_PULSE: N2N_check_priv(argp, "NSCD_PULSE"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_proc_pulse(argp, iam); break; case NSCD_FORK: N2N_check_priv(argp, "NSCD_FORK"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_proc_fork(argp, iam); break; case NSCD_KILL: N2N_check_priv(argp, "NSCD_KILL"); if (NSCD_STATUS_IS_OK(phdr)) exit(0); break; case NSCD_REFRESH: N2N_check_priv(argp, "NSCD_REFRESH"); if (NSCD_STATUS_IS_OK(phdr)) { if (_nscd_refresh() != NSCD_SUCCESS) exit(1); NSCD_SET_STATUS_SUCCESS(phdr); } break; case NSCD_GETPUADMIN: if (_nscd_is_self_cred_on(0, NULL)) { _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); } else { NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NOT_CONFIGURED); } break; case NSCD_GETADMIN: len = _nscd_door_getadmin((void *)argp); if (len == 0) break; /* size of door buffer not big enough, allocate one */ NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); /* copy packed header */ *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); /* set new buffer size */ ((nss_pheader_t *)uptr)->pbufsiz = buflen; /* try one more time */ (void) _nscd_door_getadmin((void *)uptr); (void) door_return(uptr, buflen, NULL, 0); break; case NSCD_SETADMIN: N2N_check_priv(argp, "NSCD_SETADMIN"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_door_setadmin(argp); break; case NSCD_KILLSERVER: N2N_check_priv(argp, "NSCD_KILLSERVER"); if (NSCD_STATUS_IS_OK(phdr)) { /* also kill the forker nscd if one is running */ _nscd_kill_forker(); exit(0); } break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "Unknown name service door call op %d\n", phdr->nsc_callnumber); NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); (void) door_return(argp, arg_size, NULL, 0); break; } (void) door_return(argp, arg_size, NULL, 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); }