#include <sys/types.h>
#include <sys/isa_defs.h>
#include <sys/byteorder.h>
#include <alloca.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smb/ntaccess.h>
#include <lsalib.h>
#include <samlib.h>
#ifdef _LITTLE_ENDIAN
#define htolel(x) ((uint32_t)(x))
#define letohl(x) ((uint32_t)(x))
#else
#define letohl(x) BSWAP_32(x)
#define htolel(x) BSWAP_32(x)
#endif
#define SAM_KEYLEN 16
static void samr_fill_userpw(struct samr_user_password *, const char *);
static void samr_make_encrypted_password(
struct samr_encr_passwd *epw,
char *new_pw_clear,
uint8_t *crypt_key);
DWORD
sam_remove_trust_account(char *server, char *domain)
{
char account_name[SMB_SAMACCT_MAXLEN];
if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
return (NT_STATUS_INTERNAL_ERROR);
return (sam_delete_account(server, domain, account_name));
}
DWORD
sam_delete_account(char *server, char *domain_name, char *account_name)
{
mlsvc_handle_t samr_handle;
mlsvc_handle_t domain_handle;
mlsvc_handle_t user_handle;
smb_account_t ainfo;
smb_sid_t *sid;
DWORD access_mask;
DWORD status;
int rc;
char user[SMB_USERNAME_MAXLEN];
smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
&samr_handle);
if (rc != 0)
return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
sid = samr_lookup_domain(&samr_handle, domain_name);
if (sid == NULL) {
status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
goto out_samr_hdl;
}
status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
(struct samr_sid *)sid, &domain_handle);
if (status != NT_STATUS_SUCCESS)
goto out_sid_ptr;
status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
if (status != NT_STATUS_SUCCESS)
goto out_dom_hdl;
access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
status = samr_open_user(&domain_handle, access_mask,
ainfo.a_rid, &user_handle);
if (status != NT_STATUS_SUCCESS)
goto out_dom_hdl;
status = samr_delete_user(&user_handle);
(void) samr_close_handle(&user_handle);
out_dom_hdl:
(void) samr_close_handle(&domain_handle);
out_sid_ptr:
free(sid);
out_samr_hdl:
(void) samr_close_handle(&samr_handle);
return (status);
}
DWORD
sam_lookup_name(char *server, char *domain_name, char *account_name,
DWORD *rid_ret)
{
mlsvc_handle_t samr_handle;
mlsvc_handle_t domain_handle;
smb_account_t ainfo;
struct samr_sid *domain_sid;
int rc;
DWORD status;
char user[SMB_USERNAME_MAXLEN];
smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
*rid_ret = 0;
rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
&samr_handle);
if (rc != 0)
return (NT_STATUS_OPEN_FAILED);
domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle,
domain_name);
if (domain_sid == NULL) {
(void) samr_close_handle(&samr_handle);
return (NT_STATUS_NO_SUCH_DOMAIN);
}
status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
domain_sid, &domain_handle);
if (status == NT_STATUS_SUCCESS) {
status = samr_lookup_domain_names(&domain_handle,
account_name, &ainfo);
if (status == NT_STATUS_SUCCESS)
*rid_ret = ainfo.a_rid;
(void) samr_close_handle(&domain_handle);
}
(void) samr_close_handle(&samr_handle);
return (status);
}
DWORD
sam_get_local_domains(char *server, char *domain_name)
{
mlsvc_handle_t samr_handle;
DWORD status;
int rc;
char user[SMB_USERNAME_MAXLEN];
smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN,
&samr_handle);
if (rc != 0)
return (NT_STATUS_OPEN_FAILED);
status = samr_enum_local_domains(&samr_handle);
(void) samr_close_handle(&samr_handle);
return (status);
}
DWORD
netr_set_user_control(
mlsvc_handle_t *user_handle,
DWORD UserAccountControl)
{
struct samr_SetUserInfo16 info;
info.UserAccountControl = UserAccountControl;
return (samr_set_user_info(user_handle, 16, &info));
}
DWORD
netr_set_user_password(
mlsvc_handle_t *user_handle,
char *new_pw_clear)
{
unsigned char ssn_key[SMBAUTH_HASH_SZ];
struct samr_SetUserInfo24 info;
if (ndr_rpc_get_ssnkey(user_handle, ssn_key, SMBAUTH_HASH_SZ))
return (NT_STATUS_INTERNAL_ERROR);
(void) memset(&info, 0, sizeof (info));
samr_make_encrypted_password(&info.encr_pw, new_pw_clear, ssn_key);
(void) memset(ssn_key, 0, sizeof (ssn_key));
return (samr_set_user_info(user_handle, 24, &info));
}
DWORD
netr_change_password(
char *server,
char *account,
char *old_pw_clear,
char *new_pw_clear)
{
struct samr_encr_passwd epw;
struct samr_encr_hash old_hash;
uint8_t old_nt_hash[SAMR_PWHASH_LEN];
uint8_t new_nt_hash[SAMR_PWHASH_LEN];
mlsvc_handle_t handle;
DWORD status;
status = ndr_rpc_bind(&handle, server, "", "", "SAMR");
if (status != NT_STATUS_SUCCESS)
return (status);
(void) smb_auth_ntlm_hash(old_pw_clear, old_nt_hash);
(void) smb_auth_ntlm_hash(new_pw_clear, new_nt_hash);
samr_make_encrypted_password(&epw, new_pw_clear, old_nt_hash);
(void) smb_auth_DES(old_hash.data, SAMR_PWHASH_LEN,
new_nt_hash, 14,
old_nt_hash, SAMR_PWHASH_LEN);
status = samr_change_password(
&handle, server, account,
&epw, &old_hash);
(void) memset(old_nt_hash, 0, sizeof (old_nt_hash));
(void) memset(new_nt_hash, 0, sizeof (new_nt_hash));
ndr_rpc_unbind(&handle);
return (status);
}
void
samr_make_encrypted_password(
struct samr_encr_passwd *epw,
char *new_pw_clear,
uint8_t *crypt_key)
{
union {
struct samr_user_password u;
struct samr_encr_passwd e;
} pwu;
samr_fill_userpw(&pwu.u, new_pw_clear);
(void) smb_auth_RC4(pwu.e.data, sizeof (pwu.e.data),
crypt_key, SAMR_PWHASH_LEN,
pwu.e.data, sizeof (pwu.e.data));
(void) memcpy(epw->data, pwu.e.data, sizeof (pwu.e.data));
(void) memset(pwu.e.data, 0, sizeof (pwu.e.data));
}
static void
samr_fill_userpw(struct samr_user_password *upw, const char *new_pw)
{
smb_wchar_t *pbuf;
uint32_t pwlen_bytes;
size_t pwlen_wchars;
#ifdef DEBUG
(void) memset(upw->Buffer, '*', sizeof (upw->Buffer));
#else
randomize((char *)upw->Buffer, sizeof (upw->Buffer));
#endif
pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2;
if (pwlen_wchars > SAMR_USER_PWLEN)
pwlen_wchars = SAMR_USER_PWLEN;
pwlen_bytes = pwlen_wchars * 2;
pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars];
(void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars);
upw->Length = htolel(pwlen_bytes);
}