static int pack_buffer(struct response *r, int result, krb5_error_code krberr, const char *msg, time_t expire_time) { int len; size_t p = 0; len = strlen(msg); r->size = 2 * sizeof(uint32_t) + sizeof(krb5_error_code) + len + sizeof(time_t); r->buf = talloc_array(r, uint8_t, r->size); if(!r->buf) { return ENOMEM; } /* result */ SAFEALIGN_SET_UINT32(&r->buf[p], result, &p); /* krb5 error code */ safealign_memcpy(&r->buf[p], &krberr, sizeof(krberr), &p); /* message size */ SAFEALIGN_SET_UINT32(&r->buf[p], len, &p); /* message itself */ safealign_memcpy(&r->buf[p], msg, len, &p); /* ticket expiration time */ safealign_memcpy(&r->buf[p], &expire_time, sizeof(expire_time), &p); return EOK; }
static int parse_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t size, int *result, krb5_error_code *kerr, char **ccache, time_t *expire_time_out) { size_t p = 0; uint32_t len; uint32_t res; char *ccn; time_t expire_time; krb5_error_code krberr; /* operation result code */ SAFEALIGN_COPY_UINT32_CHECK(&res, buf + p, size, &p); /* krb5 error code */ safealign_memcpy(&krberr, buf+p, sizeof(krberr), &p); /* ccache name size */ SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); if ((p + len ) > size) return EINVAL; ccn = talloc_size(mem_ctx, sizeof(char) * (len + 1)); if (ccn == NULL) { DEBUG(1, ("talloc_size failed.\n")); return ENOMEM; } safealign_memcpy(ccn, buf+p, sizeof(char) * len, &p); ccn[len] = '\0'; if (p + sizeof(time_t) > size) { talloc_free(ccn); return EINVAL; } safealign_memcpy(&expire_time, buf+p, sizeof(time_t), &p); *result = res; *ccache = ccn; *expire_time_out = expire_time; *kerr = krberr; return EOK; }
static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, struct pam_data *pd, uint8_t **_buf, size_t *_len) { int ret; uint8_t *buf; size_t len; const char *pin = NULL; if (pd == NULL || pd->authtok == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing authtok.\n"); return EINVAL; } switch (sss_authtok_get_type(pd->authtok)) { case SSS_AUTHTOK_TYPE_SC_PIN: ret = sss_authtok_get_sc_pin(pd->authtok, &pin, &len); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc_pin failed.\n"); return ret; } if (pin == NULL || len == 0) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n"); return EINVAL; } buf = talloc_size(mem_ctx, len); if (buf == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n"); return ENOMEM; } safealign_memcpy(buf, pin, len, NULL); break; case SSS_AUTHTOK_TYPE_SC_KEYPAD: /* Nothing to send */ len = 0; buf = NULL; break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type [%d].\n", sss_authtok_get_type(pd->authtok)); return EINVAL; } *_len = len; *_buf = buf; return EOK; }
static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx, const char *realm_str, const char *princ_str, const char *keytab_name, int32_t lifetime, struct io_buffer **io_buf) { struct io_buffer *buf; size_t rp; buf = talloc(mem_ctx, struct io_buffer); if (buf == NULL) { DEBUG(1, ("talloc failed.\n")); return ENOMEM; } buf->size = 4 * sizeof(uint32_t); if (realm_str) { buf->size += strlen(realm_str); } if (princ_str) { buf->size += strlen(princ_str); } if (keytab_name) { buf->size += strlen(keytab_name); } DEBUG(7, ("buffer size: %d\n", buf->size)); buf->data = talloc_size(buf, buf->size); if (buf->data == NULL) { DEBUG(1, ("talloc_size failed.\n")); talloc_free(buf); return ENOMEM; } rp = 0; /* realm */ if (realm_str) { SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(realm_str), &rp); safealign_memcpy(&buf->data[rp], realm_str, strlen(realm_str), &rp); } else { SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp); } /* principal */ if (princ_str) { SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(princ_str), &rp); safealign_memcpy(&buf->data[rp], princ_str, strlen(princ_str), &rp); } else { SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp); } /* keytab */ if (keytab_name) { SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab_name), &rp); safealign_memcpy(&buf->data[rp], keytab_name, strlen(keytab_name), &rp); } else { SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp); } /* lifetime */ SAFEALIGN_SET_UINT32(&buf->data[rp], lifetime, &rp); *io_buf = buf; return EOK; }
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; }
errno_t _sss_getautomntent_r(char **key, char **value, void *context) { int errnop; errno_t ret; size_t name_len; struct sss_cli_req_data rd; uint8_t *repbuf = NULL; size_t replen; struct automtent *ctx; size_t ctr = 0; size_t data_len = 0; uint8_t *data; sss_nss_lock(); ctx = (struct automtent *) context; if (!ctx) { 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_getautomntent_data_return(ctx->mapname, key, value); if (ret == EOK) { /* The results are available from cache. Just advance the * cursor and return. */ ctx->cursor++; ret = 0; goto out; } /* Don't try to handle any error codes, just go to the responder again */ data_len = sizeof(uint32_t) + /* mapname len */ name_len + 1 + /* mapname\0 */ sizeof(uint32_t) + /* index into the map */ sizeof(uint32_t); /* num entries to retreive */ 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, ctx->cursor, &ctr); SAFEALIGN_SET_UINT32(data+ctr, GETAUTOMNTENT_MAX_ENTRIES, &ctr); rd.data = data; rd.len = data_len; sss_autofs_make_request(SSS_AUTOFS_GETAUTOMNTENT, &rd, &repbuf, &replen, &errnop); free(data); if (errnop != 0) { ret = errnop; goto out; } /* Got reply, let's save it and return from "cache" */ ret = sss_getautomntent_data_save(ctx->mapname, &repbuf, replen); if (ret == ENOENT) { /* No results */ *key = NULL; *value = NULL; goto out; } else if (ret != EOK) { /* Unexpected error */ goto out; } ret = sss_getautomntent_data_return(ctx->mapname, key, value); if (ret != EOK) { goto out; } /* Advance the cursor so that we'll fetch the next map * next time getautomntent is called */ ctx->cursor++; ret = 0; out: 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; }
int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded, char **password) { SECStatus sret; int ret; TALLOC_CTX *tmp_ctx = NULL; struct crypto_mech_data *mech_props; struct sss_nss_crypto_ctx *cctx; int plainlen; unsigned int digestlen; unsigned char *obfbuf = NULL; size_t obflen; char *pwdbuf; /* for unmarshaling data */ uint16_t meth; uint16_t ctsize; size_t p = 0; unsigned char *cryptotext; unsigned char *keybuf; unsigned char *ivbuf; unsigned char sentinel_check[OBF_BUFFER_SENTINEL_SIZE]; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ENOMEM; } /* initialize NSS if needed */ ret = nspr_nss_init(); if (ret != EOK) { ret = EIO; goto done; } /* Base64 decode the incoming buffer */ obfbuf = sss_base64_decode(tmp_ctx, b64encoded, &obflen); if (!obfbuf) { ret = ENOMEM; goto done; } /* unpack obfuscation buffer */ SAFEALIGN_COPY_UINT16_CHECK(&meth, obfbuf+p, obflen, &p); DEBUG(SSSDBG_TRACE_INTERNAL, "Read method: %d\n", meth); SAFEALIGN_COPY_UINT16_CHECK(&ctsize, obfbuf+p, obflen, &p); DEBUG(SSSDBG_TRACE_INTERNAL, "Read bufsize: %d\n", ctsize); mech_props = get_crypto_mech_data(meth); if (mech_props == NULL) { ret = EINVAL; goto done; } /* check that we got sane mechanism properties and cryptotext size */ memcpy(sentinel_check, obfbuf + p + mech_props->keylen + mech_props->bsize + ctsize, OBF_BUFFER_SENTINEL_SIZE); if (memcmp(sentinel_check, OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) { DEBUG(SSSDBG_FATAL_FAILURE, "Obfuscation buffer seems corrupt, aborting\n"); ret = EFAULT; goto done; } /* copy out key, ivbuf and cryptotext */ keybuf = talloc_array(tmp_ctx, unsigned char, mech_props->keylen); if (keybuf == NULL) { ret = ENOMEM; goto done; } safealign_memcpy(keybuf, obfbuf+p, mech_props->keylen, &p); ivbuf = talloc_array(tmp_ctx, unsigned char, mech_props->bsize); if (ivbuf == NULL) { ret = ENOMEM; goto done; } safealign_memcpy(ivbuf, obfbuf+p, mech_props->bsize, &p); cryptotext = talloc_array(tmp_ctx, unsigned char, ctsize); if (cryptotext == NULL) { ret = ENOMEM; goto done; } safealign_memcpy(cryptotext, obfbuf+p, ctsize, &p); ret = nss_ctx_init(tmp_ctx, mech_props, &cctx); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n"); goto done; } cctx->iv = talloc_zero(cctx, SECItem); cctx->key = talloc_zero(cctx, SECItem); if (!cctx->iv || !cctx->key) { ret = ENOMEM; goto done; } MAKE_SECITEM(ivbuf, mech_props->bsize, cctx->iv); MAKE_SECITEM(keybuf, mech_props->keylen, cctx->key); ret = nss_encrypt_decrypt_init(mech_props, false, cctx); if (ret) { goto done; } pwdbuf = talloc_array(tmp_ctx, char, ctsize); if (!pwdbuf) { ret = ENOMEM; goto done; } sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen, ctsize, cryptotext, ctsize); if (sret != SECSuccess) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot execute the encryption operation (err %d)\n", PR_GetError()); ret = EIO; goto done; } sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen, &digestlen, ctsize - plainlen); if (sret != SECSuccess) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot execute the encryption operation (err %d)\n", PR_GetError()); ret = EIO; goto done; } *password = talloc_move(mem_ctx, &pwdbuf); ret = EOK; done: talloc_free(tmp_ctx); nspr_nss_cleanup(); return ret; }
int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen, enum obfmethod meth, char **obfpwd) { SECStatus sret; int ret; TALLOC_CTX *tmp_ctx = NULL; struct crypto_mech_data *mech_props; struct sss_nss_crypto_ctx *cctx; unsigned char *plaintext; unsigned char *cryptotext; int ct_maxsize; int ctlen; unsigned int digestlen; int result_len; unsigned char *obfbuf; size_t obufsize = 0; size_t p = 0; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ENOMEM; } /* initialize NSS if needed */ ret = nspr_nss_init(); if (ret != EOK) { ret = EIO; goto done; } mech_props = get_crypto_mech_data(meth); if (mech_props == NULL) { ret = EINVAL; goto done; } ret = nss_ctx_init(tmp_ctx, mech_props, &cctx); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n"); goto done; } /* generate random encryption and IV key */ ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->key); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not generate encryption key\n"); goto done; } ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->iv); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not generate initialization vector\n"); goto done; } ret = nss_encrypt_decrypt_init(mech_props, true, cctx); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context properties\n"); goto done; } plaintext = (unsigned char *) talloc_strndup(tmp_ctx, password, plen); if (!plaintext) { ret = ENOMEM; goto done; } /* cryptotext buffer must be at least len(plaintext)+blocksize */ ct_maxsize = plen + (mech_props->bsize); cryptotext = talloc_array(tmp_ctx, unsigned char, ct_maxsize); if (!cryptotext) { ret = ENOMEM; goto done; } /* sample data we'll encrypt and decrypt */ sret = PK11_CipherOp(cctx->ectx, cryptotext, &ctlen, ct_maxsize, plaintext, plen); if (sret != SECSuccess) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot execute the encryption operation (err %d)\n", PR_GetError()); ret = EIO; goto done; } sret = PK11_DigestFinal(cctx->ectx, cryptotext+ctlen, &digestlen, ct_maxsize-ctlen); if (sret != SECSuccess) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot execute the digest operation (err %d)\n", PR_GetError()); ret = EIO; goto done; } result_len = ctlen + digestlen; if (result_len < 0 || result_len > UINT16_MAX) { ret = ERANGE; goto done; } /* Pack the obfuscation buffer */ /* The buffer consists of: * uint16_t the type of the cipher * uint16_t length of the cryptotext in bytes (clen) * uint8_t[klen] key * uint8_t[blen] IV * uint8_t[clen] cryptotext * 4 bytes of "sentinel" denoting end of the buffer */ obufsize = sizeof(uint16_t) + sizeof(uint16_t) + mech_props->keylen + mech_props->bsize + result_len + OBF_BUFFER_SENTINEL_SIZE; obfbuf = talloc_array(tmp_ctx, unsigned char, obufsize); if (!obfbuf) { ret = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "Writing method: %d\n", meth); SAFEALIGN_SET_UINT16(&obfbuf[p], meth, &p); DEBUG(SSSDBG_TRACE_INTERNAL, "Writing bufsize: %d\n", result_len); SAFEALIGN_SET_UINT16(&obfbuf[p], result_len, &p); safealign_memcpy(&obfbuf[p], cctx->key->data, mech_props->keylen, &p); safealign_memcpy(&obfbuf[p], cctx->iv->data, mech_props->bsize, &p); safealign_memcpy(&obfbuf[p], cryptotext, result_len, &p); safealign_memcpy(&obfbuf[p], OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE, &p); /* Base64 encode the resulting buffer */ *obfpwd = sss_base64_encode(mem_ctx, obfbuf, obufsize); if (*obfpwd == NULL) { ret = ENOMEM; goto done; } ret = EOK; done: talloc_free(tmp_ctx); nspr_nss_cleanup(); return ret; }