int reauthorize_perform (const char *user, const char *response, char **challenge) { char *secret = NULL; int ret; if (!user || !challenge) { message ("bad arguments"); ret = -EINVAL; goto out; } if (response != NULL && strcmp (response, "") == 0) { debug ("reauthorize was cancelled"); *challenge = NULL; ret = REAUTHORIZE_NO; goto out; } ret = lookup_reauthorize_secret (user, &secret); if (ret < 0) goto out; if (secret == NULL) { ret = lookup_shadow_secret (user, &secret); if (ret < 0) goto out; } /* This is where we'll plug in GSSAPI auth */ if (secret == NULL) { debug ("no reauthorize secret available"); *challenge = NULL; ret = REAUTHORIZE_NO; } else if (response == NULL) { ret = build_reauthorize_challenge (user, secret, challenge); } else if (strcmp (response, "")) { ret = perform_reauthorize_validate (user, secret, response); } out: secfree (secret, -1); return ret; }
int reauthorize_crypt1 (const char *challenge, const char *password, char **response) { struct crypt_data *cd = NULL; char *nonce = NULL; char *salt = NULL; const char *npos; const char *spos; char *secret; char *resp; int ret; if (strncmp (challenge, "crypt1:", 7) != 0) { message ("reauthorize challenge is not a crypt1"); ret = -EINVAL; goto out; } challenge += 7; spos = NULL; npos = strchr (challenge, ':'); if (npos != NULL) { npos++; spos = strchr (npos, ':'); } if (npos == NULL || spos == NULL) { ret = -EINVAL; message ("couldn't parse reauthorize challenge"); goto out; } nonce = strndup (npos, spos - npos); salt = strdup (spos + 1); if (!nonce || !salt) { ret = -ENOMEM; message ("couldn't allocate memory for challenge fields"); goto out; } if (parse_salt (nonce) < 0 || parse_salt (salt) < 0) { message ("reauthorize challenge has bad nonce or salt"); ret = -EINVAL; goto out; } cd = calloc (2, sizeof (struct crypt_data)); if (cd == NULL) { message ("couldn't allocate crypt data"); ret = -ENOMEM; goto out; } /* * This is what we're generating here: * * response = "crypt1:" crypt(crypt(password, salt), nonce) */ secret = crypt_r (password, salt, cd + 0); if (secret == NULL) { ret = -errno; message ("couldn't hash password via crypt: %m"); goto out; } resp = crypt_r (secret, nonce, cd + 1); if (resp == NULL) { ret = -errno; message ("couldn't hash secret via crypt: %m"); goto out; } if (asprintf (response, "crypt1:%s", resp) < 0) { ret = -ENOMEM; message ("couldn't allocate response"); goto out; } ret = 0; out: free (nonce); free (salt); secfree (cd, sizeof (struct crypt_data) * 2); return ret; }
static int perform_reauthorize_validate (const char *user, const char *secret, const char *response) { struct crypt_data *cd = NULL; char *nonce = NULL; const char *check; ssize_t nonce_len; int ret; assert (user != NULL); assert (secret != NULL); assert (response != NULL); if (strncmp (response, "crypt1:", 7) != 0) { message ("received invalid response"); ret = -EINVAL; goto out; } response += 7; nonce_len = parse_salt (response); if (nonce_len < 0) { message ("ignoring invalid reauthorize response"); ret = -EINVAL; goto out; } nonce = strndup (response, nonce_len); if (!nonce) { message ("couldn't allocate memory for nonce"); ret = -ENOMEM; goto out; } cd = calloc (1, sizeof (struct crypt_data)); if (cd == NULL) { message ("couldn't allocate crypt data context"); ret = -ENOMEM; goto out; } check = crypt_r (secret, nonce, cd); if (check == NULL) { ret = -errno; message ("couldn't crypt data: %m"); goto out; } debug ("expected response is: %s", check); if (strcmp (check, response) != 0) { ret = REAUTHORIZE_NO; message ("user %s reauthorization failed", user); goto out; } message ("user %s was reauthorized", user); ret = REAUTHORIZE_YES; out: free (nonce); secfree (cd, sizeof (struct crypt_data)); return ret; }
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; }