int sss_cmd_get_version(struct cli_ctx *cctx) { uint8_t *req_body; size_t req_blen; uint8_t *body; size_t blen; int ret; uint32_t client_version; int i; static struct cli_protocol_version *cli_protocol_version = NULL; cctx->cli_protocol_version = NULL; if (cli_protocol_version == NULL) { cli_protocol_version = register_cli_protocol_version(); } if (cli_protocol_version != NULL) { cctx->cli_protocol_version = &cli_protocol_version[0]; sss_packet_get_body(cctx->creq->in, &req_body, &req_blen); if (req_blen == sizeof(uint32_t)) { memcpy(&client_version, req_body, sizeof(uint32_t)); DEBUG(5, ("Received client version [%d].\n", client_version)); i=0; while(cli_protocol_version[i].version>0) { if (cli_protocol_version[i].version == client_version) { cctx->cli_protocol_version = &cli_protocol_version[i]; break; } i++; } } } /* create response packet */ ret = sss_packet_new(cctx->creq, sizeof(uint32_t), sss_packet_get_cmd(cctx->creq->in), &cctx->creq->out); if (ret != EOK) { return ret; } sss_packet_get_body(cctx->creq->out, &body, &blen); ((uint32_t *)body)[0] = cctx->cli_protocol_version!=NULL ? cctx->cli_protocol_version->version : 0; DEBUG(5, ("Offered version [%d].\n", ((uint32_t *)body)[0])); sss_cmd_done(cctx, NULL); return EOK; }
int sss_cmd_empty_packet(struct sss_packet *packet) { uint8_t *body; size_t blen; int ret; ret = sss_packet_grow(packet, 2*sizeof(uint32_t)); if (ret != EOK) return ret; sss_packet_get_body(packet, &body, &blen); ((uint32_t *)body)[0] = 0; /* num results */ ((uint32_t *)body)[1] = 0; /* reserved */ return EOK; }
errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd) { uint8_t *body; size_t blen; errno_t ret; uint32_t terminator; sss_packet_get_body(cctx->creq->in, &body, &blen); if (blen >= sizeof(uint32_t)) { SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL); if (terminator != SSS_END_OF_PAM_REQUEST) { DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n"); ret = EINVAL; goto done; } } switch (cctx->cli_protocol_version->version) { case 1: ret = pam_parse_in_data(cctx->rctx->domains, cctx->rctx->default_domain, pd, body, blen); break; case 2: ret = pam_parse_in_data_v2(cctx->rctx->domains, cctx->rctx->default_domain, pd, body, blen); break; case 3: ret = pam_parse_in_data_v3(cctx->rctx->domains, cctx->rctx->default_domain, pd, body, blen); break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n", cctx->cli_protocol_version->version); ret = EINVAL; } done: return ret; }
errno_t nss_protocol_fill_sid(struct nss_ctx *nss_ctx, struct nss_cmd_ctx *cmd_ctx, struct sss_packet *packet, struct cache_req_result *result) { struct ldb_message *msg = result->msgs[0]; struct sized_string sz_sid; enum sss_id_type id_type; const char *sid; size_t rp = 0; size_t body_len; uint8_t *body; errno_t ret; ret = nss_get_id_type(cmd_ctx, result, &id_type); if (ret != EOK) { return ret; } sid = ldb_msg_find_attr_as_string(msg, SYSDB_SID_STR, NULL); if (sid == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing SID.\n"); return EINVAL; } to_sized_string(&sz_sid, sid); ret = sss_packet_grow(packet, sz_sid.len + 3 * sizeof(uint32_t)); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); return ret; } sss_packet_get_body(packet, &body, &body_len); SAFEALIGN_SET_UINT32(&body[rp], 1, &rp); /* Num results. */ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ SAFEALIGN_SET_UINT32(&body[rp], id_type, &rp); SAFEALIGN_SET_STRING(&body[rp], sz_sid.str, sz_sid.len, &rp); return EOK; }
static errno_t sudosrv_cmd_send_reply(struct sudo_cmd_ctx *cmd_ctx, uint8_t *response_body, size_t response_len) { errno_t ret; uint8_t *packet_body = NULL; size_t packet_len = 0; struct cli_ctx *cli_ctx = cmd_ctx->cli_ctx; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; ret = sss_packet_new(cli_ctx->creq, 0, sss_packet_get_cmd(cli_ctx->creq->in), &cli_ctx->creq->out); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create a new packet [%d]; %s\n", ret, strerror(ret)); goto done; } ret = sss_packet_grow(cli_ctx->creq->out, response_len); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create response: %s\n", strerror(ret)); goto done; } sss_packet_get_body(cli_ctx->creq->out, &packet_body, &packet_len); memcpy(packet_body, response_body, response_len); sss_packet_set_error(cli_ctx->creq->out, EOK); sss_cmd_done(cmd_ctx->cli_ctx, cmd_ctx); ret = EOK; done: talloc_zfree(tmp_ctx); return ret; }
static void pam_reply(struct pam_auth_req *preq) { struct cli_ctx *cctx; uint8_t *body; size_t blen; int ret; int32_t resp_c; int32_t resp_size; struct response_data *resp; int p; struct timeval tv; struct tevent_timer *te; struct pam_data *pd; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; time_t delay_until = -1; pd = preq->pd; cctx = preq->cctx; pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); DEBUG(SSSDBG_FUNC_DATA, "pam_reply called with result [%d].\n", pd->pam_status); if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) { switch(pd->cmd) { case SSS_PAM_AUTHENTICATE: if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { const char *password = NULL; /* do auth with offline credentials */ pd->offline_auth = true; if (preq->domain->sysdb == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Fatal: Sysdb CTX not found for domain" " [%s]!\n", preq->domain->name); goto done; } ret = sss_authtok_get_password(pd->authtok, &password, NULL); if (ret) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n"); goto done; } ret = sysdb_cache_auth(preq->domain, pd->user, password, pctx->rctx->cdb, false, &exp_date, &delay_until); pam_handle_cached_login(preq, ret, exp_date, delay_until); return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: case SSS_PAM_CHAUTHTOK: DEBUG(SSSDBG_FUNC_DATA, "Password change not possible while offline.\n"); pd->pam_status = PAM_AUTHTOK_ERR; user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), (const uint8_t *) &user_info_type); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); goto done; } break; /* TODO: we need the pam session cookie here to make sure that cached * authentication was successful */ case SSS_PAM_SETCRED: case SSS_PAM_ACCT_MGMT: case SSS_PAM_OPEN_SESSION: case SSS_PAM_CLOSE_SESSION: DEBUG(SSSDBG_OP_FAILURE, "Assuming offline authentication setting status for " "pam call %d to PAM_SUCCESS.\n", pd->cmd); pd->pam_status = PAM_SUCCESS; break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM call [%d].\n", pd->cmd); pd->pam_status = PAM_MODULE_UNKNOWN; } } if (pd->response_delay > 0) { ret = gettimeofday(&tv, NULL); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "gettimeofday failed [%d][%s].\n", errno, strerror(errno)); goto done; } tv.tv_sec += pd->response_delay; tv.tv_usec = 0; pd->response_delay = 0; te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq); if (te == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add event pam_reply_delay.\n"); goto done; } return; } /* If this was a successful login, save the lastLogin time */ if (pd->cmd == SSS_PAM_AUTHENTICATE && pd->pam_status == PAM_SUCCESS && preq->domain->cache_credentials && !pd->offline_auth && !pd->last_auth_saved && NEED_CHECK_PROVIDER(preq->domain->provider)) { ret = set_last_login(preq); if (ret != EOK) { goto done; } return; } ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), &cctx->creq->out); if (ret != EOK) { goto done; } ret = filter_responses(pctx->rctx->cdb, pd->resp_list); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n"); } if (pd->domain != NULL) { ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1, (uint8_t *) pd->domain); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); goto done; } } resp_c = 0; resp_size = 0; resp = pd->resp_list; while(resp != NULL) { if (!resp->do_not_send_to_client) { resp_c++; resp_size += resp->len; } resp = resp->next; } ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) + sizeof(int32_t) + resp_c * 2* sizeof(int32_t) + resp_size); if (ret != EOK) { goto done; } sss_packet_get_body(cctx->creq->out, &body, &blen); DEBUG(SSSDBG_FUNC_DATA, "blen: %zu\n", blen); p = 0; memcpy(&body[p], &pd->pam_status, sizeof(int32_t)); p += sizeof(int32_t); memcpy(&body[p], &resp_c, sizeof(int32_t)); p += sizeof(int32_t); resp = pd->resp_list; while(resp != NULL) { if (!resp->do_not_send_to_client) { memcpy(&body[p], &resp->type, sizeof(int32_t)); p += sizeof(int32_t); memcpy(&body[p], &resp->len, sizeof(int32_t)); p += sizeof(int32_t); memcpy(&body[p], resp->data, resp->len); p += resp->len; } resp = resp->next; } done: sss_cmd_done(cctx, preq); }
static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx) { struct tevent_req *req = NULL; struct sudo_cmd_ctx *cmd_ctx = NULL; uint8_t *query_body = NULL; size_t query_len = 0; uint32_t protocol = cli_ctx->cli_protocol_version->version; errno_t ret; /* create cmd_ctx */ cmd_ctx = talloc_zero(cli_ctx, struct sudo_cmd_ctx); if (cmd_ctx == NULL) { /* kill the connection here as we have no context for reply */ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n"); return ENOMEM; } cmd_ctx->cli_ctx = cli_ctx; cmd_ctx->type = type; cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct sudo_ctx); if (cmd_ctx->sudo_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "sudo_ctx not set, killing connection!\n"); return EFAULT; } /* if protocol is invalid return */ switch (protocol) { case 0: DEBUG(SSSDBG_FATAL_FAILURE, "Protocol [%d] is not secure. " "SSSD does not allow to use this protocol.\n", protocol); ret = EFAULT; goto done; break; case SSS_SUDO_PROTOCOL_VERSION: DEBUG(SSSDBG_TRACE_INTERNAL, "Using protocol version [%d]\n", protocol); break; default: DEBUG(SSSDBG_FATAL_FAILURE, "Invalid protocol version [%d]!\n", protocol); ret = EFAULT; goto done; } /* parse query */ sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_len); if (query_len <= 0 || query_body == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Query is empty\n"); ret = EINVAL; goto done; } ret = sudosrv_parse_query(cmd_ctx, query_body, query_len, &cmd_ctx->rawname, &cmd_ctx->uid); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse sudo query [%d]: %s\n", ret, sss_strerror(ret)); goto done; } req = sudosrv_get_rules_send(cmd_ctx, cli_ctx->ev, cmd_ctx->sudo_ctx, cmd_ctx->type, cmd_ctx->uid, cmd_ctx->rawname); if (req == NULL) { ret = ENOMEM; goto done; } tevent_req_set_callback(req, sudosrv_cmd_done, cmd_ctx); ret = EAGAIN; done: return sudosrv_cmd_reply(cmd_ctx, ret); }
errno_t nss_protocol_fill_pwent(struct nss_ctx *nss_ctx, struct nss_cmd_ctx *cmd_ctx, struct sss_packet *packet, struct cache_req_result *result) { TALLOC_CTX *tmp_ctx; struct ldb_message *msg; struct sized_string pwfield; struct sized_string *name; struct sized_string gecos; struct sized_string homedir; struct sized_string shell; uint32_t gid; uint32_t uid; uint32_t num_results; size_t rp; size_t body_len; uint8_t *body; int i; errno_t ret; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return ENOMEM; } /* First two fields (length and reserved), filled up later. */ ret = sss_packet_grow(packet, 2 * sizeof(uint32_t)); if (ret != EOK) { return ret; } rp = 2 * sizeof(uint32_t); num_results = 0; for (i = 0; i < result->count; i++) { talloc_free_children(tmp_ctx); msg = result->msgs[i]; /* Password field content. */ to_sized_string(&pwfield, nss_get_pwfield(nss_ctx, result->domain)); ret = nss_get_pwent(tmp_ctx, nss_ctx, result->domain, msg, &uid, &gid, &name, &gecos, &homedir, &shell); if (ret != EOK) { continue; } /* Adjust packet size: uid, gid + string fields. */ ret = sss_packet_grow(packet, 2 * sizeof(uint32_t) + name->len + gecos.len + homedir.len + shell.len + pwfield.len); if (ret != EOK) { goto done; } sss_packet_get_body(packet, &body, &body_len); /* Fill packet. */ SAFEALIGN_SET_UINT32(&body[rp], uid, &rp); SAFEALIGN_SET_UINT32(&body[rp], gid, &rp); SAFEALIGN_SET_STRING(&body[rp], name->str, name->len, &rp); SAFEALIGN_SET_STRING(&body[rp], pwfield.str, pwfield.len, &rp); SAFEALIGN_SET_STRING(&body[rp], gecos.str, gecos.len, &rp); SAFEALIGN_SET_STRING(&body[rp], homedir.str, homedir.len, &rp); SAFEALIGN_SET_STRING(&body[rp], shell.str, shell.len, &rp); num_results++; /* Do not store entry in memory cache during enumeration or when * requested. */ if (!cmd_ctx->enumeration && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { ret = sss_mmap_cache_pw_store(&nss_ctx->pwd_mc_ctx, name, &pwfield, uid, gid, &gecos, &homedir, &shell); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Failed to store user %s (%s) in mmap cache [%d]: %s!\n", name->str, result->domain->name, ret, sss_strerror(ret)); } } } ret = EOK; done: talloc_free(tmp_ctx); if (ret != EOK) { sss_packet_set_size(packet, 0); return ret; } sss_packet_get_body(packet, &body, &body_len); SAFEALIGN_COPY_UINT32(body, &num_results, NULL); SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL); /* reserved */ return EOK; }