Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
/* 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;
    }
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}