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; }
int sss_mmap_cache_gr_store(struct sss_mc_ctx *mcc, struct sized_string *name, struct sized_string *pw, gid_t gid, size_t memnum, char *membuf, size_t memsize) { struct sss_mc_rec *rec; struct sss_mc_grp_data *data; struct sized_string gidkey; char gidstr[11]; size_t data_len; size_t rec_len; size_t pos; int ret; ret = snprintf(gidstr, 11, "%ld", (long)gid); if (ret > 10) { return EINVAL; } to_sized_string(&gidkey, gidstr); data_len = name->len + pw->len + memsize; rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_grp_data) + data_len; if (rec_len > mcc->dt_size) { return ENOMEM; } rec = sss_mc_get_record(mcc, rec_len, name); data = (struct sss_mc_grp_data *)rec->data; pos = 0; MC_RAISE_BARRIER(rec); /* header */ rec->len = rec_len; rec->expire = time(NULL) + mcc->valid_time_slot; rec->hash1 = sss_mc_hash(mcc, name->str, name->len); rec->hash2 = sss_mc_hash(mcc, gidkey.str, gidkey.len); /* group struct */ data->name = MC_PTR_DIFF(data->strs, data); data->gid = gid; data->members = memnum; data->strs_len = data_len; memcpy(&data->strs[pos], name->str, name->len); pos += name->len; memcpy(&data->strs[pos], pw->str, pw->len); pos += pw->len; memcpy(&data->strs[pos], membuf, memsize); pos += memsize; MC_LOWER_BARRIER(rec); /* finally chain the rec in the hash table */ /* name hash first */ sss_mc_add_rec_to_chain(mcc, rec, rec->hash1); /* then gid */ sss_mc_add_rec_to_chain(mcc, rec, rec->hash2); return EOK; }
errno_t sss_mmap_cache_pw_store(struct sss_mc_ctx *mcc, struct sized_string *name, struct sized_string *pw, uid_t uid, gid_t gid, struct sized_string *gecos, struct sized_string *homedir, struct sized_string *shell) { struct sss_mc_rec *rec; struct sss_mc_pwd_data *data; struct sized_string uidkey; char uidstr[11]; size_t data_len; size_t rec_len; size_t pos; int ret; ret = snprintf(uidstr, 11, "%ld", (long)uid); if (ret > 10) { return EINVAL; } to_sized_string(&uidkey, uidstr); data_len = name->len + pw->len + gecos->len + homedir->len + shell->len; rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_pwd_data) + data_len; if (rec_len > mcc->dt_size) { return ENOMEM; } rec = sss_mc_get_record(mcc, rec_len, name); data = (struct sss_mc_pwd_data *)rec->data; pos = 0; MC_RAISE_BARRIER(rec); /* header */ rec->len = rec_len; rec->expire = time(NULL) + mcc->valid_time_slot; rec->hash1 = sss_mc_hash(mcc, name->str, name->len); rec->hash2 = sss_mc_hash(mcc, uidkey.str, uidkey.len); /* passwd struct */ data->name = MC_PTR_DIFF(data->strs, data); data->uid = uid; data->gid = gid; data->strs_len = data_len; memcpy(&data->strs[pos], name->str, name->len); pos += name->len; memcpy(&data->strs[pos], pw->str, pw->len); pos += pw->len; memcpy(&data->strs[pos], gecos->str, gecos->len); pos += gecos->len; memcpy(&data->strs[pos], homedir->str, homedir->len); pos += homedir->len; memcpy(&data->strs[pos], shell->str, shell->len); pos += shell->len; MC_LOWER_BARRIER(rec); /* finally chain the rec in the hash table */ /* name hash first */ sss_mc_add_rec_to_chain(mcc, rec, rec->hash1); /* then uid */ sss_mc_add_rec_to_chain(mcc, rec, rec->hash2); return EOK; }
static errno_t process_attr_list(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char **attr_list, struct sized_string **_keys, struct sized_string **_vals, size_t *array_size, size_t *sum, size_t *found) { size_t c; size_t d; struct sized_string *keys; struct sized_string *vals; struct ldb_val val; struct ldb_message_element *el; bool use_base64; keys = *_keys; vals = *_vals; for (c = 0; attr_list[c] != NULL; c++) { el = ldb_msg_find_element(msg, attr_list[c]); if (el != NULL && el->num_values > 0) { if (el->num_values > 1) { *array_size += el->num_values; keys = talloc_realloc(mem_ctx, keys, struct sized_string, *array_size); vals = talloc_realloc(mem_ctx, vals, struct sized_string, *array_size); if (keys == NULL || vals == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); return ENOMEM; } } use_base64 = false; if (strcmp(attr_list[c], SYSDB_USER_CERT) == 0) { use_base64 = true; } for (d = 0; d < el->num_values; d++) { to_sized_string(&keys[*found], attr_list[c]); *sum += keys[*found].len; if (use_base64) { val.data = (uint8_t *)sss_base64_encode(vals, el->values[d].data, el->values[d].length); if (val.data != NULL) { val.length = strlen((char *)val.data); } } else { val = el->values[d]; } if (val.data == NULL || val.data[val.length] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected attribute value found for [%s].\n", attr_list[c]); return EINVAL; } to_sized_string(&vals[*found], (const char *)val.data); *sum += vals[*found].len; (*found)++; } } }
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; }
static errno_t nss_get_pwent(TALLOC_CTX *mem_ctx, struct nss_ctx *nss_ctx, struct sss_domain_info *domain, struct ldb_message *msg, uint32_t *_uid, uint32_t *_gid, struct sized_string **_name, struct sized_string *_gecos, struct sized_string *_homedir, struct sized_string *_shell) { const char *upn; const char *name; const char *gecos; const char *homedir; const char *shell; uint32_t gid; uint32_t uid; errno_t ret; /* Get fields. */ upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL); name = sss_get_name_from_msg(domain, msg); gid = nss_get_gid(domain, msg); uid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_UIDNUM, 0); if (name == NULL || uid == 0 || gid == 0) { DEBUG(SSSDBG_OP_FAILURE, "Incomplete user object for %s[%u]! Skipping\n", name ? name : "<NULL>", uid); return EINVAL; } gecos = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_GECOS, NULL); homedir = nss_get_homedir(mem_ctx, nss_ctx, domain, msg, name, upn, uid); ret = nss_get_shell(nss_ctx, domain, msg, name, uid, &shell); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "failed retrieving shell for %s[%u], skipping [%d]: %s\n", name, uid, ret, sss_strerror(ret)); return ret; } /* Convert to sized strings. */ ret = sized_output_name(mem_ctx, nss_ctx->rctx, name, domain, _name); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "sized_output_name failed, skipping [%d]: %s\n", ret, sss_strerror(ret)); return ret; } to_sized_string(_gecos, gecos == NULL ? "" : gecos); to_sized_string(_shell, shell); to_sized_string(_homedir, homedir); *_gid = gid; *_uid = uid; return EOK; }