--- samba-3.0.26a/source/configure.in~ 2007-12-07 14:48:00.000000000 -0500 +++ samba-3.0.26a/source/configure.in 2007-12-07 15:12:50.000000000 -0500 @@ -4296,6 +4296,50 @@ ) +################################################# +# check for KCRAP support +AC_MSG_CHECKING(whether to use auth_kcrap) +AC_ARG_WITH(kcrap, +[ --with-kcrap={yes/static|module|no} Build KCRAP module for authenticating NTLM against Kerberos password database (default=auto)], +[ case "$withval" in + yes|static) + AC_MSG_RESULT(static) + AC_CHECK_HEADER(kcrap.h) + AC_CHECK_LIB(kcrap, kcrap_try) + default_static_modules="$default_static_modules auth_kcrap" + LIBS="$LIBS -lkcrap" + ;; + module) + AC_MSG_RESULT(module) + AC_CHECK_HEADER(kcrap.h) + AC_CHECK_LIB(kcrap, kcrap_try) + default_shared_modules="$default_shared_modules auth_kcrap" + ;; + no) + AC_MSG_RESULT(no) + ;; + *) + AC_CHECK_HEADER(kcrap.h,[ + AC_CHECK_LIB(kcrap, kcrap_try, [ + AC_MSG_RESULT(yes) + default_static_modules="$default_static_modules auth_kcrap" + LIBS="$LIBS -lkcrap" + ], [ AC_MSG_RESULT(no library) ]) + ], [ AC_MSG_RESULT(no header) ]) + + ;; + esac ], [ + AC_CHECK_HEADER(kcrap.h,[ + AC_CHECK_LIB(kcrap, kcrap_try, [ + AC_MSG_RESULT(yes) + default_static_modules="$default_static_modules auth_kcrap" + LIBS="$LIBS -lkcrap" + ], [ AC_MSG_RESULT(no library) ]) + ], [ AC_MSG_RESULT(no header) ]) + ], +) + + ############################################### # test for where we get crypt() from AC_SEARCH_LIBS(crypt, [crypt], @@ -6081,6 +6117,7 @@ SMB_MODULE(auth_domain, \$(AUTH_DOMAIN_OBJ), "bin/domain.$SHLIBEXT", AUTH) SMB_MODULE(auth_builtin, \$(AUTH_BUILTIN_OBJ), "bin/builtin.$SHLIBEXT", AUTH) SMB_MODULE(auth_script, \$(AUTH_SCRIPT_OBJ), "bin/script.$SHLIBEXT", AUTH) +SMB_MODULE(auth_kcrap, \$(AUTH_KCRAP_OBJ), "bin/kcrap.$SHLIBEXT", AUTH) SMB_SUBSYSTEM(AUTH,auth/auth.o) SMB_MODULE(vfs_default, \$(VFS_DEFAULT_OBJ), "bin/default.$SHLIBEXT", VFS) --- samba-3.0.26a/source/Makefile.in~ 2007-12-07 14:49:35.000000000 -0500 +++ samba-3.0.26a/source/Makefile.in 2007-12-07 15:13:40.000000000 -0500 @@ -446,6 +446,7 @@ AUTH_UNIX_OBJ = auth/auth_unix.o AUTH_WINBIND_OBJ = auth/auth_winbind.o AUTH_SCRIPT_OBJ = auth/auth_script.o +AUTH_KCRAP_OBJ = auth/auth_kcrap.o AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/auth_compat.o \ auth/auth_ntlmssp.o \ @@ -1314,6 +1315,10 @@ @echo "Building plugin $@" @$(SHLD) $(LDSHFLAGS) -o $@ $(AUTH_SCRIPT_OBJ) @SONAMEFLAG@`basename $@` +bin/kcrap.@SHLIBEXT@: proto_exists $(AUTH_KCRAP_OBJ) + @echo "Building plugin $@" + @$(SHLD) $(LDSHFLAGS) -o $@ $(AUTH_KCRAP_OBJ) @SONAMEFLAG@`basename $@` -lkcrap + bin/smbserver.@SHLIBEXT@: proto_exists $(AUTH_SERVER_OBJ) @echo "Building plugin $@" @$(SHLD) $(LDSHFLAGS) -o $@ $(AUTH_SERVER_OBJ) @SONAMEFLAG@`basename $@` --- /dev/null 2007-12-07 15:11:00.000000000 -0500 +++ samba-3.0.26a/source/auth/auth_kcrap.c 2007-12-07 14:21:52.000000000 -0500 @@ -0,0 +1,591 @@ +/* +*/ + +#include "includes.h" +#undef AP_OPTS_USE_SUBKEY +#include +#include +#include + +#undef malloc + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_AUTH + +#define KCRAP_SDATA(VAR,VAL) (VAR).data = (VAL), (VAR).length = strlen((VAR).data) + +struct kcrap_priv_data { + struct kcrap_context *context; + char* keytab_file; +}; + +/**************************************************************************** + Check if a user is allowed to logon at this time. Note this is the + servers local time, as logon hours are just specified as a weekly + bitmask. +****************************************************************************/ + +static BOOL logon_hours_ok(struct samu *sampass) +{ + /* In logon hours first bit is Sunday from 12AM to 1AM */ + const uint8 *hours; + struct tm *utctime; + time_t lasttime; + const char *asct; + uint8 bitmask, bitpos; + + hours = pdb_get_hours(sampass); + if (!hours) { + DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n",pdb_get_username(sampass))); + return True; + } + + lasttime = time(NULL); + utctime = gmtime(&lasttime); + if (!utctime) { + DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n", + pdb_get_username(sampass) )); + return False; + } + + /* find the corresponding byte and bit */ + bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168; + bitmask = 1 << (bitpos % 8); + + if (! (hours[bitpos/8] & bitmask)) { + struct tm *t = localtime(&lasttime); + if (!t) { + asct = "INVALID TIME"; + } else { + asct = asctime(t); + if (!asct) { + asct = "INVALID TIME"; + } + } + + DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to " + "logon at this time (%s).\n", + pdb_get_username(sampass), asct )); + return False; + } + + asct = asctime(utctime); + DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n", + pdb_get_username(sampass), asct ? asct : "UNKNOWN TIME" )); + + return True; +} + + +/**************************************************************************** + Do a specific test for a struct samu being vaild for this connection + (ie not disabled, expired and the like). +****************************************************************************/ + +static NTSTATUS kcrap_account_ok(TALLOC_CTX *mem_ctx, + struct samu *sampass, + const auth_usersupplied_info *user_info) { + uint32 acct_ctrl = pdb_get_acct_ctrl(sampass); + char *workstation_list; + time_t kickoff_time; + + DEBUG(4,("kcrap_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass))); + + /* Quit if the account was disabled. */ + if (acct_ctrl & ACB_DISABLED) { + DEBUG(1,("kcrap_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass))); + return NT_STATUS_ACCOUNT_DISABLED; + } + + /* Quit if the account was locked out. */ + if (acct_ctrl & ACB_AUTOLOCK) { + DEBUG(1,("kcrap_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass))); + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + + /* Quit if the account is not allowed to logon at this time. */ + if (! logon_hours_ok(sampass)) { + return NT_STATUS_INVALID_LOGON_HOURS; + } + + /* Test account expire time */ + + kickoff_time = pdb_get_kickoff_time(sampass); + if (kickoff_time != 0 && time(NULL) > kickoff_time) { + DEBUG(1,("kcrap_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass))); + DEBUG(3,("kcrap_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time)); + return NT_STATUS_ACCOUNT_EXPIRED; + } + + /* Test workstation. Workstation list is comma separated. */ + + 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; + fstring tok; + const char *s = workstation_list; + + const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name); + if (machine_name == NULL) + return NT_STATUS_NO_MEMORY; + + while (next_token(&s, tok, ",", sizeof(tok))) { + DEBUG(10,("kcrap_account_ok: 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 (tok[0] == '+') { + DEBUG(10,("kcrap_account_ok: checking for workstation %s in group: %s\n", + machine_name, tok + 1)); + if (user_in_group(machine_name, tok + 1)) { + invalid_ws = False; + break; + } + } + } + + if (invalid_ws) + return NT_STATUS_INVALID_WORKSTATION; + } + + if (acct_ctrl & ACB_DOMTRUST) { + DEBUG(2,("kcrap_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) { + if (!(user_info->logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) { + DEBUG(2,("kcrap_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) { + if (!(user_info->logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) { + DEBUG(2,("kcrap_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_kcrap_password(const struct auth_context *auth_context, + void *my_private_data, + TALLOC_CTX *mem_ctx, + const auth_usersupplied_info *user_info) { + static const unsigned char zeros[24] = { 0, }; + struct kcrap_priv_data* priv = my_private_data; + struct kcrap_auth_req_data req; + int ret; + char *updomain; + int auth_status; + + if (priv->context == NULL) + priv->context = kcrap_init(priv->keytab_file, NULL); + if (priv->context == NULL) { + DEBUG(1,("check_kcrap_password: KCRAP initialize Internal Error - %s\n", kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } + + bzero(&req, sizeof(req)); + + if (user_info->nt_interactive_pwd.length) { + uchar chal[8]; + uchar p24[24]; + + if (user_info->nt_interactive_pwd.length != 16) { + DEBUG(3,("check_kcrap_password: Interactive logon: Invalid NT password length (%d) supplied for user %s\n", (int)user_info->nt_interactive_pwd.length, + user_info->smb_name)); + return NT_STATUS_INVALID_PARAMETER; + } + + generate_random_buffer(chal, sizeof(chal)); + SMBOWFencrypt(user_info->nt_interactive_pwd.data, chal, p24); + + KCRAP_SDATA(req.chal_type, "NTLM"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = 8; + req.server_challenge.data = chal; + req.response.length = 24; + req.response.data = p24; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLM (Interactive) Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: NTLM (Interactive) password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + /* NOTREACHED */ + } + + /* Check for cleartext netlogon. Used by Exchange 5.5. */ + if (auth_context->challenge.length == 8 && + (memcmp(auth_context->challenge.data, zeros, auth_context->challenge.length) == 0 )) { + + DEBUG(4,("check_kcrap_password: checking plaintext passwords for user %s\n", + user_info->smb_name)); + if (user_info->nt_resp.length) { + uchar chal[8]; + uchar p24[24]; + unsigned char pwhash[16]; + mdfour(pwhash, user_info->nt_resp.data, user_info->nt_resp.length); + + generate_random_buffer(chal, sizeof(chal)); + SMBOWFencrypt(pwhash, chal, p24); + + KCRAP_SDATA(req.chal_type, "NTLM"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = 8; + req.server_challenge.data = chal; + req.response.length = 24; + req.response.data = p24; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLM (PLAIN) Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: NTLM (PLAIN) password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + } else { + return NT_STATUS_NOT_IMPLEMENTED; + } + /* NOTREACHED */ + } + + if (user_info->nt_resp.length > 24) { + DEBUG(4,("check_kcrap_password: Checking NTLMv2 password with domain [%s]\n", user_info->client_domain)); + KCRAP_SDATA(req.chal_type, "NTLM2"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = auth_context->challenge.length; + req.server_challenge.data = auth_context->challenge.data; + req.client_challenge.length = user_info->nt_resp.length-16; + req.client_challenge.data = user_info->nt_resp.data+16; + req.response.length = 16; + req.response.data = user_info->nt_resp.data; + KCRAP_SDATA(req.alt_username, user_info->client_domain); + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status > 0) { + return NT_STATUS_OK; + } + + DEBUG(4,("check_kcrap_password: Checking NTLMv2 password with uppercased version of domain [%s]\n", user_info->client_domain)); + updomain = malloc(strlen(user_info->client_domain)+1); + if (updomain) { + int i; + for (i = 0; i < strlen(user_info->client_domain); i++) + updomain[i] = toupper(user_info->client_domain[i]); + updomain[i] = 0; + } + req.alt_username.data = updomain; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + free(updomain); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status > 0) { + free(updomain); + return NT_STATUS_OK; + } + free(updomain); + + req.alt_username.data = NULL; + req.alt_username.length = 0; + + DEBUG(4,("check_kcrap_password: Checking NTLMv2 password without a domain\n")); + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: NTLMv2 password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + /* NOTREACHED */ + } + + if (user_info->nt_resp.length == 24 && lp_ntlm_auth()) { + DEBUG(4,("check_kcrap_password: Checking NT MD4 password\n")); + KCRAP_SDATA(req.chal_type, "NTLM"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = auth_context->challenge.length; + req.server_challenge.data = auth_context->challenge.data; + req.response.length = 24; + req.response.data = user_info->nt_resp.data; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLM Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: NTLM password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + /* NOTREACHED */ + } + + if (user_info->lm_resp.length < 24) { + DEBUG(3,("check_kcrap_password:: NEITHER LanMan nor NT password supplied for user %s\n", + user_info->smb_name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + + if (memcmp(user_info->lm_resp.data+8, zeros, 16) == 0) { + DEBUG(4,("check_kcrap_password: Checking LMv2 password with domain [%s]\n", user_info->client_domain)); + KCRAP_SDATA(req.chal_type, "NTLM2S"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = auth_context->challenge.length; + req.server_challenge.data = auth_context->challenge.data; + req.client_challenge.length = 8; + req.client_challenge.data = user_info->lm_resp.data; + req.response.length = user_info->nt_resp.length; + req.response.data = user_info->nt_resp.data; + KCRAP_SDATA(req.alt_username, user_info->client_domain); + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP LMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status > 0) { + return NT_STATUS_OK; + } + + + DEBUG(4,("check_kcrap_password: Checking LMv2 password with uppercased version of domain [%s]\n", user_info->client_domain)); + updomain = malloc(strlen(user_info->client_domain)+1); + if (updomain) { + int i; + for (i = 0; i < strlen(user_info->client_domain); i++) + updomain[i] = toupper(user_info->client_domain[i]); + updomain[i] = 0; + } + req.alt_username.data = updomain; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP LMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + free(updomain); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status > 0) { + free(updomain); + return NT_STATUS_OK; + } + free(updomain); + + req.alt_username.data = NULL; + req.alt_username.length = 0; + + DEBUG(4,("check_kcrap_password: Checking LMv2 password without a domain\n")); + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP LMv2 Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: LMv2 password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + /* NOTREACHED */ + } + + if (lp_ntlm_auth()) { + DEBUG(4,("check_kcrap_password: Checking NT MD4 password in LM field\n")); + KCRAP_SDATA(req.chal_type, "NTLM"); + KCRAP_SDATA(req.principal, user_info->smb_name); + req.server_challenge.length = auth_context->challenge.length; + req.server_challenge.data = auth_context->challenge.data; + req.response.length = 24; + req.response.data = user_info->nt_resp.data; + + ret = kcrap_try(priv->context, &req, &auth_status); + if (ret != 0) { + DEBUG(1,("check_kcrap_password: KCRAP NTLM Internal Error for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_INTERNAL_ERROR; + } else if (auth_status == 0) { + DEBUG(3,("check_kcrap_password: NTLM password check failed for user %s - %s\n", + user_info->smb_name, kcrap_errmsg())); + return NT_STATUS_WRONG_PASSWORD; + } else { + return NT_STATUS_OK; + } + /* NOTREACHED */ + } + + DEBUG(4,("check_kcrap_password: No appropiate authentication\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS check_kcrap_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; + int ret; + NTSTATUS nt_status, retstat; + BOOL updated_autolock = False, updated_badpw = False; + + if (!user_info) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!auth_context) { + DEBUG(3,("script_check_user_credentials: no auth_info !\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + /* Can't use the talloc version here, because the returned struct gets + kept on the server_info */ + + if ( !(sampass = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } + + /* get the account information */ + + become_root(); + ret = pdb_getsampwnam(sampass, user_info->internal_username); + unbecome_root(); + + if (ret == False) { + DEBUG(3,("check_kcrap_security: Couldn't find user '%s' in passdb.\n", user_info->internal_username)); + TALLOC_FREE(sampass); + return NT_STATUS_NO_SUCH_USER; + } + + /* see if autolock flag needs to be updated */ + if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) + pdb_update_autolock_flag(sampass, &updated_autolock); + /* Quit if the account was locked out. */ + if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) { + DEBUG(3,("check_kcrap_security: Account for user %s was locked out.\n", pdb_get_username(sampass))); + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + + nt_status = check_kcrap_password(auth_context, my_private_data, mem_ctx, user_info); + + /* Notify passdb backend of login success/failure. If not NT_STATUS_OK the backend doesn't like the login */ + retstat = pdb_update_login_attempts(sampass, NT_STATUS_IS_OK(nt_status)); + if (!NT_STATUS_IS_OK(retstat)) + nt_status = retstat; + + if (!NT_STATUS_IS_OK(nt_status)) { + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) && pdb_get_acct_ctrl(sampass) & ACB_NORMAL) { + pdb_increment_bad_password_count(sampass); + updated_badpw = True; + } else { + pdb_update_bad_password_count(sampass, &updated_badpw); + } + if (updated_autolock || updated_badpw) { + become_root(); + if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass))) + DEBUG(1, ("Failed to modify entry.\n")); + unbecome_root(); + } + TALLOC_FREE(sampass); + return nt_status; + } + + if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && (pdb_get_bad_password_count(sampass) > 0)){ + pdb_set_bad_password_count(sampass, 0, PDB_CHANGED); + pdb_set_bad_password_time(sampass, 0, PDB_CHANGED); + updated_badpw = True; + } + + if (updated_autolock || updated_badpw){ + become_root(); + if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass))) + DEBUG(1, ("Failed to modify entry.\n")); + unbecome_root(); + } + + nt_status = kcrap_account_ok(mem_ctx, sampass, user_info); + + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(sampass); + return nt_status; + } + + become_root(); + nt_status = make_server_info_sam(server_info, sampass); + unbecome_root(); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0,("check_kcrap_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status))); + TALLOC_FREE(sampass); + return nt_status; + } + + (*server_info)->was_mapped |= user_info->was_mapped; + + return nt_status; +} + +static void kcrap_free_private(void** private_data) { + struct kcrap_priv_data* priv = *private_data; + + kcrap_free(priv->context); + if (priv->keytab_file) free(priv->keytab_file); + free(priv); +} + +/* module initialisation */ +static NTSTATUS auth_init_kcrap(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)->name = "kcrap"; + (*auth_method)->auth = check_kcrap_security; + (*auth_method)->private_data = calloc(1, sizeof(struct kcrap_priv_data)); + if ((*auth_method)->private_data == NULL) { + return NT_STATUS_NO_MEMORY; + } + if (param) { + ((struct kcrap_priv_data*)((*auth_method)->private_data))->keytab_file = strdup(param); + } + (*auth_method)->free_private_data = kcrap_free_private; + return NT_STATUS_OK; +} + +NTSTATUS auth_kcrap_init(void) +{ + return smb_register_auth(AUTH_INTERFACE_VERSION, "kcrap", auth_init_kcrap); +}