#include <sys/random.h>
#include "chap.h"
#include "iscsi.h"
#include <sys/iscsi_protocol.h>
#include "iscsiAuthClient.h"
#include "persistent.h"
int
iscsiAuthClientChapAuthRequest(IscsiAuthClient *client,
char *username, unsigned int id, uchar_t *challengeData,
unsigned int challengeLength, uchar_t *responseData,
unsigned int responseLength)
{
iscsi_sess_t *isp = (iscsi_sess_t *)client->userHandle;
IscsiAuthMd5Context context;
uchar_t verifyData[16];
iscsi_radius_props_t p_radius_cfg;
if (isp == NULL) {
return (iscsiAuthStatusFail);
}
if (strcmp(username, isp->sess_auth.username_in) != 0) {
cmn_err(CE_WARN, "iscsi session(%u) failed authentication, "
"received incorrect username from target",
isp->sess_oid);
return (iscsiAuthStatusFail);
}
if (persistent_radius_get(&p_radius_cfg) == ISCSI_NVFILE_SUCCESS &&
p_radius_cfg.r_radius_access == B_TRUE) {
chap_validation_status_type chap_valid_status;
int authStatus;
RADIUS_CONFIG radius_cfg;
if (p_radius_cfg.r_radius_config_valid == B_FALSE) {
return (iscsiAuthStatusFail);
}
if (p_radius_cfg.r_insize == sizeof (in_addr_t)) {
radius_cfg.rad_svr_addr.i_addr.in4.s_addr =
p_radius_cfg.r_addr.u_in4.s_addr;
radius_cfg.rad_svr_addr.i_insize
= sizeof (in_addr_t);
} else if (p_radius_cfg.r_insize == sizeof (in6_addr_t)) {
bcopy(p_radius_cfg.r_addr.u_in6.s6_addr,
radius_cfg.rad_svr_addr.i_addr.in6.s6_addr,
16);
radius_cfg.rad_svr_addr.i_insize = sizeof (in6_addr_t);
} else {
return (iscsiAuthStatusFail);
}
radius_cfg.rad_svr_port = p_radius_cfg.r_port;
bcopy(p_radius_cfg.r_shared_secret,
radius_cfg.rad_svr_shared_secret,
MAX_RAD_SHARED_SECRET_LEN);
radius_cfg.rad_svr_shared_secret_len =
p_radius_cfg.r_shared_secret_len;
chap_valid_status = chap_validate_tgt(
isp->sess_auth.username_in,
isp->sess_auth.username,
challengeData,
challengeLength,
responseData,
responseLength,
id,
RADIUS_AUTHENTICATION,
(void *)&radius_cfg);
switch (chap_valid_status) {
case CHAP_VALIDATION_PASSED:
authStatus = iscsiAuthStatusPass;
break;
case CHAP_VALIDATION_INVALID_RESPONSE:
authStatus = iscsiAuthStatusFail;
break;
case CHAP_VALIDATION_DUP_SECRET:
authStatus = iscsiAuthStatusFail;
break;
case CHAP_VALIDATION_RADIUS_ACCESS_ERROR:
authStatus = iscsiAuthStatusFail;
break;
case CHAP_VALIDATION_BAD_RADIUS_SECRET:
authStatus = iscsiAuthStatusFail;
break;
default:
authStatus = iscsiAuthStatusFail;
break;
}
return (authStatus);
} else {
if ((isp->sess_auth.password_length_in < 1) ||
(isp->sess_auth.password_in[0] == '\0')) {
return (iscsiAuthStatusFail);
}
if (responseLength != sizeof (verifyData)) {
cmn_err(CE_WARN, "iscsi session(%u) failed "
"authentication, received incorrect CHAP response "
"from target", isp->sess_oid);
return (iscsiAuthStatusFail);
}
iscsiAuthMd5Init(&context);
verifyData[0] = id;
iscsiAuthMd5Update(&context, verifyData, 1);
iscsiAuthMd5Update(&context,
(uchar_t *)isp->sess_auth.password_in,
isp->sess_auth.password_length_in);
iscsiAuthMd5Update(&context,
(uchar_t *)challengeData,
challengeLength);
iscsiAuthMd5Final(verifyData, &context);
if (bcmp(responseData, verifyData,
sizeof (verifyData)) == 0) {
return (iscsiAuthStatusPass);
}
cmn_err(CE_WARN, "iscsi session(%u) failed authentication, "
"received incorrect CHAP response from target",
isp->sess_oid);
}
return (iscsiAuthStatusFail);
}
void
iscsiAuthClientChapAuthCancel(IscsiAuthClient * client)
{
}
int
iscsiAuthClientTextToNumber(const char *text, unsigned long *pNumber)
{
char *pEnd;
unsigned long number;
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
if (ddi_strtoul(text + 2, &pEnd, 16, &number) != 0) {
return (1);
}
} else {
if (ddi_strtoul(text, &pEnd, 10, &number) != 0) {
return (1);
}
}
if (*text != '\0' && *pEnd == '\0') {
*pNumber = number;
return (0);
} else {
return (1);
}
}
void
iscsiAuthClientNumberToText(unsigned long number, char *text,
unsigned int length)
{
(void) sprintf(text, "%lu", number);
}
void
iscsiAuthRandomSetData(uchar_t *data, unsigned int length)
{
(void) random_get_pseudo_bytes(data, length);
}
void
iscsiAuthMd5Init(IscsiAuthMd5Context * context)
{
MD5Init(context);
}
void
iscsiAuthMd5Update(IscsiAuthMd5Context *context, uchar_t *data,
unsigned int length)
{
MD5Update(context, data, length);
}
void
iscsiAuthMd5Final(uchar_t *hash, IscsiAuthMd5Context *context)
{
MD5Final(hash, context);
}
int
iscsiAuthClientData(uchar_t *outData, unsigned int *outLength,
uchar_t *inData, unsigned int inLength)
{
if (*outLength < inLength) {
return (1);
}
bcopy(inData, outData, inLength);
*outLength = inLength;
return (0);
}