Exemple #1
0
static int
lookup_shadow_secret (const char *user,
                      char **secret)
{
  struct spwd *sp;

  sp = getspnam_a (user);
  if (!sp)
    {
      if (errno == ENOENT)
        {
          debug ("no shadow for user: %s", user);
          return 0;
        }
      else
        {
          message ("couldn't lookup shadow entry for user: %s: %m", user);
          return -errno;
        }
    }

  if (!sp->sp_pwdp || parse_salt (sp->sp_pwdp) < 0)
    {
      debug ("no valid salted password hash in shadow for user: %s", user);
      free (sp);
      return 0;
    }

  memmove (sp, sp->sp_pwdp, strlen (sp->sp_pwdp) + 1);
  *secret = (char *)sp;
  return 0;
}
Exemple #2
0
static int
build_reauthorize_challenge (const char *user,
                             const char *secret,
                             char **challenge)
{
  int ret;
  char *nonce = NULL;
  char *hex = NULL;
  ssize_t salt_len;
  int len;

  salt_len = parse_salt (secret);
  if (salt_len < 0)
    {
      message ("ignoring invalid reauthorize secret");
      ret = -EINVAL;
      goto out;
    }

  ret = generate_salt (&nonce);
  if (ret < 0)
    {
      errno = -ret;
      message ("unable to generate crypt salt: %m");
      goto out;
    }

  ret = hex_encode (user, -1, &hex);
  if (ret < 0)
    {
      errno = -ret;
      message ("couldn't encode user as hex: %m");
      goto out;
    }

  len = asprintf (challenge, "crypt1:%s:%s:%.*s", hex, nonce, (int)salt_len, secret);
  if (len < 0)
    {
      message ("failed to allocate challenge");
      ret = -ENOMEM;
      goto out;
    }

  /* Double check that we didn't include the whole secret */
  assert ((*challenge)[len - 1] == '$');
  assert (strstr (*challenge, secret) == NULL);
  ret = 0;

out:
  free (nonce);
  free (hex);
  return ret;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}