/*
* Copyright (c) 2004, Archie L. Cobbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "sl2tps" nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*/
#include "sls_global.h"
#include "sls_config.h"
/*
* PPP authorization callbacks and configuration.
*/
static ppp_auth_acquire_t sls_auth_acquire;
static ppp_auth_check_t sls_auth_check;
static struct ppp_auth_meth sls_auth_meth = {
sls_auth_acquire,
sls_auth_check,
};
const struct ppp_auth_config sls_auth_config = {
&sls_auth_meth,
{
(1 << PPP_AUTH_CHAP_MSV1)
| (1 << PPP_AUTH_CHAP_MSV2)
| (1 << PPP_AUTH_CHAP_MD5),
(1 << PPP_AUTH_NONE)
}
};
static int
sls_auth_acquire(struct ppp_link *link,
struct ppp_auth_cred *creds, struct ppp_auth_resp *resp)
{
errno = EPROTONOSUPPORT;
return (-1);
}
static int
sls_auth_check(struct ppp_link *link,
const struct ppp_auth_cred *creds, struct ppp_auth_resp *resp)
{
static const struct sls_user *user;
const char *username;
int i;
/* Get username */
switch (creds->type) {
case PPP_AUTH_PAP:
username = creds->u.pap.name;
break;
case PPP_AUTH_CHAP_MSV1:
case PPP_AUTH_CHAP_MSV2:
case PPP_AUTH_CHAP_MD5:
username = creds->u.chap.name;
break;
default:
snprintf(resp->errmsg, sizeof(resp->errmsg),
"unsupported auth type");
return -1;
}
/* Find user */
for (i = 0; i < sls_curconf->users.length
&& strcmp(sls_curconf->users.elems[i].name, username) != 0; i++);
if (i == sls_curconf->users.length) {
snprintf(resp->errmsg, sizeof(resp->errmsg),
"unknown user \"%s\"", username);
return -1;
}
user = &sls_curconf->users.elems[i];
/* Check credentials */
switch (creds->type) {
case PPP_AUTH_PAP:
{
const struct ppp_auth_cred_pap *const pap = &creds->u.pap;
if (strcmp(pap->password, user->password) != 0) {
snprintf(resp->errmsg, sizeof(resp->errmsg),
"wrong password");
return -1;
}
break;
}
case PPP_AUTH_CHAP_MSV1:
{
const struct ppp_auth_cred_chap *const chap = &creds->u.chap;
const struct ppp_auth_cred_chap_msv1 *const rsp = &chap->u.msv1;
u_char buf[PPP_MSOFT_NT_HASH_LEN];
/* Check response */
if (!rsp->use_nt) { /* disallow lan-man hash */
snprintf(resp->errmsg, sizeof(resp->errmsg),
"LAN-MAN hash unacceptable");
return -1;
}
ppp_msoft_nt_challenge_response(chap->chal_data,
user->password, buf);
if (memcmp(rsp->nt_hash, buf, sizeof(buf)) != 0) {
snprintf(resp->errmsg, sizeof(resp->errmsg),
"MSCHAPv1 hash is invalid");
return -1;
}
/* Derive MPPE keys */
ppp_msoft_init_key_v1(0, user->password,
chap->chal_data, resp->mppe.msv1.key_64);
ppp_msoft_init_key_v1(1, user->password,
chap->chal_data, resp->mppe.msv1.key_128);
break;
}
case PPP_AUTH_CHAP_MSV2:
{
const struct ppp_auth_cred_chap *const chap = &creds->u.chap;
const struct ppp_auth_cred_chap_msv2 *const rsp = &chap->u.msv2;
u_char buf[PPP_MSOFT_NT_HASH_LEN];
/* Check response */
ppp_msoft_generate_nt_response(chap->chal_data,
rsp->peer_chal, chap->name, user->password, buf);
if (memcmp(rsp->nt_response, buf, sizeof(buf)) != 0) {
snprintf(resp->errmsg, sizeof(resp->errmsg),
"MSCHAPv2 hash is invalid");
return -1;
}
/* Generate expected authenticator response for reply */
ppp_msoft_generate_authenticator_response(user->password,
rsp->nt_response, rsp->peer_chal, chap->chal_data,
chap->name, resp->authresp);
/* Derive MPPE keys */
for (i = 0; i < 2; i++) {
ppp_msoft_init_key_v2(i, user->password,
rsp->nt_response, resp->mppe.msv2.keys[i]);
}
break;
}
case PPP_AUTH_CHAP_MD5:
{
const struct ppp_auth_cred_chap *const chap = &creds->u.chap;
struct ppp_auth_cred_chap temp;
strlcpy(temp.name, chap->name, sizeof(temp.name));
temp.chal_len = chap->chal_len;
memcpy(temp.chal_data, chap->chal_data, chap->chal_len);
temp.u.md5.id = chap->u.md5.id;
(*ppp_auth_chap_md5.hash)(&temp,
user->password, strlen(user->password));
if (memcmp(temp.u.md5.hash,
chap->u.md5.hash, sizeof(temp.u.md5.hash)) != 0) {
snprintf(resp->errmsg, sizeof(resp->errmsg),
"invalid MD5 hash");
return -1;
}
break;
}
default:
snprintf(resp->errmsg, sizeof(resp->errmsg),
"unsupported auth check");
errno = EPROTONOSUPPORT;
return -1;
}
/* Authorization successful */
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1