/* The repbuf is owned by the sss_getautomntent_data once this * function is called */ static errno_t sss_getautomntent_data_save(const char *mapname, uint8_t **repbuf, size_t replen) { size_t rp; uint32_t num; rp = 0; SAFEALIGN_COPY_UINT32(&num, *repbuf+rp, &rp); if (num == 0) { free(*repbuf); return ENOENT; } sss_getautomntent_data.mapname = strdup(mapname); if (sss_getautomntent_data.mapname == NULL) { free(*repbuf); return ENOENT; } sss_getautomntent_data.data = *repbuf; sss_getautomntent_data.len = replen; sss_getautomntent_data.ptr = rp; *repbuf = NULL; return EOK; }
enum idmap_error_code sss_idmap_bin_sid_to_dom_sid(struct sss_idmap_ctx *ctx, const uint8_t *bin_sid, size_t length, struct sss_dom_sid **_dom_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid; size_t i = 0; size_t p = 0; uint32_t val; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); if (length > sizeof(struct sss_dom_sid)) return IDMAP_SID_INVALID; dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt); if (dom_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(dom_sid, 0, sizeof(struct sss_dom_sid)); /* Safely copy in the SID revision number */ dom_sid->sid_rev_num = (uint8_t) *(bin_sid + p); p++; /* Safely copy in the number of sub auth values */ dom_sid->num_auths = (uint8_t) *(bin_sid + p); p++; /* Make sure we aren't being told to read more bin_sid * than can fit in the structure */ if (dom_sid->num_auths > SID_SUB_AUTHS) { err = IDMAP_SID_INVALID; goto done; } /* Safely copy in the id_auth values */ for (i = 0; i < SID_ID_AUTHS; i++) { dom_sid->id_auth[i] = (uint8_t) *(bin_sid + p); p++; } /* Safely copy in the sub_auths values */ for (i = 0; i < dom_sid->num_auths; i++) { /* SID sub auth values in Active Directory are stored little-endian, * we store them in host order */ SAFEALIGN_COPY_UINT32(&val, bin_sid + p, &p); dom_sid->sub_auths[i] = le32toh(val); } *_dom_sid = dom_sid; err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(dom_sid, ctx->alloc_pvt); } return err; }
enum idmap_error_code sss_idmap_dom_sid_to_bin_sid(struct sss_idmap_ctx *ctx, struct sss_dom_sid *dom_sid, uint8_t **_bin_sid, size_t *_length) { enum idmap_error_code err; uint8_t *bin_sid; size_t length; size_t i = 0; size_t p = 0; uint32_t val; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); if (dom_sid->num_auths > SID_SUB_AUTHS) { return IDMAP_SID_INVALID; } length = 2 + SID_ID_AUTHS + dom_sid->num_auths * 4; bin_sid = ctx->alloc_func(length, ctx->alloc_pvt); if (bin_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } bin_sid[p] = dom_sid->sid_rev_num; p++; bin_sid[p] = dom_sid->num_auths; p++; for (i = 0; i < SID_ID_AUTHS; i++) { bin_sid[p] = dom_sid->id_auth[i]; p++; } for (i = 0; i < dom_sid->num_auths; i++) { if (p + sizeof(uint32_t) > length) { err = IDMAP_SID_INVALID; goto done; } val = htole32(dom_sid->sub_auths[i]); SAFEALIGN_COPY_UINT32(bin_sid + p, &val, &p); } *_bin_sid = bin_sid; *_length = length; err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(bin_sid, ctx->alloc_pvt); } return err; }
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; }
static int pam_parse_in_data_v2(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { size_t c; uint32_t type; uint32_t size; char *pam_user; int ret; uint32_t start; uint32_t terminator; if (blen < 4*sizeof(uint32_t)+2) { DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n"); return EINVAL; } SAFEALIGN_COPY_UINT32(&start, body, NULL); SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL); if (start != SSS_START_OF_PAM_REQUEST || terminator != SSS_END_OF_PAM_REQUEST) { DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n"); return EINVAL; } c = sizeof(uint32_t); do { SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c); if (type == SSS_END_OF_PAM_REQUEST) { if (c != blen) return EINVAL; } else { SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c); /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to * the remaining buffer */ if (size > (blen - c - sizeof(uint32_t))) { DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n"); return EINVAL; } switch(type) { case SSS_PAM_ITEM_USER: ret = extract_string(&pam_user, size, body, blen, &c); if (ret != EOK) return ret; ret = sss_parse_name_for_domains(pd, domains, default_domain, pam_user, &pd->domain, &pd->user); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_SERVICE: ret = extract_string(&pd->service, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_TTY: ret = extract_string(&pd->tty, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_RUSER: ret = extract_string(&pd->ruser, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_RHOST: ret = extract_string(&pd->rhost, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_CLI_PID: ret = extract_uint32_t(&pd->cli_pid, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: ret = extract_authtok_v2(pd->authtok, size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: ret = extract_authtok_v2(pd->newauthtok, size, body, blen, &c); if (ret != EOK) return ret; break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Ignoring unknown data type [%d].\n", type); c += size; } } } while(c < blen); if (pd->user == NULL || *pd->user == '\0') return EINVAL; DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd); return EOK; }
static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, uint8_t *buf, size_t *len) { errno_t ret; size_t i, slen, dlen; char *sbuf; uint32_t c; if (*len < 13) { /* not enough space for data, bad packet */ return EBADMSG; } SAFEALIGN_COPY_UINT32(&c, buf, NULL); pr->result->pw_uid = c; SAFEALIGN_COPY_UINT32(&c, buf+sizeof(uint32_t), NULL); pr->result->pw_gid = c; sbuf = (char *)&buf[8]; slen = *len - 8; dlen = pr->buflen; i = 0; pr->result->pw_name = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->pw_name, NULL); if (ret != EOK) return ret; pr->result->pw_passwd = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->pw_passwd, NULL); if (ret != EOK) return ret; pr->result->pw_gecos = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->pw_gecos, NULL); if (ret != EOK) return ret; pr->result->pw_dir = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->pw_dir, NULL); if (ret != EOK) return ret; pr->result->pw_shell = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->pw_shell, NULL); if (ret != EOK) return ret; *len = slen - i; return 0; }
static enum nss_status internal_getpwent_r(struct passwd *result, char *buffer, size_t buflen, int *errnop) { struct sss_cli_req_data rd; struct sss_nss_pw_rep pwrep; uint8_t *repbuf; size_t replen; uint32_t num_results; enum nss_status nret; uint32_t num_entries; int ret; /* Caught once glibc passing in buffer == 0x0 */ if (!buffer || !buflen) return ERANGE; /* if there are leftovers return the next one */ if (sss_nss_getpwent_data.data != NULL && sss_nss_getpwent_data.ptr < sss_nss_getpwent_data.len) { repbuf = sss_nss_getpwent_data.data + sss_nss_getpwent_data.ptr; replen = sss_nss_getpwent_data.len - sss_nss_getpwent_data.ptr; pwrep.result = result; pwrep.buffer = buffer; pwrep.buflen = buflen; ret = sss_nss_getpw_readrep(&pwrep, repbuf, &replen); if (ret) { *errnop = ret; return NSS_STATUS_TRYAGAIN; } /* advance buffer pointer */ sss_nss_getpwent_data.ptr = sss_nss_getpwent_data.len - replen; return NSS_STATUS_SUCCESS; } /* release memory if any */ sss_nss_getpwent_data_clean(); /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */ num_entries = SSS_NSS_MAX_ENTRIES; rd.len = sizeof(uint32_t); rd.data = &num_entries; nret = sss_nss_make_request(SSS_NSS_GETPWENT, &rd, &repbuf, &replen, errnop); if (nret != NSS_STATUS_SUCCESS) { return nret; } /* Get number of results from repbuf. */ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); /* no results if not found */ if ((num_results == 0) || (replen - 8 == 0)) { free(repbuf); return NSS_STATUS_NOTFOUND; } sss_nss_getpwent_data.data = repbuf; sss_nss_getpwent_data.len = replen; sss_nss_getpwent_data.ptr = 8; /* skip metadata fields */ /* call again ourselves, this will return the first result */ return internal_getpwent_r(result, buffer, buflen, errnop); }
enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, size_t buflen, int *errnop) { struct sss_cli_req_data rd; struct sss_nss_pw_rep pwrep; uint8_t *repbuf; size_t replen, len; uint32_t num_results; enum nss_status nret; uint32_t user_uid; int ret; /* Caught once glibc passing in buffer == 0x0 */ if (!buffer || !buflen) return ERANGE; ret = sss_nss_mc_getpwuid(uid, result, buffer, buflen); switch (ret) { case 0: *errnop = 0; return NSS_STATUS_SUCCESS; case ERANGE: *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; case ENOENT: /* fall through, we need to actively ask the parent * if no entry is found */ break; default: /* if using the mmaped cache failed, * fall back to socket based comms */ break; } user_uid = uid; rd.len = sizeof(uint32_t); rd.data = &user_uid; sss_nss_lock(); /* previous thread might already initialize entry in mmap cache */ ret = sss_nss_mc_getpwuid(uid, result, buffer, buflen); switch (ret) { case 0: *errnop = 0; nret = NSS_STATUS_SUCCESS; goto out; case ERANGE: *errnop = ERANGE; nret = NSS_STATUS_TRYAGAIN; goto out; case ENOENT: /* fall through, we need to actively ask the parent * if no entry is found */ break; default: /* if using the mmaped cache failed, * fall back to socket based comms */ break; } nret = sss_nss_make_request(SSS_NSS_GETPWUID, &rd, &repbuf, &replen, errnop); if (nret != NSS_STATUS_SUCCESS) { goto out; } pwrep.result = result; pwrep.buffer = buffer; pwrep.buflen = buflen; /* Get number of results from repbuf. */ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); /* no results if not found */ if (num_results == 0) { free(repbuf); nret = NSS_STATUS_NOTFOUND; goto out; } /* only 1 result is accepted for this function */ if (num_results != 1) { *errnop = EBADMSG; free(repbuf); nret = NSS_STATUS_TRYAGAIN; goto out; } len = replen - 8; ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len); free(repbuf); if (ret) { *errnop = ret; nret = NSS_STATUS_TRYAGAIN; goto out; } nret = NSS_STATUS_SUCCESS; out: sss_nss_unlock(); return nret; }
static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , struct output *out) { int ret; size_t inp_len; struct sss_cli_req_data rd; uint8_t *repbuf = NULL; size_t replen; int errnop; enum nss_status nret; uint32_t num_results; char *str = NULL; size_t data_len; uint32_t c; switch (cmd) { case SSS_NSS_GETSIDBYNAME: case SSS_NSS_GETNAMEBYSID: case SSS_NSS_GETIDBYSID: ret = sss_strnlen(inp.str, SSS_NAME_MAX, &inp_len); if (ret != EOK) { return EINVAL; } rd.len = inp_len + 1; rd.data = inp.str; break; case SSS_NSS_GETSIDBYID: rd.len = sizeof(uint32_t); rd.data = &inp.id; break; default: return EINVAL; } sss_nss_lock(); nret = sss_nss_make_request(cmd, &rd, &repbuf, &replen, &errnop); if (nret != NSS_STATUS_SUCCESS) { ret = nss_status_to_errno(nret); goto done; } if (replen < 8) { ret = EBADMSG; goto done; } num_results = ((uint32_t *)repbuf)[0]; if (num_results == 0) { ret = ENOENT; goto done; } else if (num_results > 1) { ret = EBADMSG; goto done; } out->type = ((uint32_t *)repbuf)[2]; data_len = replen - DATA_START; switch(cmd) { case SSS_NSS_GETSIDBYID: case SSS_NSS_GETSIDBYNAME: case SSS_NSS_GETNAMEBYSID: if (data_len <= 1 || repbuf[replen - 1] != '\0') { ret = EBADMSG; goto done; } str = malloc(sizeof(char) * data_len); if (str == NULL) { ret = ENOMEM; goto done; } strncpy(str, (char *) repbuf + DATA_START, data_len); out->d.str = str; break; case SSS_NSS_GETIDBYSID: if (data_len != sizeof(uint32_t)) { ret = EBADMSG; goto done; } SAFEALIGN_COPY_UINT32(&c, repbuf + DATA_START, NULL); out->d.id = c; break; default: ret = EINVAL; goto done; } ret = EOK; done: sss_nss_unlock(); free(repbuf); if (ret != EOK) { free(str); } return 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; }
errno_t _sss_setautomntent(const char *mapname, void **context) { errno_t ret; int errnop; struct automtent *ctx; char *name; size_t name_len; struct sss_cli_req_data rd; uint8_t *repbuf = NULL; size_t replen; uint32_t num_results = 0; if (!mapname) return EINVAL; sss_nss_lock(); /* Make sure there are no leftovers from previous runs */ sss_getautomntent_data_clean(); ret = sss_strnlen(mapname, MAX_AUTOMNTMAPNAME_LEN, &name_len); if (ret != 0) { ret = EINVAL; goto out; } name = malloc(sizeof(char)*name_len + 1); if (name == NULL) { ret = ENOMEM; goto out; } strncpy(name, mapname, name_len + 1); rd.data = name; rd.len = name_len + 1; sss_autofs_make_request(SSS_AUTOFS_SETAUTOMNTENT, &rd, &repbuf, &replen, &errnop); if (errnop != 0) { free(name); ret = errnop; goto out; } /* Get number of results from repbuf. */ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); /* no results if not found */ if (num_results == 0) { free(name); free(repbuf); ret = ENOENT; goto out; } free(repbuf); ctx = malloc(sizeof(struct automtent)); if (!ctx) { free(name); ret = ENOMEM; goto out; } ctx->mapname = strdup(name); if (!ctx->mapname) { free(name); free(ctx); ret = ENOMEM; goto out; } ctx->cursor = 0; free(name); *context = ctx; ret = 0; out: sss_nss_unlock(); return ret; }
errno_t _sss_getautomntbyname_r(const char *key, char **value, void *context) { int errnop; errno_t ret; struct automtent *ctx; size_t key_len; size_t name_len; size_t data_len = 0; uint8_t *data; size_t ctr = 0; struct sss_cli_req_data rd; uint8_t *repbuf = NULL; size_t replen; char *buf; uint32_t len; uint32_t vallen; size_t rp; sss_nss_lock(); ctx = (struct automtent *) context; if (!ctx || !key) { ret = EINVAL; goto out; } /* Be paranoid in case someone tries to smuggle in a huge map name */ ret = sss_strnlen(ctx->mapname, MAX_AUTOMNTMAPNAME_LEN, &name_len); if (ret != 0) { ret = EINVAL; goto out; } ret = sss_strnlen(key, MAX_AUTOMNTKEYNAME_LEN, &key_len); if (ret != 0) { ret = EINVAL; goto out; } data_len = sizeof(uint32_t) + /* mapname len */ name_len + 1 + /* mapname\0 */ sizeof(uint32_t) + /* keyname len */ key_len + 1; /* keyname\0 */ data = malloc(data_len); if (!data) { ret = ENOMEM; goto out; } SAFEALIGN_SET_UINT32(data, name_len, &ctr); safealign_memcpy(data+ctr, ctx->mapname, name_len + 1, &ctr); SAFEALIGN_SET_UINT32(data+ctr, key_len, &ctr); safealign_memcpy(data+ctr, key, key_len + 1, &ctr); rd.data = data; rd.len = data_len; sss_autofs_make_request(SSS_AUTOFS_GETAUTOMNTBYNAME, &rd, &repbuf, &replen, &errnop); free(data); if (errnop != 0) { ret = errnop; goto out; } /* Got reply, let's parse it */ rp = 0; SAFEALIGN_COPY_UINT32(&len, repbuf+rp, &rp); if (len == 0) { /* No data */ *value = NULL; ret = ENOENT; goto out; } SAFEALIGN_COPY_UINT32(&vallen, repbuf+rp, &rp); if (vallen > len-rp) { ret = EIO; goto out; } buf = malloc(vallen); if (!buf) { ret = ENOMEM; goto out; } safealign_memcpy(buf, repbuf+rp, vallen, &rp); *value = buf; ret = 0; out: free(repbuf); sss_nss_unlock(); return ret; }
static errno_t sss_getautomntent_data_return(const char *mapname, char **_key, char **_value) { size_t dp; uint32_t len = 0; char *key = NULL; uint32_t keylen; char *value = NULL; uint32_t vallen; errno_t ret; if (sss_getautomntent_data.mapname == NULL || sss_getautomntent_data.data == NULL || sss_getautomntent_data.ptr >= sss_getautomntent_data.len) { /* We're done with this buffer */ ret = ENOENT; goto done; } ret = strcmp(mapname, sss_getautomntent_data.mapname); if (ret != EOK) { /* The map we're looking for is not cached. Let responder * do an implicit setautomntent */ ret = ENOENT; goto done; } dp = sss_getautomntent_data.ptr; SAFEALIGN_COPY_UINT32(&len, sss_getautomntent_data.data+dp, &dp); if (len + sss_getautomntent_data.ptr > sss_getautomntent_data.len) { /* len is bigger than the buffer */ ret = EIO; goto done; } if (len == 0) { /* There are no more records. */ *_key = NULL; *_value = NULL; ret = ENOENT; goto done; } SAFEALIGN_COPY_UINT32(&keylen, sss_getautomntent_data.data+dp, &dp); if (keylen + dp > sss_getautomntent_data.len) { ret = EIO; goto done; } key = malloc(keylen); if (!key) { ret = ENOMEM; goto done; } safealign_memcpy(key, sss_getautomntent_data.data+dp, keylen, &dp); SAFEALIGN_COPY_UINT32(&vallen, sss_getautomntent_data.data+dp, &dp); if (vallen + dp > sss_getautomntent_data.len) { ret = EIO; goto done; } value = malloc(vallen); if (!value) { ret = ENOMEM; goto done; } safealign_memcpy(value, sss_getautomntent_data.data+dp, vallen, &dp); sss_getautomntent_data.ptr = dp; *_key = key; *_value = value; return EOK; done: free(key); free(value); sss_getautomntent_data_clean(); return ret; }
/* SSH public key request: * * header: * 0..3: flags (unsigned int, must be combination of SSS_SSH_REQ_* flags) * 4..7: name length (unsigned int) * 8..X: name (null-terminated UTF-8 string) * alias (only included if flags & SSS_SSH_REQ_ALIAS): * 0..3: alias length (unsigned int) * 4..X: alias (null-terminated UTF-8 string) * domain (ony included if flags & SSS_SSH_REQ_DOMAIN): * 0..3: domain length (unsigned int, 0 means default domain) * 4..X: domain (null-terminated UTF-8 string) * * SSH public key reply: * * header: * 0..3: number of results (unsigned int) * 4..7: reserved (unsigned int, must be 0) * results (repeated for each result): * 0..3: flags (unsigned int, must be 0) * 4..7: name length (unsigned int) * 8..(X-1): name (null-terminated UTF-8 string) * X..(X+3): key length (unsigned int) * (X+4)..Y: key (public key data) */ errno_t sss_ssh_get_ent(TALLOC_CTX *mem_ctx, enum sss_cli_command command, const char *name, const char *domain, const char *alias, struct sss_ssh_ent **result) { TALLOC_CTX *tmp_ctx; struct sss_ssh_ent *res = NULL; errno_t ret; uint32_t flags; uint32_t name_len; uint32_t alias_len = 0; uint32_t domain_len; size_t req_len; uint8_t *req = NULL; size_t c = 0; struct sss_cli_req_data rd; int req_ret, req_errno; uint8_t *rep = NULL; size_t rep_len; uint32_t count, reserved, len, i; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } /* build request */ flags = 0; name_len = strlen(name)+1; req_len = 2*sizeof(uint32_t) + name_len; if (alias) { flags |= SSS_SSH_REQ_ALIAS; alias_len = strlen(alias)+1; req_len += sizeof(uint32_t) + alias_len; } flags |= SSS_SSH_REQ_DOMAIN; domain_len = domain ? (strlen(domain)+1) : 0; req_len += sizeof(uint32_t) + domain_len; req = talloc_array(tmp_ctx, uint8_t, req_len); if (!req) { ret = ENOMEM; goto done; } SAFEALIGN_SET_UINT32(req+c, flags, &c); SAFEALIGN_SET_UINT32(req+c, name_len, &c); safealign_memcpy(req+c, name, name_len, &c); if (alias) { SAFEALIGN_SET_UINT32(req+c, alias_len, &c); safealign_memcpy(req+c, alias, alias_len, &c); } SAFEALIGN_SET_UINT32(req+c, domain_len, &c); if (domain_len > 0) { safealign_memcpy(req+c, domain, domain_len, &c); } /* send request */ rd.data = req; rd.len = req_len; req_ret = sss_ssh_make_request(command, &rd, &rep, &rep_len, &req_errno); if (req_errno != EOK) { ret = req_errno; goto done; } if (req_ret != SSS_STATUS_SUCCESS) { ret = EFAULT; goto done; } /* parse reply */ c = 0; if (rep_len-c < 2*sizeof(uint32_t)) { ret = EINVAL; goto done; } SAFEALIGN_COPY_UINT32(&count, rep+c, &c); SAFEALIGN_COPY_UINT32(&reserved, rep+c, &c); if (reserved != 0) { ret = EINVAL; goto done; } res = talloc_zero(tmp_ctx, struct sss_ssh_ent); if (!res) { ret = ENOMEM; goto done; } if (count > 0) { res->pubkeys = talloc_zero_array(res, struct sss_ssh_pubkey, count); if (!res->pubkeys) { ret = ENOMEM; goto done; } res->num_pubkeys = count; }
static int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, uint8_t *buf, size_t *len) { errno_t ret; size_t i, l, slen, ptmem, pad, dlen, glen; char *sbuf; uint32_t mem_num; uint32_t c; if (*len < 11) { /* not enough space for data, bad packet */ return EBADMSG; } SAFEALIGN_COPY_UINT32(&c, buf, NULL); pr->result->gr_gid = c; SAFEALIGN_COPY_UINT32(&mem_num, buf+sizeof(uint32_t), NULL); sbuf = (char *)&buf[8]; slen = *len - 8; dlen = pr->buflen; pr->result->gr_name = &(pr->buffer[0]); i = 0; ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->gr_name, NULL); if (ret != EOK) return ret; pr->result->gr_passwd = &(pr->buffer[i]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->gr_passwd, NULL); if (ret != EOK) return ret; /* Make sure pr->buffer[i+pad] is 32 bit aligned */ pad = 0; while((i + pad) % 4) { pad++; } /* now members */ pr->result->gr_mem = (char **)&(pr->buffer[i+pad]); ptmem = (sizeof(char *) * (mem_num + 1)) + pad; if (ptmem > dlen) { return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */ } dlen -= ptmem; ptmem += i; pr->result->gr_mem[mem_num] = NULL; /* terminate array */ for (l = 0; l < mem_num; l++) { pr->result->gr_mem[l] = &(pr->buffer[ptmem]); ret = sss_readrep_copy_string(sbuf, &i, &slen, &dlen, &pr->result->gr_mem[l], &glen); if (ret != EOK) return ret; ptmem += glen + 1; } *len = slen -i; return 0; }