static void N2N_check_priv( void *buf, char *dc_str) { nss_pheader_t *phdr = (nss_pheader_t *)buf; ucred_t *uc = NULL; const priv_set_t *eset; zoneid_t zoneid; int errnum; char *me = "N2N_check_priv"; if (door_ucred(&uc) != 0) { errnum = errno; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door_ucred: %s\n", strerror(errno)); NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); } eset = ucred_getprivset(uc, PRIV_EFFECTIVE); zoneid = ucred_getzoneid(uc); if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : ucred_geteuid(uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) (me, "%s call failed(cred): caller pid %d, uid %d, " "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), ucred_getruid(uc), ucred_geteuid(uc), zoneid); ucred_free(uc); NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); } _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "nscd received %s cmd from pid %d, uid %d, " "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), ucred_getruid(uc), ucred_geteuid(uc), zoneid); ucred_free(uc); NSCD_RETURN_STATUS_SUCCESS(phdr); }
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); } }
/* * Check to see if we have the permissions to set scheduler parameters and * policy, based on Linux' demand that such commands fail with errno set to * EPERM if the current euid is not the euid or ruid of the process in * question. */ static int check_schedperms(pid_t pid) { size_t sz; ucred_t *cr; uid_t euid; euid = geteuid(); if (pid == getpid()) { /* * If we're the process to be checked, simply check the euid * against our ruid. */ if (euid != getuid()) return (-EPERM); return (0); } /* * We allocate a ucred_t ourselves rather than call ucred_get(3C) * because ucred_get() calls malloc(3C), which the brand library cannot * use. Because we allocate the space with SAFE_ALLOCA(), there's * no need to free it when we're done. */ sz = ucred_size(); cr = (ucred_t *)SAFE_ALLOCA(sz); if (cr == NULL) return (-ENOMEM); /* * If we can't access the process' credentials, fail with errno EPERM * as the call would not have succeeded anyway. */ if (syscall(SYS_ucredsys, UCREDSYS_UCREDGET, pid, cr) != 0) return ((errno == EACCES) ? -EPERM : -errno); if ((euid != ucred_geteuid(cr)) && (euid != ucred_getruid(cr))) return (-EPERM); return (0); }
static int ctrls_get_creds_peerucred(int sockfd, uid_t *uid, gid_t *gid) { ucred_t *cred = NULL; if (getpeerucred(sockfd, &cred) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 7, "error obtaining credentials using " "getpeerucred(3) on fd %d: %s", sockfd, strerror(xerrno)); errno = xerrno; return -1; } if (uid) *uid = ucred_getruid(cred); if (gid) *gid = ucred_getrgid(cred); ucred_free(cred); return 0; }
/* ARGSUSED */ void ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc) { ipmgmt_door_info_t *infop = NULL; ipmgmt_retval_t retval; int i; uint_t err; ucred_t *cred = NULL; for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) { if (i_ipmgmt_door_info_tbl[i].idi_cmd == ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) { infop = &i_ipmgmt_door_info_tbl[i]; break; } } if (infop == NULL) { ipmgmt_log(LOG_ERR, "Invalid door command specified"); err = EINVAL; goto fail; } /* check for solaris.network.interface.config authorization */ if (infop->idi_set) { uid_t uid; struct passwd pwd; char buf[1024]; if (door_ucred(&cred) != 0) { err = errno; ipmgmt_log(LOG_ERR, "Could not get user credentials."); goto fail; } uid = ucred_getruid(cred); if ((int)uid < 0) { err = errno; ipmgmt_log(LOG_ERR, "Could not get user id."); goto fail; } if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) { err = errno; ipmgmt_log(LOG_ERR, "Could not get password entry."); goto fail; } if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 1) { err = EPERM; ipmgmt_log(LOG_ERR, "Not authorized for operation."); goto fail; } ucred_free(cred); } /* individual handlers take care of calling door_return */ infop->idi_handler((void *)argp); return; fail: ucred_free(cred); retval.ir_err = err; (void) door_return((char *)&retval, sizeof (retval), NULL, 0); }
/* * build_mgmt_request -- extracts the request info from the given XML doc. * * x_doc: ptr to the request XML doc * req: ptr to the request struct to be filled up. * * Return value: ISNS_RSP_SUCCESSFUL if successful or an error code. */ static int process_mgmt_request(xmlDocPtr x_doc, request_t *req, ucred_t *uc) { result_code_t ret; int op; xmlXPathContextPtr ctext = NULL; uid_t user; struct passwd pwds, *pwd; char buf_pwd[1024]; isnslog(LOG_DEBUG, "process_mgmt_request", "entered"); (void) memset(req, 0, sizeof (request_t)); /* get the operation first. */ ctext = xmlXPathNewContext(x_doc); if (ctext == NULL) { return (ERR_XML_FAILED_TO_SET_XPATH_CONTEXT); } isnslog(LOG_DEBUG, "process_mgmt_request", "xpath context succeeded"); op = get_op_id_from_doc(ctext); if (op == -1) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_XML_VALID_OPERATION_NOT_FOUND); } user = ucred_getruid(uc); ret = getpwuid_r(user, &pwds, buf_pwd, sizeof (buf_pwd), &pwd); if (ret != 0) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_DOOR_SERVER_DETECTED_INVALID_USER); } /* write operations are restricted. */ if ((op == delete_op) || (op == createModify_op)) { if (!chkauthattr(ISNS_ADMIN_WRITE_AUTH, pwd->pw_name)) { if (ctext) xmlXPathFreeContext(ctext); return (ERR_DOOR_SERVER_DETECTED_NOT_AUTHORIZED_USER); } } req->op_info.op = op; if (ISNS_MGMT_OPERATION_TYPE_ENABLED()) { ISNS_MGMT_OPERATION_TYPE(op); } switch (op) { case (get_op): ret = process_get_request_from_doc(ctext, req); break; case (getAssociated_op): ret = process_getAssociated_request_from_doc(ctext, req); break; case (enumerate_op): ret = process_enumerate_request_from_doc(ctext, req); break; case (delete_op): ret = process_delete_request_from_doc(ctext, req); break; case (createModify_op): ret = process_createModify_request_from_doc(ctext, req); break; default: ret = ERR_XML_VALID_OPERATION_NOT_FOUND; } if (ctext) xmlXPathFreeContext(ctext); return (ret); }
void getpw_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) { int out_of_date; nsc_bucket_t *retb; char **bucket; static time_t lastmod; int bufferspace = maxsize - sizeof (nsc_return_t); if (current_admin.passwd.nsc_enabled == 0) { out->nsc_return_code = NOSERVER; out->nsc_bufferbytesused = sizeof (*out); return; } mutex_lock(&passwd_lock); if (current_admin.passwd.nsc_check_files) { struct stat buf; if (stat("/etc/passwd", &buf) < 0) { /*EMPTY*/; } else if (lastmod == 0) { lastmod = buf.st_mtime; } else if (lastmod < buf.st_mtime) { getpw_invalidate_unlocked(); lastmod = buf.st_mtime; } } if (current_admin.debug_level >= DBG_ALL) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { logit("getpw_lookup: looking for uid %d\n", in->nsc_u.uid); } else { logit("getpw_lookup: looking for name %s\n", in->nsc_u.name); } } for (;;) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { bucket = get_hash(uid_hash, (char *)in->nsc_u.uid); } else { /* make reasonableness check here */ if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { ucred_t *uc = NULL; if (door_ucred(&uc) != 0) { logit("getpw_lookup: Name too long, " "but no user credential: %s\n", strerror(errno)); } else { logit("getpw_lookup: Name too long " "from pid %d uid %d\n", ucred_getpid(uc), ucred_getruid(uc)); ucred_free(uc); } out->nsc_errno = NSS_NOTFOUND; out->nsc_return_code = NOTFOUND; out->nsc_bufferbytesused = sizeof (*out); goto getout; } bucket = get_hash(nam_hash, in->nsc_u.name); } if (*bucket == (char *)-1) { /* pending lookup */ if (get_clearance(in->nsc_callnumber) != 0) { /* no threads available */ out->nsc_return_code = NOSERVER; /* cannot process now */ out->nsc_bufferbytesused = sizeof (*out); current_admin.passwd.nsc_throttle_count++; goto getout; } nscd_wait(&passwd_wait, &passwd_lock, bucket); release_clearance(in->nsc_callnumber); continue; /* go back and relookup hash bucket */ } break; } /* * check for no name_service mode */ if (*bucket == NULL && current_admin.avoid_nameservice) { out->nsc_return_code = NOTFOUND; out->nsc_bufferbytesused = sizeof (*out); } else if (*bucket == NULL || (in->nsc_callnumber & UPDATEBIT) || (out_of_date = (!current_admin.avoid_nameservice && (current_admin.passwd.nsc_old_data_ok == 0) && (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { /* * time has expired */ int saved_errno; int saved_hits = 0; struct passwd *p; if (get_clearance(in->nsc_callnumber) != 0) { /* no threads available */ out->nsc_return_code = NOSERVER; /* cannot process now */ out->nsc_bufferbytesused = sizeof (*out); current_admin.passwd.nsc_throttle_count++; goto getout; } if (*bucket != NULL) { saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; } /* * block any threads accessing this bucket if data * is non-existent or out of date */ if (*bucket == NULL || out_of_date) { update_pw_bucket((nsc_bucket_t **)bucket, (nsc_bucket_t *)-1, in->nsc_callnumber); } else { /* * if still not -1 bucket we are doing * update... mark to prevent pileups of threads if * the name service is hanging.. */ ((nsc_bucket_t *)(*bucket))->nsc_status |= ST_UPDATE_PENDING; /* cleared by deletion of old data */ } mutex_unlock(&passwd_lock); if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { p = _uncached_getpwuid_r(in->nsc_u.uid, &out->nsc_u.pwd, out->nsc_u.buff+sizeof (struct passwd), bufferspace); saved_errno = errno; } else { p = _uncached_getpwnam_r(in->nsc_u.name, &out->nsc_u.pwd, out->nsc_u.buff+sizeof (struct passwd), bufferspace); saved_errno = errno; } mutex_lock(&passwd_lock); release_clearance(in->nsc_callnumber); if (p == NULL) { /* data not found */ if (current_admin.debug_level >= DBG_CANT_FIND) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { logit("getpw_lookup: nscd COULDN'T FIND uid %d\n", in->nsc_u.uid); } else { logit("getpw_lookup: nscd COULDN'T FIND passwd name %s\n", in->nsc_u.name); } } if (!(UPDATEBIT & in->nsc_callnumber)) current_admin.passwd.nsc_neg_cache_misses++; retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); retb->nsc_refcount = 1; retb->nsc_data.nsc_bufferbytesused = sizeof (nsc_return_t); retb->nsc_data.nsc_return_code = NOTFOUND; retb->nsc_data.nsc_errno = saved_errno; memcpy(out, &retb->nsc_data, retb->nsc_data.nsc_bufferbytesused); update_pw_bucket((nsc_bucket_t **)bucket, retb, in->nsc_callnumber); goto getout; } else { if (current_admin.debug_level >= DBG_ALL) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { logit("getpw_lookup: nscd FOUND uid %d\n", in->nsc_u.uid); } else { logit("getpw_lookup: nscd FOUND passwd name %s\n", in->nsc_u.name); } } if (!(UPDATEBIT & in->nsc_callnumber)) current_admin.passwd.nsc_pos_cache_misses++; retb = fixbuffer(out, bufferspace); update_pw_bucket((nsc_bucket_t **)bucket, retb, in->nsc_callnumber); if (saved_hits) retb->nsc_hits = saved_hits; } } else { /* found entry in cache */ retb = (nsc_bucket_t *)*bucket; retb->nsc_hits++; memcpy(out, &(retb->nsc_data), retb->nsc_data.nsc_bufferbytesused); if (out->nsc_return_code == SUCCESS) { if (!(UPDATEBIT & in->nsc_callnumber)) current_admin.passwd.nsc_pos_cache_hits++; if (current_admin.debug_level >= DBG_ALL) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { logit("getpw_lookup: found uid %d in cache\n", in->nsc_u.uid); } else { logit("getpw_lookup: found name %s in cache\n", in->nsc_u.name); } } } else { if (!(UPDATEBIT & in->nsc_callnumber)) current_admin.passwd.nsc_neg_cache_hits++; if (current_admin.debug_level >= DBG_ALL) { if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { logit("getpw_lookup: %d marked as NOT FOUND in cache.\n", in->nsc_u.uid); } else { logit("getpw_lookup: %s marked as NOT FOUND in cache.\n", in->nsc_u.name); } } } if ((retb->nsc_timestamp < now) && !(in->nsc_callnumber & UPDATEBIT) && !(retb->nsc_status & ST_UPDATE_PENDING)) { logit("launch update since time = %d\n", retb->nsc_timestamp); retb->nsc_status |= ST_UPDATE_PENDING; /* cleared by deletion of old data */ launch_update(in); } } getout: mutex_unlock(&passwd_lock); /* * secure mode check - blank out passwd if call sucessfull * and caller != effective id */ if ((current_admin.passwd.nsc_secure_mode != 0) && (out->nsc_return_code == SUCCESS) && !(UPDATEBIT & in->nsc_callnumber)) { ucred_t *uc = NULL; if (door_ucred(&uc) != 0) { perror("door_ucred"); } else { if (ucred_geteuid(uc) != out->nsc_u.pwd.pw_uid) { /* * write *NP* into passwd field if * not already that way... we fixed * the buffer code so there's always room. */ int len; char *foo = out->nsc_u.buff + sizeof (struct passwd) + (int)out->nsc_u.pwd.pw_passwd; len = strlen(foo); if (len > 0 && strcmp(foo, "*NP*") != 0 && strcmp(foo, "x") != 0) { if (len < 5) len = 5; strncpy(foo, "*NP*", len); /* * strncpy will * blank all */ } } ucred_free(uc); } } }
/*ARGSUSED*/ void iod_dispatch(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc) { smb_iod_ssn_t *ssn; ucred_t *ucred; uid_t cl_uid; int rc; /* * Verify that the calling process has the same UID. * Paranoia: The door we created has mode 0600, so * this check is probably redundant. */ ucred = NULL; if (door_ucred(&ucred) != 0) { rc = EACCES; goto out; } cl_uid = ucred_getruid(ucred); ucred_free(ucred); ucred = NULL; if (cl_uid != getuid()) { DPRINT("iod_dispatch: wrong UID\n"); rc = EACCES; goto out; } /* * The library uses a NULL arg call to check if * the deamon is running. Just return zero. */ if (argp == NULL) { rc = 0; goto out; } /* * Otherwise, the arg must be the (fixed size) * smb_iod_ssn_t */ if (argsz != sizeof (*ssn)) { rc = EINVAL; goto out; } mutex_lock(&iod_mutex); if (iod_terminating) { mutex_unlock(&iod_mutex); DPRINT("iod_dispatch: terminating\n"); rc = EINTR; goto out; } if (iod_thr_count++ == 0) { alarm(0); DPRINT("iod_dispatch: cancelled alarm\n"); } mutex_unlock(&iod_mutex); ssn = (void *) argp; rc = iod_newvc(ssn); mutex_lock(&iod_mutex); if (--iod_thr_count == 0) { DPRINT("iod_dispatch: schedule alarm\n"); alarm(ALARM_TIME); } mutex_unlock(&iod_mutex); out: door_return((void *)&rc, sizeof (rc), NULL, 0); }
/* * Accept a new client request. A struct ilbd_client_t is allocated to * store the client info. The accepted socket is port_associate() with * the given port. And the allocated ilbd_client_t struct is passed as * the user pointer. */ static void new_req(int ev_port, int listener, void *ev_obj) { struct sockaddr sa; int sa_len; int new_sd; int sflags; ilbd_client_t *cli; int res; uid_t uid; sa_len = sizeof (sa); if ((new_sd = accept(listener, &sa, &sa_len)) == -1) { /* don't log if we're out of file descriptors */ if (errno != EINTR && errno != EMFILE) logperror("new_req: accept failed"); goto done; } /* Set the new socket to be non-blocking. */ if ((sflags = fcntl(new_sd, F_GETFL, 0)) == -1) { logperror("new_req: fcntl(F_GETFL)"); goto clean_up; } if (fcntl(new_sd, F_SETFL, sflags | O_NONBLOCK) == -1) { logperror("new_req: fcntl(F_SETFL)"); goto clean_up; } if (fcntl(new_sd, F_SETFD, FD_CLOEXEC) == -1) { logperror("new_req: fcntl(FD_CLOEXEC)"); goto clean_up; } if ((cli = calloc(1, sizeof (ilbd_client_t))) == NULL) { logerr("new_req: malloc(ilbd_client_t)"); goto clean_up; } res = getpeerucred(new_sd, &cli->cli_peer_ucredp); if (res == -1) { logperror("new_req: getpeerucred failed"); goto clean_up; } if ((uid = ucred_getruid(cli->cli_peer_ucredp)) == (uid_t)-1) { logperror("new_req: ucred_getruid failed"); goto clean_up; } cli->cli_pw_bufsz = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX); if ((cli->cli_pw_buf = malloc(cli->cli_pw_bufsz)) == NULL) { free(cli); logerr("new_req: malloc(cli_pw_buf)"); goto clean_up; } if (getpwuid_r(uid, &cli->cli_pw, cli->cli_pw_buf, cli->cli_pw_bufsz) == NULL) { free(cli->cli_pw_buf); free(cli); logperror("new_req: invalid user"); goto clean_up; } cli->cli_ev = ILBD_EVENT_REQ; cli->cli_sd = new_sd; cli->cli_cmd = ILBD_BAD_CMD; cli->cli_saved_reply = NULL; cli->cli_saved_size = 0; if (port_associate(ev_port, PORT_SOURCE_FD, new_sd, POLLRDNORM, cli) == -1) { logperror("new_req: port_associate(cli) failed"); free(cli->cli_pw_buf); free(cli); clean_up: (void) close(new_sd); } done: /* Re-associate the listener with the event port. */ if (port_associate(ev_port, PORT_SOURCE_FD, listener, POLLRDNORM, ev_obj) == -1) { logperror("new_req: port_associate(listener) failed"); exit(1); } }