mirror of
https://github.com/samba-team/samba.git
synced 2025-01-15 23:24:37 +03:00
7a8b82f2ce
(This used to be commit b742d068b889e861599333281e825e45cc8d13a2)
308 lines
9.2 KiB
C
308 lines
9.2 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
Password and authentication handling
|
|
Copyright (C) Jeremy Allison 1996-2001
|
|
Copyright (C) Luke Kenneth Casson Leighton 1996-1998
|
|
Copyright (C) Gerald (Jerry) Carter 2000-2001
|
|
Copyright (C) Andrew Bartlett 2001-2002
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#undef DBGC_CLASS
|
|
#define DBGC_CLASS DBGC_SAM
|
|
|
|
/************************************************************
|
|
Fill the SAM_ACCOUNT_HANDLE with default values.
|
|
***********************************************************/
|
|
|
|
static void sam_fill_default_account(SAM_ACCOUNT_HANDLE *account)
|
|
{
|
|
ZERO_STRUCT(account->private); /* Don't touch the talloc context */
|
|
|
|
/* Don't change these timestamp settings without a good reason.
|
|
They are important for NT member server compatibility. */
|
|
|
|
account->private.init_flag = FLAG_SAM_UNINIT;
|
|
|
|
/* FIXME: We should actually call get_nt_time_max() or sthng
|
|
* here */
|
|
unix_to_nt_time(&(account->private.logoff_time),get_time_t_max());
|
|
unix_to_nt_time(&(account->private.kickoff_time),get_time_t_max());
|
|
unix_to_nt_time(&(account->private.pass_must_change_time),get_time_t_max());
|
|
account->private.unknown_1 = 0x00ffffff; /* don't know */
|
|
account->private.logon_divs = 168; /* hours per week */
|
|
account->private.hours_len = 21; /* 21 times 8 bits = 168 */
|
|
memset(account->private.hours, 0xff, account->private.hours_len); /* available at all hours */
|
|
account->private.unknown_2 = 0x00000000; /* don't know */
|
|
account->private.unknown_3 = 0x000004ec; /* don't know */
|
|
}
|
|
|
|
static void destroy_sam_talloc(SAM_ACCOUNT_HANDLE **account)
|
|
{
|
|
if (*account) {
|
|
data_blob_clear_free(&((*account)->private.lm_pw));
|
|
data_blob_clear_free(&((*account)->private.nt_pw));
|
|
if((*account)->private.plaintext_pw!=NULL)
|
|
memset((*account)->private.plaintext_pw,'\0',strlen((*account)->private.plaintext_pw));
|
|
|
|
talloc_destroy((*account)->mem_ctx);
|
|
*account = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
Alloc memory and initialises a SAM_ACCOUNT_HANDLE on supplied mem_ctx.
|
|
***********************************************************************/
|
|
|
|
NTSTATUS sam_init_account_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT_HANDLE **account)
|
|
{
|
|
SMB_ASSERT(*account != NULL);
|
|
|
|
if (!mem_ctx) {
|
|
DEBUG(0,("sam_init_account_talloc: mem_ctx was NULL!\n"));
|
|
return NT_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
*account=(SAM_ACCOUNT_HANDLE *)talloc(mem_ctx, sizeof(SAM_ACCOUNT_HANDLE));
|
|
|
|
if (*account==NULL) {
|
|
DEBUG(0,("sam_init_account_talloc: error while allocating memory\n"));
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
(*account)->mem_ctx = mem_ctx;
|
|
|
|
(*account)->free_fn = NULL;
|
|
|
|
sam_fill_default_account(*account);
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
Alloc memory and initialises a struct sam_passwd.
|
|
************************************************************/
|
|
|
|
NTSTATUS sam_init_account(SAM_ACCOUNT_HANDLE **account)
|
|
{
|
|
TALLOC_CTX *mem_ctx;
|
|
NTSTATUS nt_status;
|
|
|
|
mem_ctx = talloc_init_named("sam internal SAM_ACCOUNT_HANDLE allocation");
|
|
|
|
if (!mem_ctx) {
|
|
DEBUG(0,("sam_init_account: error while doing talloc_init()\n"));
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(nt_status = sam_init_account_talloc(mem_ctx, account))) {
|
|
talloc_destroy(mem_ctx);
|
|
return nt_status;
|
|
}
|
|
|
|
(*account)->free_fn = destroy_sam_talloc;
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* Free the contents of the SAM_ACCOUNT_HANDLE, but not the structure.
|
|
*
|
|
* Also wipes the LM and NT hashes and plaintext password from
|
|
* memory.
|
|
*
|
|
* @param account SAM_ACCOUNT_HANDLE to free members of.
|
|
**/
|
|
|
|
static void sam_free_account_contents(SAM_ACCOUNT_HANDLE *account)
|
|
{
|
|
|
|
/* Kill off sensitive data. Free()ed by the
|
|
talloc mechinism */
|
|
|
|
data_blob_clear_free(&(account->private.lm_pw));
|
|
data_blob_clear_free(&(account->private.nt_pw));
|
|
if (account->private.plaintext_pw)
|
|
memset(account->private.plaintext_pw,'\0',strlen(account->private.plaintext_pw));
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
Reset the SAM_ACCOUNT_HANDLE and free the NT/LM hashes.
|
|
***********************************************************/
|
|
|
|
NTSTATUS sam_reset_sam(SAM_ACCOUNT_HANDLE *account)
|
|
{
|
|
SMB_ASSERT(account != NULL);
|
|
|
|
sam_free_account_contents(account);
|
|
|
|
sam_fill_default_account(account);
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
Free the SAM_ACCOUNT_HANDLE and the member pointers.
|
|
***********************************************************/
|
|
|
|
NTSTATUS sam_free_account(SAM_ACCOUNT_HANDLE **account)
|
|
{
|
|
SMB_ASSERT(*account != NULL);
|
|
|
|
sam_free_account_contents(*account);
|
|
|
|
if ((*account)->free_fn) {
|
|
(*account)->free_fn(account);
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
|
|
/**********************************************************
|
|
Encode the account control bits into a string.
|
|
length = length of string to encode into (including terminating
|
|
null). length *MUST BE MORE THAN 2* !
|
|
**********************************************************/
|
|
|
|
char *sam_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
|
|
{
|
|
static fstring acct_str;
|
|
size_t i = 0;
|
|
|
|
acct_str[i++] = '[';
|
|
|
|
if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
|
|
if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
|
|
if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
|
|
if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
|
|
if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
|
|
if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
|
|
if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
|
|
if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
|
|
if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
|
|
if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
|
|
if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
|
|
|
|
for ( ; i < length - 2 ; i++ )
|
|
acct_str[i] = ' ';
|
|
|
|
i = length - 2;
|
|
acct_str[i++] = ']';
|
|
acct_str[i++] = '\0';
|
|
|
|
return acct_str;
|
|
}
|
|
|
|
/**********************************************************
|
|
Decode the account control bits from a string.
|
|
**********************************************************/
|
|
|
|
uint16 sam_decode_acct_ctrl(const char *p)
|
|
{
|
|
uint16 acct_ctrl = 0;
|
|
BOOL finished = False;
|
|
|
|
/*
|
|
* Check if the account type bits have been encoded after the
|
|
* NT password (in the form [NDHTUWSLXI]).
|
|
*/
|
|
|
|
if (*p != '[')
|
|
return 0;
|
|
|
|
for (p++; *p && !finished; p++) {
|
|
switch (*p) {
|
|
case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
|
|
case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
|
|
case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
|
|
case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
|
|
case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
|
|
case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
|
|
case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
|
|
case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
|
|
case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
|
|
case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
|
|
case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
|
|
case ' ': { break; }
|
|
case ':':
|
|
case '\n':
|
|
case '\0':
|
|
case ']':
|
|
default: { finished = True; }
|
|
}
|
|
}
|
|
|
|
return acct_ctrl;
|
|
}
|
|
|
|
/*************************************************************
|
|
Routine to set 32 hex password characters from a 16 byte array.
|
|
**************************************************************/
|
|
|
|
void sam_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl)
|
|
{
|
|
if (pwd != NULL) {
|
|
int i;
|
|
for (i = 0; i < 16; i++)
|
|
slprintf(&p[i*2], 3, "%02X", pwd[i]);
|
|
} else {
|
|
if (acct_ctrl & ACB_PWNOTREQ)
|
|
safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
|
|
else
|
|
safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
Routine to get the 32 hex characters and turn them
|
|
into a 16 byte array.
|
|
**************************************************************/
|
|
|
|
BOOL sam_gethexpwd(const char *p, unsigned char *pwd)
|
|
{
|
|
int i;
|
|
unsigned char lonybble, hinybble;
|
|
char *hexchars = "0123456789ABCDEF";
|
|
char *p1, *p2;
|
|
|
|
if (!p)
|
|
return (False);
|
|
|
|
for (i = 0; i < 32; i += 2) {
|
|
hinybble = toupper(p[i]);
|
|
lonybble = toupper(p[i + 1]);
|
|
|
|
p1 = strchr(hexchars, hinybble);
|
|
p2 = strchr(hexchars, lonybble);
|
|
|
|
if (!p1 || !p2)
|
|
return (False);
|
|
|
|
hinybble = PTR_DIFF(p1, hexchars);
|
|
lonybble = PTR_DIFF(p2, hexchars);
|
|
|
|
pwd[i / 2] = (hinybble << 4) | lonybble;
|
|
}
|
|
return (True);
|
|
}
|