/*
* This file is part of Cockpit.
*
* Copyright (C) 2014 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see .
*/
#include "config.h"
#include "cockpitcompat.h"
#include "common/cockpitauthorize.h"
#include "common/cockpitmemory.h"
#include
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void
secfree (void *data,
ssize_t len)
{
if (!data)
return;
cockpit_memory_clear (data, len);
free (data);
}
static ssize_t
parse_salt (const char *input)
{
const char *pos;
const char *end;
/*
* Parse a encrypted secret produced by crypt() using one
* of the additional algorithms. Return the length of
* the salt or -1.
*/
if (input[0] != '$')
return -1;
pos = strchr (input + 1, '$');
if (pos == NULL || pos == input + 1)
return -1;
end = strchr (pos + 1, '$');
if (end == NULL || end < pos + 8)
return -1;
/* Full length of the salt */
return (end - input) + 1;
}
char *
cockpit_compat_reply_crypt1 (const char *challenge,
const char *password)
{
struct crypt_data *cd = NULL;
char *response = NULL;
char *nonce = NULL;
char *salt = NULL;
const char *npos;
const char *spos;
char *secret;
char *resp;
int errn = 0;
challenge = cockpit_authorize_subject (challenge, NULL);
if (!challenge)
return NULL;
npos = challenge;
spos = strchr (npos, ':');
if (spos == NULL)
{
g_message ("couldn't parse \"authorize\" message \"challenge\"");
errn = EINVAL;
goto out;
}
nonce = g_strndup (npos, spos - npos);
salt = g_strdup (spos + 1);
if (parse_salt (nonce) < 0 ||
parse_salt (salt) < 0)
{
g_message ("\"authorize\" message \"challenge\" has bad nonce or salt");
errn = EINVAL;
goto out;
}
cd = g_new0 (struct crypt_data, 2);
/*
* This is what we're generating here:
*
* response = "crypt1:" crypt(crypt(password, salt), nonce)
*/
secret = crypt_r (password, salt, cd + 0);
if (secret == NULL)
{
errn = errno;
g_message ("couldn't hash password via crypt: %m");
goto out;
}
resp = crypt_r (secret, nonce, cd + 1);
if (resp == NULL)
{
errn = errno;
g_message ("couldn't hash secret via crypt: %m");
goto out;
}
response = g_strdup_printf ("crypt1:%s", resp);
out:
free (nonce);
free (salt);
secfree (cd, sizeof (struct crypt_data) * 2);
if (!response)
errno = errn;
return response;
}