static int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error) { int seqwin = 0; char buf[32]; char *p, *end; logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid); p = buf; end = buf + sizeof(buf); WRITE_BYTES(&p, end, seqwin); WRITE_BYTES(&p, end, rpc_error); WRITE_BYTES(&p, end, gss_error); again: if (keyctl_update(keyid, buf, p - buf)) { if (errno != EAGAIN) { logmsg(LL_ERR, "revoke key %08x: %s\n", keyid, strerror(errno)); return -1; } logmsg(LL_WARN, "key %08x: revoking too soon, try again\n", keyid); sleep(2); goto again; } logmsg(LL_INFO, "key %08x: revoked\n", keyid); return 0; }
static int update_kernel_key(key_serial_t keyid, struct lgss_nego_data *lnd, gss_buffer_desc *ctx_token) { char *buf = NULL, *p = NULL, *end = NULL; unsigned int buf_size = 0; int rc; logmsg(LL_TRACE, "updating kernel key %08x\n", keyid); buf_size = sizeof(lnd->lnd_seq_win) + sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length + sizeof(ctx_token->length) + ctx_token->length; buf = malloc(buf_size); if (buf == NULL) { logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n", keyid, buf_size); return 1; } p = buf; end = buf + buf_size; rc = -1; if (WRITE_BYTES(&p, end, lnd->lnd_seq_win)) goto out; if (write_buffer(&p, end, &lnd->lnd_rmt_ctx)) goto out; if (write_buffer(&p, end, ctx_token)) goto out; again: if (keyctl_update(keyid, buf, p - buf)) { if (errno != EAGAIN) { logmsg(LL_ERR, "update key %08x: %s\n", keyid, strerror(errno)); goto out; } logmsg(LL_DEBUG, "key %08x: updating too soon, try again\n", keyid); sleep(2); goto again; } rc = 0; logmsg(LL_DEBUG, "key %08x: updated\n", keyid); out: free(buf); return rc; }
int reauthorize_prepare (const char *user, const char *password, long keyring, long *out_key) { struct crypt_data *cd = NULL; key_serial_t key; const char *secret; char *salt = NULL; ssize_t salt_len; char *name = NULL; key_perm_t perm; int ret; if (password == NULL) { debug ("no password available for user %s", user); return 0; } /* The salt already contains algorithm prefix and suffix */ ret = generate_salt (&salt); if (ret < 0) { message ("couldn't generate crypt salt: %m"); goto out; } cd = calloc (1, sizeof (struct crypt_data)); if (!cd) { message ("couldn't allocate crypt data"); ret = -ENOMEM; goto out; } secret = crypt_r (password, salt, cd); if (!secret) { ret = -errno; message ("couldn't crypt reauthorize secret: %m"); goto out; } /* * Double check that our assumptions about crypt() work * as expected. We're later going to be sending away the * salt as a challenge, so guarantee that it works. */ salt_len = parse_salt (secret); if (salt_len != strlen (salt) || memcmp (secret, salt, salt_len) != 0) { ret = -EINVAL; message ("got invalid result from crypt"); goto out; } if (asprintf (&name, "reauthorize/secret/%s", user) < 0) { ret = -ENOMEM; message ("couldn't allocate keyring name"); goto out; } /* * Don't put our secret into the session keyring until the permissions * are strong enough. Since we want that to be atomic, first store in * our thread keyring, and then link below. */ if (keyring == 0) keyring = KEY_SPEC_SESSION_KEYRING; key = add_key ("user", name, "xxx", 3, keyring); if (key < 0) { ret = -errno; message ("couldn't create key in kernel session keyring: %s: %m", name); goto out; } /* Set permissions, and double check that what we expect happened */ perm = KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | KEY_USR_SEARCH | KEY_USR_LINK; if (keyctl_setperm (key, perm) < 0) { ret = -errno; message ("couldn't set permissions on kernel key: %s: %m", name); goto out; } if (keyctl_update (key, secret, strlen (secret))) { ret = -errno; message ("couldn't update secret reauthorize key in kernel keyring: %s: %m", name); goto out; } debug ("placed secret in kernel session keyring"); *out_key = key; ret = 0; out: secfree (cd, sizeof (struct crypt_data)); free (name); free (salt); return ret; }