📄 passdb.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 Copyright (C) Simo Sorce 2003 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_PASSDB/****************************************************************** get the default domain/netbios name to be used when testing authentication. For example, if you connect to a Windows member server using a bogus domain name, the Windows box will map the BOGUS\user to DOMAIN\user. A standalone box will map to WKS\user.******************************************************************/const char *get_default_sam_name(void){ /* standalone servers can only use the local netbios name */ if ( lp_server_role() == ROLE_STANDALONE ) return global_myname(); /* Windows domain members default to the DOMAIN name when not specified */ return lp_workgroup();}/************************************************************ Fill the SAM_ACCOUNT with default values. ***********************************************************/void pdb_fill_default_sam(SAM_ACCOUNT *user){ ZERO_STRUCT(user->private_u); /* Don't touch the talloc context */ /* no initial methods */ user->methods = NULL; /* Don't change these timestamp settings without a good reason. They are important for NT member server compatibility. */ user->private_u.logon_time = (time_t)0; user->private_u.pass_last_set_time = (time_t)0; user->private_u.pass_can_change_time = (time_t)0; user->private_u.logoff_time = user->private_u.kickoff_time = user->private_u.pass_must_change_time = get_time_t_max(); user->private_u.fields_present = 0x00ffffff; user->private_u.logon_divs = 168; /* hours per week */ user->private_u.hours_len = 21; /* 21 times 8 bits = 168 */ memset(user->private_u.hours, 0xff, user->private_u.hours_len); /* available at all hours */ user->private_u.bad_password_count = 0; user->private_u.logon_count = 0; user->private_u.unknown_6 = 0x000004ec; /* don't know */ /* Some parts of samba strlen their pdb_get...() returns, so this keeps the interface unchanged for now. */ user->private_u.username = ""; user->private_u.domain = ""; user->private_u.nt_username = ""; user->private_u.full_name = ""; user->private_u.home_dir = ""; user->private_u.logon_script = ""; user->private_u.profile_path = ""; user->private_u.acct_desc = ""; user->private_u.workstations = ""; user->private_u.unknown_str = ""; user->private_u.munged_dial = ""; user->private_u.plaintext_pw = NULL; /* Unless we know otherwise have a Account Control Bit value of 'normal user'. This helps User Manager, which asks for a filtered list of users. */ user->private_u.acct_ctrl = ACB_NORMAL;} static void destroy_pdb_talloc(SAM_ACCOUNT **user) { if (*user) { data_blob_clear_free(&((*user)->private_u.lm_pw)); data_blob_clear_free(&((*user)->private_u.nt_pw)); if((*user)->private_u.plaintext_pw!=NULL) memset((*user)->private_u.plaintext_pw,'\0',strlen((*user)->private_u.plaintext_pw)); talloc_destroy((*user)->mem_ctx); *user = NULL; }}/********************************************************************** Allocates memory and initialises a struct sam_passwd on supplied mem_ctx.***********************************************************************/NTSTATUS pdb_init_sam_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT **user){ if (*user != NULL) { DEBUG(0,("pdb_init_sam_talloc: SAM_ACCOUNT was non NULL\n"));#if 0 smb_panic("non-NULL pointer passed to pdb_init_sam\n");#endif return NT_STATUS_UNSUCCESSFUL; } if (!mem_ctx) { DEBUG(0,("pdb_init_sam_talloc: mem_ctx was NULL!\n")); return NT_STATUS_UNSUCCESSFUL; } *user=TALLOC_P(mem_ctx, SAM_ACCOUNT); if (*user==NULL) { DEBUG(0,("pdb_init_sam_talloc: error while allocating memory\n")); return NT_STATUS_NO_MEMORY; } (*user)->mem_ctx = mem_ctx; (*user)->free_fn = NULL; pdb_fill_default_sam(*user); return NT_STATUS_OK;}/************************************************************* Allocates memory and initialises a struct sam_passwd. ************************************************************/NTSTATUS pdb_init_sam(SAM_ACCOUNT **user){ TALLOC_CTX *mem_ctx; NTSTATUS nt_status; mem_ctx = talloc_init("passdb internal SAM_ACCOUNT allocation"); if (!mem_ctx) { DEBUG(0,("pdb_init_sam: error while doing talloc_init()\n")); return NT_STATUS_NO_MEMORY; } if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(mem_ctx, user))) { talloc_destroy(mem_ctx); return nt_status; } (*user)->free_fn = destroy_pdb_talloc; return NT_STATUS_OK;}/************************************************************************** * This function will take care of all the steps needed to correctly * allocate and set the user SID, please do use this function to create new * users, messing with SIDs is not good. * * account_data must be provided initialized, pwd may be null. * SSS ***************************************************************************/static NTSTATUS pdb_set_sam_sids(SAM_ACCOUNT *account_data, const struct passwd *pwd){ const char *guest_account = lp_guestaccount(); GROUP_MAP map; BOOL ret; if (!account_data || !pwd) { return NT_STATUS_INVALID_PARAMETER; } /* this is a hack this thing should not be set this way --SSS */ if (!(guest_account && *guest_account)) { DEBUG(1, ("NULL guest account!?!?\n")); return NT_STATUS_UNSUCCESSFUL; } else { /* Ensure this *must* be set right */ if (strcmp(pwd->pw_name, guest_account) == 0) { if (!pdb_set_user_sid_from_rid(account_data, DOMAIN_USER_RID_GUEST, PDB_DEFAULT)) { return NT_STATUS_UNSUCCESSFUL; } if (!pdb_set_group_sid_from_rid(account_data, DOMAIN_GROUP_RID_GUESTS, PDB_DEFAULT)) { return NT_STATUS_UNSUCCESSFUL; } return NT_STATUS_OK; } } if (!pdb_set_user_sid_from_rid(account_data, algorithmic_pdb_uid_to_user_rid(pwd->pw_uid), PDB_SET)) { DEBUG(0,("Can't set User SID from RID!\n")); return NT_STATUS_INVALID_PARAMETER; } /* call the mapping code here */ become_root(); ret = pdb_getgrgid(&map, pwd->pw_gid); unbecome_root(); if( ret ) { if (!pdb_set_group_sid(account_data, &map.sid, PDB_SET)){ DEBUG(0,("Can't set Group SID!\n")); return NT_STATUS_INVALID_PARAMETER; } } else { if (!pdb_set_group_sid_from_rid(account_data, pdb_gid_to_group_rid(pwd->pw_gid), PDB_SET)) { DEBUG(0,("Can't set Group SID\n")); return NT_STATUS_INVALID_PARAMETER; } } return NT_STATUS_OK;}/************************************************************* Initialises a struct sam_passwd with sane values. ************************************************************/NTSTATUS pdb_fill_sam_pw(SAM_ACCOUNT *sam_account, const struct passwd *pwd){ NTSTATUS ret; if (!pwd) { return NT_STATUS_UNSUCCESSFUL; } pdb_fill_default_sam(sam_account); pdb_set_username(sam_account, pwd->pw_name, PDB_SET); pdb_set_fullname(sam_account, pwd->pw_gecos, PDB_SET); pdb_set_unix_homedir(sam_account, pwd->pw_dir, PDB_SET); pdb_set_domain (sam_account, get_global_sam_name(), PDB_DEFAULT); /* When we get a proper uid -> SID and SID -> uid allocation mechinism, we should call it here. We can't just set this to 0 or allow it only to be filled in when added to the backend, because the user's SID may already be in security descriptors etc. -- abartlet 11-May-02 */ ret = pdb_set_sam_sids(sam_account, pwd); if (!NT_STATUS_IS_OK(ret)) return ret; /* check if this is a user account or a machine account */ if (pwd->pw_name[strlen(pwd->pw_name)-1] != '$') { pdb_set_profile_path(sam_account, talloc_sub_specified((sam_account)->mem_ctx, lp_logon_path(), pwd->pw_name, global_myname(), pwd->pw_uid, pwd->pw_gid), PDB_DEFAULT); pdb_set_homedir(sam_account, talloc_sub_specified((sam_account)->mem_ctx, lp_logon_home(), pwd->pw_name, global_myname(), pwd->pw_uid, pwd->pw_gid), PDB_DEFAULT); pdb_set_dir_drive(sam_account, talloc_sub_specified((sam_account)->mem_ctx, lp_logon_drive(), pwd->pw_name, global_myname(), pwd->pw_uid, pwd->pw_gid), PDB_DEFAULT); pdb_set_logon_script(sam_account, talloc_sub_specified((sam_account)->mem_ctx, lp_logon_script(), pwd->pw_name, global_myname(), pwd->pw_uid, pwd->pw_gid), PDB_DEFAULT); if (!pdb_set_acct_ctrl(sam_account, ACB_NORMAL, PDB_DEFAULT)) { DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n", pwd->pw_name)); return NT_STATUS_UNSUCCESSFUL; } } else { if (!pdb_set_acct_ctrl(sam_account, ACB_WSTRUST, PDB_DEFAULT)) { DEBUG(1, ("Failed to set 'trusted workstation account' flags for user %s.\n", pwd->pw_name)); return NT_STATUS_UNSUCCESSFUL; } } return NT_STATUS_OK;}/************************************************************* Initialises a struct sam_passwd with sane values. ************************************************************/NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd){ NTSTATUS nt_status; if (!pwd) { new_sam_acct = NULL; return NT_STATUS_INVALID_PARAMETER; } if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(new_sam_acct))) { new_sam_acct = NULL; return nt_status; } if (!NT_STATUS_IS_OK(nt_status = pdb_fill_sam_pw(*new_sam_acct, pwd))) { pdb_free_sam(new_sam_acct); new_sam_acct = NULL; return nt_status; } return NT_STATUS_OK;}/************************************************************* Initialises a SAM_ACCOUNT ready to add a new account, based on the UNIX user. Pass in a RID if you have one ************************************************************/NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username, uint32 rid){ NTSTATUS nt_status = NT_STATUS_NO_MEMORY; struct passwd *pwd; BOOL ret; pwd = Get_Pwnam(username); if (!pwd) return NT_STATUS_NO_SUCH_USER; if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { *new_sam_acct = NULL; return nt_status; } /* see if we need to generate a new rid using the 2.2 algorithm */ if ( rid == 0 && lp_enable_rid_algorithm() ) { DEBUG(10,("pdb_init_sam_new: no RID specified. Generating one via old algorithm\n")); rid = algorithmic_pdb_uid_to_user_rid(pwd->pw_uid); } /* set the new SID */ ret = pdb_set_user_sid_from_rid( *new_sam_acct, rid, PDB_SET ); return (ret ? NT_STATUS_OK : NT_STATUS_NO_SUCH_USER);}/** * Free the contets of the SAM_ACCOUNT, but not the structure. * * Also wipes the LM and NT hashes and plaintext password from * memory. * * @param user SAM_ACCOUNT to free members of. **/static void pdb_free_sam_contents(SAM_ACCOUNT *user){ /* Kill off sensitive data. Free()ed by the talloc mechinism */ data_blob_clear_free(&(user->private_u.lm_pw)); data_blob_clear_free(&(user->private_u.nt_pw)); if (user->private_u.plaintext_pw!=NULL) memset(user->private_u.plaintext_pw,'\0',strlen(user->private_u.plaintext_pw)); if (user->private_u.backend_private_data && user->private_u.backend_private_data_free_fn) { user->private_u.backend_private_data_free_fn(&user->private_u.backend_private_data); }}/************************************************************ Reset the SAM_ACCOUNT and free the NT/LM hashes. ***********************************************************/NTSTATUS pdb_reset_sam(SAM_ACCOUNT *user){ if (user == NULL) { DEBUG(0,("pdb_reset_sam: SAM_ACCOUNT was NULL\n"));#if 0 smb_panic("NULL pointer passed to pdb_free_sam\n");#endif return NT_STATUS_UNSUCCESSFUL; } pdb_free_sam_contents(user); pdb_fill_default_sam(user); return NT_STATUS_OK;}/************************************************************ Free the SAM_ACCOUNT and the member pointers. ***********************************************************/NTSTATUS pdb_free_sam(SAM_ACCOUNT **user){ if (*user == NULL) { DEBUG(0,("pdb_free_sam: SAM_ACCOUNT was NULL\n"));#if 0 smb_panic("NULL pointer passed to pdb_free_sam\n");#endif return NT_STATUS_UNSUCCESSFUL; } pdb_free_sam_contents(*user); if ((*user)->free_fn) { (*user)->free_fn(user); } return NT_STATUS_OK; }/********************************************************** Encode the account control bits into a string.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -