#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
#include <DirectoryService/DirectoryService.h>
#include <libopendirectorycommon.h>
tDirNodeReference getusernode(tDirReference dirRef, const char *userName)
{
tDirStatus status = eDSNoErr;
long bufferSize = 1024 * 10;
unsigned long returnCount = 0;
tDataBufferPtr dataBuffer = NULL;
tDirNodeReference searchNodeRef = 0;
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(dirRef, bufferSize);
if (dataBuffer == NULL) goto cleanup;
status = dsFindDirNodes(dirRef, dataBuffer, NULL, eDSSearchNodeName, &returnCount, NULL);
if ((status != eDSNoErr) || (returnCount <= 0)) goto cleanup;
status = dsGetDirNodeName(dirRef, dataBuffer, 1, &searchNodeName);
if (status != eDSNoErr) goto cleanup;
status = dsOpenDirNode(dirRef, searchNodeName, &searchNodeRef);
if (status != eDSNoErr) goto cleanup;
recName = dsBuildListFromStrings(dirRef, userName, NULL);
recType = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, NULL);
attrType = dsBuildListFromStrings(dirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
status = dsGetRecordList(searchNodeRef, dataBuffer, recName, eDSiExact, recType, attrType, 0, &returnCount, NULL);
if (status != eDSNoErr) goto cleanup;
status = dsGetRecordEntry(searchNodeRef, dataBuffer, 1, &attributeListRef, &outRecordEntryPtr);
if (status == eDSNoErr)
{
for (i = 1 ; i <= outRecordEntryPtr->fRecordAttributeCount; i++)
{
status = dsGetAttributeEntry(searchNodeRef, dataBuffer, attributeListRef, i, &attributeValueListRef, &attributeInfo);
status = dsGetAttributeValue(searchNodeRef, dataBuffer, 1, attributeValueListRef, &attrValue);
if (status == eDSNoErr)
{
if (strncmp(attributeInfo->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation, strlen(kDSNAttrMetaNodeLocation)) == 0)
{
strncpy(userNodePathStr, attrValue->fAttributeValueData.fBufferData, attrValue->fAttributeValueData.fBufferSize);
} else if (strncmp(attributeInfo->fAttributeSignature.fBufferData, kDSNAttrRecordName, strlen(kDSNAttrRecordName)) == 0) {
strncpy(recUserName, attrValue->fAttributeValueData.fBufferData, attrValue->fAttributeValueData.fBufferSize);
}
}
if (attrValue != NULL) {
dsDeallocAttributeValueEntry(dirRef, attrValue);
attrValue = NULL;
}
if (attributeValueListRef != 0)
{
dsCloseAttributeValueList(attributeValueListRef);
attributeValueListRef = 0;
}
if (attributeInfo != NULL) {
dsDeallocAttributeEntry(dirRef, attributeInfo);
attributeInfo = NULL;
}
}
if (outRecordEntryPtr != NULL) {
dsDeallocRecordEntry(dirRef, outRecordEntryPtr);
outRecordEntryPtr = NULL;
}
if (strlen(userNodePathStr) != 0 && strlen(recUserName) != 0)
{
userNodePath = dsBuildFromPath(dirRef, userNodePathStr, "/");
status = dsOpenDirNode(dirRef, userNodePath, &userNodeRef);
dsDataListDeallocate( dirRef, userNodePath);
free(userNodePath);
}
}
cleanup:
if (dataBuffer != NULL)
dsDataBufferDeAllocate(dirRef, dataBuffer);
if (searchNodeName != NULL)
{
dsDataListDeallocate(dirRef, searchNodeName);
free(searchNodeName);
}
if (searchNodeRef != 0)
dsCloseDirNode(searchNodeRef);
if (recName != NULL)
{
dsDataListDeallocate(dirRef, recName);
free(recName);
}
if (recType != NULL)
{
dsDataListDeallocate(dirRef, recType);
free(recType);
}
if (attrType != NULL)
{
dsDataListDeallocate(dirRef, attrType);
free(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;
};
}
tDirStatus opendirectory_auth_user(tDirReference dirRef, tDirNodeReference userNode, const char* user, u_int8_t *challenge, u_int8_t *password, char *inAuthMethod)
{
tDirStatus status = eDSNoErr;
tDirStatus bufferStatus = eDSNoErr;
unsigned long curr = 0;
unsigned long len = 0;
tDataBufferPtr authBuff = NULL;
tDataBufferPtr stepBuff = NULL;
tDataNodePtr authType = NULL;
authBuff = dsDataBufferAllocate( dirRef, 2048 );
if ( authBuff != NULL )
{
stepBuff = dsDataBufferAllocate( dirRef, 2048 );
if ( stepBuff != NULL )
{
authType = dsDataNodeAllocateString( dirRef, 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 );
if ( status == eDSNoErr )
{
DEBUG(1,("User \"%s\" authenticated successfully with \"%s\" :)\n", user, inAuthMethod ));
}
else
{
DEBUG(1,("User \"%s\" failed to authenticate with \"%s\" (%d) :(\n", user, inAuthMethod,status) );
}
}
bufferStatus = dsDataBufferDeAllocate( dirRef, stepBuff );
if ( bufferStatus != eDSNoErr )
{
DEBUG(1,("*** dsDataBufferDeAllocate(2) faild with error = %d: \n", bufferStatus) );
}
}
else
{
DEBUG(1,("*** dsDataBufferAllocate(2) faild with \n" ));
}
bufferStatus = dsDataBufferDeAllocate( dirRef, authBuff );
if ( bufferStatus != eDSNoErr )
{
DEBUG(1,( "*** dsDataBufferDeAllocate(2) faild with error = %d: \n", bufferStatus ));
}
}
else
{
DEBUG(1,("*** dsDataBufferAllocate(1) faild with \n" ));
}
if (authType != NULL)
dsDataNodeDeAllocate(dirRef, authType);
return status;
}
tDirStatus opendirectory_ntlmv2_auth_user(tDirReference dirRef, tDirNodeReference userNode, const char* user, const char* domain,
const DATA_BLOB *sec_blob, const DATA_BLOB *ntv2_response, DATA_BLOB *user_sess_key)
{
tDirStatus status = eDSNoErr;
tDirStatus bufferStatus = eDSNoErr;
unsigned long curr = 0;
unsigned long len = 0;
tDataBufferPtr authBuff = NULL;
tDataBufferPtr stepBuff = NULL;
tDataNodePtr authType = NULL;
authBuff = dsDataBufferAllocate( dirRef, 2048 );
if ( authBuff != NULL )
{
stepBuff = dsDataBufferAllocate( dirRef, 2048 );
if ( stepBuff != NULL )
{
authType = dsDataNodeAllocateString( dirRef, "dsAuthMethodStandard:dsAuthNodeNTLMv2");
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 );
if ( status == eDSNoErr )
{
DEBUG(1,("User \"%s\" authenticated successfully with \"%s\" :)\n", user, "dsAuthMethodStandard:dsAuthNodeNTLMv2" ));
}
else
{
DEBUG(1,("User \"%s\" failed to authenticate with \"%s\" (%d) :(\n", user, "dsAuthMethodStandard:dsAuthNodeNTLMv2",status) );
}
}
bufferStatus = dsDataBufferDeAllocate( dirRef, stepBuff );
if ( bufferStatus != eDSNoErr )
{
DEBUG(1,("*** dsDataBufferDeAllocate(2) faild with error = %d: \n", bufferStatus) );
}
}
else
{
DEBUG(1,("*** dsDataBufferAllocate(2) faild with \n" ));
}
bufferStatus = dsDataBufferDeAllocate( dirRef, authBuff );
if ( bufferStatus != eDSNoErr )
{
DEBUG(1,( "*** dsDataBufferDeAllocate(2) faild with error = %d: \n", bufferStatus ));
}
}
else
{
DEBUG(1,("*** dsDataBufferAllocate(1) faild with \n" ));
}
if (authType != NULL)
dsDataNodeDeAllocate(dirRef, authType);
return status;
}
static tDirStatus opendirectory_smb_pwd_check_ntlmv1(tDirReference dirRef, tDirNodeReference userNode, const char *user, 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(0, ("opendirectory_smb_pwd_check_ntlmv1: incorrect challenge size (%ld)\n", sec_blob->length));
return eDSAuthFailed;
}
if (nt_response->length != 24) {
DEBUG(0, ("opendirectory_smb_pwd_check_ntlmv1: 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(dirRef, userNode, user, sec_blob->data, nt_response->data, user_sess_key->data, &key_length, NULL);
unbecome_root();
}
if (eDSAuthMethodNotSupported == status || eNotHandledByThisNode == status || (strcmp(inAuthMethod,kDSStdAuthSMB_LM_Key) == 0))
{
status = opendirectory_auth_user(dirRef, userNode,(const char*) user, sec_blob->data, nt_response->data, inAuthMethod);
DEBUG(1, ("opendirectory_smb_pwd_check_ntlmv1: [%d]opendirectory_auth_user\n", status));
if (user_sess_key != NULL)
{
*user_sess_key = data_blob(NULL, 16);
become_root();
keyStatus = opendirectory_user_session_key(dirRef, userNode, user, user_sess_key->data, NULL);
unbecome_root();
DEBUG(2, ("opendirectory_smb_pwd_check_ntlmv1: [%d]opendirectory_user_session_key\n", keyStatus));
}
} else {
DEBUG(1, ("opendirectory_smb_pwd_check_ntlmv1: [%d]opendirectory_user_auth_and_session_key key_length(%d)\n", status, key_length));
}
return (status);
}
static tDirStatus opendirectory_smb_pwd_check_ntlmv2(tDirReference dirRef, 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(0, ("opendirectory_smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n",
(unsigned long)sec_blob->length));
return False;
}
if (ntv2_response->length < 24) {
DEBUG(0, ("opendirectory_smb_pwd_check_ntlmv2: incorrect password length (%lu)\n",
(unsigned long)ntv2_response->length));
return False;
}
status = opendirectory_ntlmv2_auth_user(dirRef, userNode, user, domain, sec_blob, ntv2_response, user_sess_key );
DEBUG(4, ("opendirectory_smb_pwd_check_ntlmv2: [%d]opendirectory_[%s]_auth_user\n", status, ntv2_response->length == 24 ? "LMv2" : "NTLMv2"));
if (eDSNoErr == 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, NULL);
unbecome_root();
DEBUG(2, ("opendirectory_smb_pwd_check_ntlmv2: [%d]opendirectory_[%s]user_session_key len(%d)\n", keyStatus, ntv2_response->length == 24 ? "LMv2" : "NTLMv2", session_key_len));
}
}
return (status);
}
NTSTATUS opendirectory_opendirectory_ntlm_password_check(tDirReference dirRef, 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 != 0 && nt_response->length < 24) {
DEBUG(2,("opendirectory_ntlm_password_check: invalid NT password length (%lu) for user %s\n",
(unsigned long)nt_response->length, username));
}
if (nt_response->length >= 24) {
if (nt_response->length > 24) {
DEBUG(4,("opendirectory_ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, nt_response,
challenge,
client_username,
client_domain,
False,
user_sess_key)) == eDSNoErr)
{
#if DEBUG_LMv2
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password with domain [%s]\n", client_domain));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, lm_response,
challenge,
client_username,
client_domain,
False,
user_sess_key)) == eDSNoErr)
{
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password with domain [%s]\n", client_domain));
} else {
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password with domain [%s]\n", client_domain));
}
#endif
return NT_STATUS_OK;
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, nt_response,
challenge,
client_username,
client_domain,
True,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking NTLMv2 password without a domain\n"));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, nt_response,
challenge,
client_username,
"",
False,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
} else {
DEBUG(3,("opendirectory_ntlm_password_check: NTLMv2 password check failed\n"));
return map_dserr_to_nterr(dirStatus);
}
}
if (lp_ntlm_auth() || (nt_interactive_pwd && nt_interactive_pwd->length)) {
DEBUG(4,("opendirectory_ntlm_password_check: Checking NT MD4 password\n"));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv1(dirRef, userNode, username, kDSStdAuthSMB_NT_Key,
nt_response,
challenge,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
} else {
DEBUG(3,("opendirectory_ntlm_password_check: NT MD4 password check failed for user %s\n",
username));
return map_dserr_to_nterr(dirStatus);
}
} else {
DEBUG(2,("opendirectory_ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
username));
}
}
if (lm_response->length == 0) {
DEBUG(3,("opendirectory_ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
username));
return NT_STATUS_WRONG_PASSWORD;
}
if (lm_response->length < 24) {
DEBUG(2,("opendirectory_ntlm_password_check: invalid LanMan password length (%lu) for user %s\n",
(unsigned long)nt_response->length, username));
return NT_STATUS_WRONG_PASSWORD;
}
if (!lp_lanman_auth()) {
DEBUG(3,("opendirectory_ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
username));
} else {
DEBUG(4,("opendirectory_ntlm_password_check: Checking LM password\n"));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv1(dirRef, userNode, username, kDSStdAuthSMB_LM_Key,
lm_response,
challenge,
NULL)) == eDSNoErr)
{
return NT_STATUS_OK;
} else {
DEBUG(3,("opendirectory_ntlm_password_check: LM password check failed for user %s\n",username));
}
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, lm_response,
challenge,
client_username,
client_domain,
False,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, lm_response,
challenge,
client_username,
client_domain,
True,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking LMv2 password without a domain\n"));
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv2( dirRef, userNode, lm_response,
challenge,
client_username,
"",
False,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
}
DEBUG(4,("opendirectory_ntlm_password_check: Checking NT MD4 password in LM field\n"));
if (lp_ntlm_auth()) {
if ((dirStatus = opendirectory_smb_pwd_check_ntlmv1(dirRef, userNode, username, kDSStdAuthSMB_NT_Key,
lm_response,
challenge,
user_sess_key)) == eDSNoErr)
{
return NT_STATUS_OK;
}
DEBUG(3,("opendirectory_ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
} else {
DEBUG(3,("opendirectory_ntlm_password_check: 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(tDirReference dirRef, tDirNodeReference userNode,
const struct auth_context *auth_context,
TALLOC_CTX *mem_ctx,
SAM_ACCOUNT *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) {
if (lp_null_passwords()) {
DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
return NT_STATUS_OK;
} else {
DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username));
return NT_STATUS_LOGON_FAILURE;
}
}
return opendirectory_opendirectory_ntlm_password_check(dirRef, 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.str,
user_info->client_domain.str,
user_sess_key, lm_sess_key);
}
static NTSTATUS opendirectory_account_ok(TALLOC_CTX *mem_ctx,
SAM_ACCOUNT *sampass,
const auth_usersupplied_info *user_info)
{
uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
char *workstation_list;
time_t kickoff_time;
DEBUG(4,("opendirectory_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
if (acct_ctrl & ACB_DISABLED) {
DEBUG(1,("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(1,("Account for user '%s' has expired.\n", pdb_get_username(sampass)));
DEBUG(3,("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(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
return NT_STATUS_PASSWORD_MUST_CHANGE;
}
if (must_change_time < time(NULL) && must_change_time != 0) {
DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
DEBUG(1,("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(10,("checking for workstation match %s and %s (len=%d)\n",
tok, user_info->wksta_name.str, user_info->wksta_name.len));
if(strequal(tok, user_info->wksta_name.str)) {
invalid_ws = False;
break;
}
}
if (invalid_ws)
return NT_STATUS_INVALID_WORKSTATION;
}
if (acct_ctrl & ACB_DOMTRUST) {
DEBUG(2,("opendirectory_account_ok: 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(2,("opendirectory_account_ok: 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(4,("opendirectory_account_ok: 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)
{
SAM_ACCOUNT *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;
tDirReference dirRef = 0;
tDirNodeReference userNodeRef = 0;
if (!user_info || !auth_context) {
return NT_STATUS_UNSUCCESSFUL;
}
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) {
return nt_status;
}
if (user_info->internal_username.str && strlen(user_info->internal_username.str)) {
become_root();
ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
unbecome_root();
}
if (ret == False)
{
DEBUG(3,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
pdb_free_sam(&sampass);
return NT_STATUS_NO_SUCH_USER;
}
nt_status = opendirectory_account_ok(mem_ctx, sampass, user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
pdb_free_sam(&sampass);
return nt_status;
}
dirStatus = dsOpenDirService(&dirRef);
if (dirStatus != eDSNoErr)
{
DEBUG(0,("check_opendirectory_security: [%d]dsOpenDirService error\n", dirStatus));
pdb_free_sam(&sampass);
return NT_STATUS_UNSUCCESSFUL;
}
userNodeRef = getusernode(dirRef, pdb_get_username(sampass));
if (userNodeRef != 0)
{
nt_status = opendirectory_password_ok(dirRef, userNodeRef, auth_context, mem_ctx, sampass, user_info, &user_sess_key, &lm_sess_key);
dsCloseDirNode( userNodeRef );
dsCloseDirService(dirRef);
} else {
dsCloseDirService(dirRef);
pdb_free_sam(&sampass);
return NT_STATUS_NO_SUCH_USER;
}
if (!NT_STATUS_IS_OK(nt_status)) {
pdb_free_sam(&sampass);
return nt_status;
}
if (!NT_STATUS_IS_OK(nt_status = make_server_info_sam(server_info, sampass))) {
DEBUG(0,("check_opendirectory_security: 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;
}
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 = "opendirectory";
return NT_STATUS_OK;
}
NTSTATUS init_module(void)
{
return smb_register_auth(AUTH_INTERFACE_VERSION, "opendirectory", auth_init_opendirectory);
}