#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
#undef u32
#include "opendirectory.h"
#define MODULE_NAME "odsam"
static enum ds_trace_level ds_trace = DS_TRACE_ERRORS;
static int module_debug;
static tDirNodeReference getusernode(struct opendirectory_session *session,
const char *userName)
{
tDirStatus status = eDSNoErr;
unsigned long returnCount = 0;
tDataBufferPtr dataBuffer = NULL;
tDataListPtr searchNodeName = NULL;
tDirNodeReference userNodeRef = 0;
tDataListPtr userNodePath = NULL;
char userNodePathStr[256] = {0};
char recUserName[128] = {0};
tDataListPtr recName = NULL;
tDataListPtr recType = NULL;
tDataListPtr attrType = NULL;
tAttributeListRef attributeListRef = 0;
tRecordEntryPtr outRecordEntryPtr = NULL;
tAttributeEntryPtr attributeInfo = NULL;
tAttributeValueListRef attributeValueListRef = 0;
tAttributeValueEntryPtr attrValue = NULL;
long i = 0;
dataBuffer = dsDataBufferAllocate(session->ref, DEFAULT_DS_BUFFER_SIZE);
if (dataBuffer == NULL) {
goto cleanup;
}
status = opendirectory_searchnode(session);
LOG_DS_ERROR(ds_trace, status, "opendirectory_searchnode");
if (status != eDSNoErr) {
goto cleanup;
}
recName = dsBuildListFromStrings(session->ref, userName, NULL);
recType = dsBuildListFromStrings(session->ref, kDSStdRecordTypeUsers, NULL);
attrType = dsBuildListFromStrings(session->ref, kDSNAttrMetaNodeLocation,
kDSNAttrRecordName, NULL);
status = dsGetRecordList(session->search, dataBuffer, recName, eDSiExact,
recType, attrType, 0, &returnCount, NULL);
LOG_DS_ERROR(ds_trace, status, "dsGetRecordList");
if (status != eDSNoErr) {
goto cleanup;
}
status = dsGetRecordEntry(session->search, dataBuffer, 1,
&attributeListRef, &outRecordEntryPtr);
LOG_DS_ERROR(ds_trace, status, "dsGetRecordEntry");
if (status != eDSNoErr) {
goto cleanup;
}
for (i = 1 ; i <= outRecordEntryPtr->fRecordAttributeCount; i++) {
status = dsGetAttributeEntry(session->search, dataBuffer,
attributeListRef, i, &attributeValueListRef,
&attributeInfo);
LOG_DS_ERROR(ds_trace, status, "dsGetAttributeEntry");
status = dsGetAttributeValue(session->search, dataBuffer, 1,
attributeValueListRef, &attrValue);
LOG_DS_ERROR(ds_trace, status, "dsGetAttributeValue");
if (status == eDSNoErr) {
if (strncmp(attributeInfo->fAttributeSignature.fBufferData,
kDSNAttrMetaNodeLocation,
strlen(kDSNAttrMetaNodeLocation)) == 0) {
SMB_ASSERT(attrValue->fAttributeValueData.fBufferSize <
sizeof(userNodePathStr));
strncpy(userNodePathStr,
attrValue->fAttributeValueData.fBufferData,
attrValue->fAttributeValueData.fBufferSize);
} else if (strncmp(attributeInfo->fAttributeSignature.fBufferData,
kDSNAttrRecordName, strlen(kDSNAttrRecordName)) == 0) {
SMB_ASSERT(attrValue->fAttributeValueData.fBufferSize <
sizeof(recUserName));
strncpy(recUserName,
attrValue->fAttributeValueData.fBufferData,
attrValue->fAttributeValueData.fBufferSize);
}
}
if (attrValue != NULL) {
dsDeallocAttributeValueEntry(session->ref, attrValue);
attrValue = NULL;
}
if (attributeValueListRef != 0) {
dsCloseAttributeValueList(attributeValueListRef);
attributeValueListRef = 0;
}
if (attributeInfo != NULL) {
dsDeallocAttributeEntry(session->ref, attributeInfo);
attributeInfo = NULL;
}
}
if (outRecordEntryPtr != NULL) {
dsDeallocRecordEntry(session->ref, outRecordEntryPtr);
outRecordEntryPtr = NULL;
}
if (strlen(userNodePathStr) != 0 && strlen(recUserName) != 0) {
userNodePath = dsBuildFromPath(session->ref, userNodePathStr, "/");
status = dsOpenDirNode(session->ref, userNodePath, &userNodeRef);
LOG_DS_ERROR(ds_trace, status, "dsOpenDirNode");
opendirectory_free_list(session, userNodePath);
}
cleanup:
DS_CLOSE_NODE(session->search);
opendirectory_free_buffer(session, dataBuffer);
opendirectory_free_list(session, searchNodeName);
opendirectory_free_list(session, recName);
opendirectory_free_list(session, recType);
opendirectory_free_list(session, attrType);
return userNodeRef;
}
static NTSTATUS map_dserr_to_nterr(tDirStatus dirStatus)
{
switch (dirStatus) {
case (eDSAuthFailed):
case (eDSAuthBadPassword):
return NT_STATUS_WRONG_PASSWORD;
case (eDSAuthAccountInactive):
return NT_STATUS_ACCOUNT_DISABLED;
case (eDSAuthNewPasswordRequired):
case (eDSAuthPasswordExpired):
return NT_STATUS_PASSWORD_MUST_CHANGE;
default:
return NT_STATUS_WRONG_PASSWORD;
}
}
static tDirStatus opendirectory_auth_user(
struct opendirectory_session *session,
tDirNodeReference userNode,
const char* user,
u_int8_t *challenge,
u_int8_t *password,
const char *inAuthMethod)
{
tDirStatus status = eDSAuthServerError;
unsigned long curr = 0;
unsigned long len = 0;
tDataBufferPtr authBuff = NULL;
tDataBufferPtr stepBuff = NULL;
tDataNodePtr authType = NULL;
authBuff = dsDataBufferAllocate( session->ref, 2048 );
if ( authBuff == NULL ) {
DEBUG(module_debug, ("*** dsDataBufferAllocate failed\n" ));
return eMemoryAllocError;
}
stepBuff = dsDataBufferAllocate( session->ref, 2048 );
if ( stepBuff == NULL ) {
dsDataBufferDeAllocate( session->ref, authBuff );
DEBUG(module_debug, ("*** dsDataBufferAllocate failed\n" ));
return eMemoryAllocError;
}
authType = dsDataNodeAllocateString( session->ref, inAuthMethod);
if ( authType != NULL ) {
len = strlen( user );
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof( long );
memcpy( &(authBuff->fBufferData[ curr ]), user, len );
curr += len;
len = 8;
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof (long );
memcpy( &(authBuff->fBufferData[ curr ]), challenge, len );
curr += len;
len = 24;
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof (long );
memcpy( &(authBuff->fBufferData[ curr ]), password, len );
curr += len;
authBuff->fBufferLength = curr;
status = dsDoDirNodeAuth( userNode, authType, True,
authBuff, stepBuff, NULL );
LOG_DS_ERROR(ds_trace, status, "dsDoNodeAuth");
DEBUG(module_debug, ("User \"%s\" %s ""with \"%s\"\n", user,
status == eDSNoErr ? "authenticated successfully"
: "failed to authenticate",
inAuthMethod));
}
opendirectory_free_buffer(session, stepBuff);
opendirectory_free_buffer(session, authBuff);
opendirectory_free_node(session, authType);
return status;
}
static tDirStatus opendirectory_ntlmv2_auth_user(
struct opendirectory_session *session,
tDirNodeReference userNode,
const char* user,
const char* domain,
const DATA_BLOB *sec_blob,
const DATA_BLOB *ntv2_response,
DATA_BLOB *user_sess_key)
{
static const char const method[] =
"dsAuthMethodStandard:dsAuthNodeNTLMv2";
tDirStatus status = eDSAuthServerError;
unsigned long curr = 0;
unsigned long len = 0;
tDataBufferPtr authBuff = NULL;
tDataBufferPtr stepBuff = NULL;
tDataNodePtr authType = NULL;
authBuff = dsDataBufferAllocate( session->ref, 2048 );
if ( authBuff == NULL ) {
DEBUG(module_debug, ("*** dsDataBufferAllocate failed\n" ));
return eMemoryAllocError;
}
stepBuff = dsDataBufferAllocate( session->ref, 2048 );
if ( stepBuff == NULL ) {
dsDataBufferDeAllocate( session->ref, authBuff );
DEBUG(module_debug, ("*** dsDataBufferAllocate failed\n" ));
return eMemoryAllocError;
}
authType = dsDataNodeAllocateString( session->ref, method );
if ( authType != NULL ) {
len = strlen( user );
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof( long );
memcpy( &(authBuff->fBufferData[ curr ]), user, len );
curr += len;
len = 8;
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof (long );
memcpy( &(authBuff->fBufferData[ curr ]), sec_blob->data, len );
curr += len;
len = ntv2_response->length;
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof (long );
memcpy( &(authBuff->fBufferData[ curr ]), ntv2_response->data, len );
curr += len;
len = strlen( user );
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof( long );
memcpy( &(authBuff->fBufferData[ curr ]), user, len );
curr += len;
len = strlen( domain );
memcpy( &(authBuff->fBufferData[ curr ]), &len, 4 );
curr += sizeof( long );
memcpy( &(authBuff->fBufferData[ curr ]), domain, len );
curr += len;
authBuff->fBufferLength = curr;
status = dsDoDirNodeAuth( userNode, authType, True,
authBuff, stepBuff, NULL );
LOG_DS_ERROR(ds_trace, status, "dsDoNodeAuth");
DEBUG(module_debug, ("User \"%s\" %s ""with \"%s\"\n", user,
status == eDSNoErr ? "authenticated successfully"
: "failed to authenticate",
method));
}
opendirectory_free_buffer(session, stepBuff);
opendirectory_free_buffer(session, authBuff);
opendirectory_free_node(session, authType);
return status;
}
static tDirStatus opendirectory_smb_pwd_check_ntlmv1(
struct opendirectory_session *session,
tDirNodeReference userNode,
const char *user,
const char *inAuthMethod,
const DATA_BLOB *nt_response,
const DATA_BLOB *sec_blob,
DATA_BLOB *user_sess_key)
{
tDirStatus status = eDSAuthFailed;
tDirStatus keyStatus = eDSAuthFailed;
u_int32_t key_length = 0;
if (sec_blob->length != 8) {
DEBUG(module_debug, ("incorrect challenge size (%ld)\n",
sec_blob->length));
return eDSAuthFailed;
}
if (nt_response->length != 24) {
DEBUG(module_debug, ("incorrect password length (%ld)\n",
nt_response->length));
return eDSAuthFailed;
}
if ((user_sess_key != NULL) &&
(strcmp(inAuthMethod,kDSStdAuthSMB_NT_Key) == 0) ) {
*user_sess_key = data_blob(NULL, 16);
become_root();
status = opendirectory_user_auth_and_session_key(session,
userNode, user, sec_blob->data,
nt_response->data, user_sess_key->data,
&key_length);
unbecome_root();
LOG_DS_ERROR(ds_trace, status,
"opendirectory_user_auth_and_session_key");
}
if (eDSAuthMethodNotSupported == status ||
eNotHandledByThisNode == status ||
(strcmp(inAuthMethod,kDSStdAuthSMB_LM_Key) == 0)) {
status = opendirectory_auth_user(session, userNode, user,
sec_blob->data, nt_response->data, inAuthMethod);
LOG_DS_ERROR(ds_trace, status,
"opendirectory_auth_user");
if (user_sess_key != NULL) {
*user_sess_key = data_blob(NULL, 16);
become_root();
keyStatus = opendirectory_user_session_key(session,
userNode, user, user_sess_key->data);
unbecome_root();
LOG_DS_ERROR(ds_trace, status,
"opendirectory_user_session_key");
}
}
return status;
}
static tDirStatus opendirectory_smb_pwd_check_ntlmv2(
struct opendirectory_session *session,
tDirNodeReference userNode,
const DATA_BLOB *ntv2_response,
const DATA_BLOB *sec_blob,
const char *user, const char *domain,
BOOL upper_case_domain,
DATA_BLOB *user_sess_key)
{
tDirStatus status = eDSAuthFailed;
tDirStatus keyStatus = eDSNoErr;
u_int32_t session_key_len = 0;
if (sec_blob->length != 8) {
DEBUG(module_debug, ("incorrect challenge size (%lu)\n",
(unsigned long)sec_blob->length));
return False;
}
if (ntv2_response->length < 24) {
DEBUG(module_debug, ("incorrect password length (%lu)\n",
(unsigned long)ntv2_response->length));
return False;
}
status = opendirectory_ntlmv2_auth_user(session, userNode, user,
domain, sec_blob, ntv2_response, user_sess_key );
LOG_DS_ERROR(ds_trace, status, "opendirectory_ntlmv2_auth_user");
if (eDSNoErr != status) {
return status;
}
if (user_sess_key != NULL) {
*user_sess_key = data_blob(NULL, 16);
become_root();
keyStatus = opendirectory_ntlmv2user_session_key(user,
ntv2_response->length, ntv2_response->data,
domain, &session_key_len, user_sess_key->data);
unbecome_root();
LOG_DS_ERROR_MSG(ds_trace, status,
"opendirectory_ntlmv2user_session_key",
("%u byte session key (%s)\n",
session_key_len,
ntv2_response->length == 24 ? "LMv2" : "NTLMv2"));
}
return (status);
}
static NTSTATUS
opendirectory_opendirectory_ntlm_password_check(
struct opendirectory_session *session,
tDirNodeReference userNode,
TALLOC_CTX *mem_ctx,
const DATA_BLOB *challenge,
const DATA_BLOB *lm_response,
const DATA_BLOB *nt_response,
const DATA_BLOB *lm_interactive_pwd,
const DATA_BLOB *nt_interactive_pwd,
const char *username,
const char *client_username,
const char *client_domain,
DATA_BLOB *user_sess_key,
DATA_BLOB *lm_sess_key)
{
tDirStatus dirStatus = eDSAuthFailed;
if (nt_response->length > 24) {
DEBUG(module_debug,("Checking NTLMv2 password with domain [%s]\n",
client_domain));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session,
userNode, nt_response,
challenge,
client_username,
client_domain,
False,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus == eDSNoErr) {
#if DEBUG_LMv2
DEBUG(module_debug,("Checking LMv2 password with domain [%s]\n",
client_domain));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session,
userNode, lm_response,
challenge,
client_username,
client_domain,
False,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
#endif
return NT_STATUS_OK;
}
DEBUG(module_debug,("Checking NTLMv2 password with uppercase domain [%s]\n",
client_domain));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session,
userNode, nt_response,
challenge,
client_username,
client_domain,
True,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus == eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("Checking NTLMv2 password without a domain\n"));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session,
userNode, nt_response,
challenge,
client_username,
"",
False,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus == eDSNoErr) {
return NT_STATUS_OK;
}
return map_dserr_to_nterr(dirStatus);
}
if (nt_response->length == 24) {
if (lp_ntlm_auth() ||
(nt_interactive_pwd && nt_interactive_pwd->length)) {
DEBUG(module_debug,("Checking NT MD4 password\n"));
dirStatus =
opendirectory_smb_pwd_check_ntlmv1(session,
userNode, username,
kDSStdAuthSMB_NT_Key,
nt_response,
challenge,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv1");
if (dirStatus == eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("NT MD4 password check failed for user %s\n",
username));
return map_dserr_to_nterr(dirStatus);
}
DEBUG(module_debug,("NTLMv1 passwords NOT PERMITTED for user %s\n",
username));
}
if (lm_response->length == 0) {
DEBUG(module_debug,("NEITHER LanMan nor NT password supplied for user %s\n",
username));
return NT_STATUS_ILL_FORMED_PASSWORD;
}
if (lm_response->length < 24) {
DEBUG(module_debug,("invalid LanMan password length (%lu) for user %s\n",
(unsigned long)nt_response->length, username));
return NT_STATUS_ILL_FORMED_PASSWORD;
}
if (lp_lanman_auth()) {
DEBUG(module_debug,("Checking LM password\n"));
dirStatus = opendirectory_smb_pwd_check_ntlmv1(session,
userNode, username,
kDSStdAuthSMB_LM_Key,
lm_response,
challenge,
NULL);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv1");
if (dirStatus == eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("LM password check failed for user %s\n",username));
}
DEBUG(module_debug,("Checking LMv2 password with domain %s\n", client_domain));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session, userNode,
lm_response,
challenge,
client_username,
client_domain,
False,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus== eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("Checking LMv2 password with upper-cased domain %s\n",
client_domain));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session, userNode,
lm_response,
challenge,
client_username,
client_domain,
True,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus== eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("Checking LMv2 password without a domain\n"));
dirStatus = opendirectory_smb_pwd_check_ntlmv2(session, userNode,
lm_response,
challenge,
client_username,
"",
False,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv2");
if (dirStatus== eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("Checking NT MD4 password in LM field\n"));
if (lp_ntlm_auth()) {
dirStatus = opendirectory_smb_pwd_check_ntlmv1(session,
userNode, username,
kDSStdAuthSMB_NT_Key,
lm_response,
challenge,
user_sess_key);
LOG_DS_ERROR(ds_trace, dirStatus,
"opendirectory_smb_pwd_check_ntlmv1");
if (dirStatus== eDSNoErr) {
return NT_STATUS_OK;
}
DEBUG(module_debug,("LM password, NT MD4 password in LM field "
"and LMv2 failed for user %s\n",username));
}
DEBUG(module_debug,("LM password and LMv2 failed for user %s, "
"and NT MD4 password in LM field not permitted\n",username));
return NT_STATUS_WRONG_PASSWORD;
}
static NTSTATUS opendirectory_password_ok(
struct opendirectory_session *session,
tDirNodeReference userNode,
const struct auth_context *auth_context,
TALLOC_CTX *mem_ctx,
struct samu *sampass,
const auth_usersupplied_info *user_info,
DATA_BLOB *user_sess_key,
DATA_BLOB *lm_sess_key)
{
uint16 acct_ctrl;
const char *username = pdb_get_username(sampass);
acct_ctrl = pdb_get_acct_ctrl(sampass);
if (acct_ctrl & ACB_PWNOTREQ) {
DEBUG(module_debug,("Account for user '%s' has no password "
"and null passwords %s allowed.\n",
lp_null_passwords() ? "are" : "are NOT",
username));
return lp_null_passwords() ? NT_STATUS_OK
: NT_STATUS_LOGON_FAILURE;
}
return opendirectory_opendirectory_ntlm_password_check(session,
userNode, mem_ctx, &auth_context->challenge,
&user_info->lm_resp, &user_info->nt_resp,
&user_info->lm_interactive_pwd,
&user_info->nt_interactive_pwd,
username,
user_info->smb_name,
user_info->client_domain,
user_sess_key, lm_sess_key);
}
static NTSTATUS opendirectory_account_ok(TALLOC_CTX *mem_ctx,
struct samu *sampass,
const auth_usersupplied_info *user_info)
{
uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
char *workstation_list;
time_t kickoff_time;
DEBUG(module_debug,("Checking SMB password for user %s\n",
pdb_get_username(sampass)));
if (acct_ctrl & ACB_DISABLED) {
DEBUG(module_debug,("Account for user '%s' was disabled.\n",
pdb_get_username(sampass)));
return NT_STATUS_ACCOUNT_DISABLED;
}
kickoff_time = pdb_get_kickoff_time(sampass);
if (kickoff_time != 0 && time(NULL) > kickoff_time) {
DEBUG(module_debug,("Account for user '%s' has expired.\n",
pdb_get_username(sampass)));
DEBUG(module_debug,("Account expired at '%ld' unix time.\n",
(long)kickoff_time));
return NT_STATUS_ACCOUNT_EXPIRED;
}
if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) {
time_t must_change_time = pdb_get_pass_must_change_time(sampass);
time_t last_set_time = pdb_get_pass_last_set_time(sampass);
if (must_change_time == 0 && last_set_time != 0) {
DEBUG(module_debug,("Password for user '%s' must change!\n",
pdb_get_username(sampass)));
return NT_STATUS_PASSWORD_MUST_CHANGE;
}
if (must_change_time < time(NULL) && must_change_time != 0) {
DEBUG(module_debug,("Password for user '%s' has expired!\n",
pdb_get_username(sampass)));
DEBUG(module_debug,("Password expired at '%s' (%ld) unix time.\n",
http_timestring(must_change_time),
(long)must_change_time));
return NT_STATUS_PASSWORD_EXPIRED;
}
}
workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
if (!workstation_list) return NT_STATUS_NO_MEMORY;
if (*workstation_list) {
BOOL invalid_ws = True;
const char *s = workstation_list;
fstring tok;
while (next_token(&s, tok, ",", sizeof(tok))) {
DEBUG(module_debug,("checking for workstation match %s and %s\n",
tok, user_info->wksta_name));
if(strequal(tok, user_info->wksta_name)) {
invalid_ws = False;
break;
}
}
if (invalid_ws)
return NT_STATUS_INVALID_WORKSTATION;
}
if (acct_ctrl & ACB_DOMTRUST) {
DEBUG(module_debug,("Domain trust account %s denied by server\n",
pdb_get_username(sampass)));
return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
}
if (acct_ctrl & ACB_SVRTRUST) {
DEBUG(module_debug,("Server trust account %s denied by server\n",
pdb_get_username(sampass)));
return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
}
if (acct_ctrl & ACB_WSTRUST) {
DEBUG(module_debug,("Wksta trust account %s denied by server\n",
pdb_get_username(sampass)));
return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
}
return NT_STATUS_OK;
}
static NTSTATUS check_opendirectory_security(
const struct auth_context *auth_context,
void *my_private_data,
TALLOC_CTX *mem_ctx,
const auth_usersupplied_info *user_info,
auth_serversupplied_info **server_info)
{
struct samu *sampass=NULL;
BOOL ret = False;
NTSTATUS nt_status = NT_STATUS_OK;
DATA_BLOB user_sess_key = data_blob(NULL, 0);
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
tDirStatus dirStatus = eDSNoErr;
tDirNodeReference userNodeRef = 0;
struct opendirectory_session session;
if (!user_info || !auth_context) {
return NT_STATUS_UNSUCCESSFUL;
}
sampass = samu_new(NULL);
if (!sampass) {
return NT_STATUS_NO_MEMORY;
}
if (user_info->internal_username &&
strlen(user_info->internal_username)) {
become_root();
ret = pdb_getsampwnam(sampass, user_info->internal_username);
unbecome_root();
}
if (ret == False) {
DEBUG(module_debug, ("user '%s' is not in the password database\n",
user_info->internal_username));
TALLOC_FREE(sampass);
return NT_STATUS_NO_SUCH_USER;
}
nt_status = opendirectory_account_ok(mem_ctx, sampass, user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
TALLOC_FREE(sampass);
return nt_status;
}
dirStatus = opendirectory_connect(&session);
LOG_DS_ERROR(ds_trace, dirStatus, "dsOpenDirService");
if (dirStatus != eDSNoErr) {
TALLOC_FREE(sampass);
return NT_STATUS_UNSUCCESSFUL;
}
userNodeRef = getusernode(&session, pdb_get_username(sampass));
if (userNodeRef == 0) {
opendirectory_disconnect(&session);
TALLOC_FREE(sampass);
return NT_STATUS_NO_SUCH_USER;
}
nt_status = opendirectory_password_ok(&session, userNodeRef,
auth_context, mem_ctx, sampass, user_info,
&user_sess_key, &lm_sess_key);
DS_CLOSE_NODE( userNodeRef );
opendirectory_disconnect(&session);
if (!NT_STATUS_IS_OK(nt_status)) {
TALLOC_FREE(sampass);
return nt_status;
}
nt_status = make_server_info_sam(server_info, sampass);
if (!NT_STATUS_IS_OK(nt_status)) {
TALLOC_FREE(sampass);
DEBUG(module_debug, ("make_server_info_sam() failed with '%s'\n",
nt_errstr(nt_status)));
return nt_status;
}
(*server_info)->user_session_key = user_sess_key;
(*server_info)->lm_session_key = lm_sess_key;
return nt_status;
}
static NTSTATUS auth_init_opendirectory(struct auth_context *auth_context,
const char *param, auth_methods **auth_method)
{
if (!make_auth_methods(auth_context, auth_method)) {
return NT_STATUS_NO_MEMORY;
}
(*auth_method)->auth = check_opendirectory_security;
(*auth_method)->name = MODULE_NAME;
return NT_STATUS_OK;
}
static NTSTATUS auth_init_od_historic(struct auth_context *auth_context,
const char *param, auth_methods **auth_method)
{
if (!make_auth_methods(auth_context, auth_method)) {
return NT_STATUS_NO_MEMORY;
}
(*auth_method)->auth = check_opendirectory_security;
(*auth_method)->name = "opendirectory";
return NT_STATUS_OK;
}
NTSTATUS auth_ods_init(void)
{
if (lp_parm_bool(GLOBAL_SECTION_SNUM,
MODULE_NAME, "traceall", False)) {
ds_trace = DS_TRACE_ALL;
}
module_debug = lp_parm_int(GLOBAL_SECTION_SNUM,
MODULE_NAME, "msglevel", 100);
smb_register_auth(AUTH_INTERFACE_VERSION, MODULE_NAME,
auth_init_opendirectory);
smb_register_auth(AUTH_INTERFACE_VERSION, "opendirectory",
auth_init_od_historic);
return NT_STATUS_OK;
}