summaryrefslogtreecommitdiff
path: root/source3/passdb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/passdb')
-rw-r--r--source3/passdb/.cvsignore2
-rw-r--r--source3/passdb/machine_sid.c167
-rw-r--r--source3/passdb/passdb.c1223
-rw-r--r--source3/passdb/passgrp.c216
-rw-r--r--source3/passdb/pdb_get_set.c956
-rw-r--r--source3/passdb/pdb_interface.c391
-rw-r--r--source3/passdb/pdb_ldap.c1537
-rw-r--r--source3/passdb/pdb_nisplus.c1428
-rw-r--r--source3/passdb/pdb_plugin.c59
-rw-r--r--source3/passdb/pdb_smbpasswd.c1660
-rw-r--r--source3/passdb/pdb_tdb.c938
-rw-r--r--source3/passdb/secrets.c359
-rw-r--r--source3/passdb/smbpass.c304
13 files changed, 8936 insertions, 304 deletions
diff --git a/source3/passdb/.cvsignore b/source3/passdb/.cvsignore
new file mode 100644
index 0000000000..5f2a5c4cf7
--- /dev/null
+++ b/source3/passdb/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source3/passdb/machine_sid.c b/source3/passdb/machine_sid.c
new file mode 100644
index 0000000000..6436a2cd05
--- /dev/null
+++ b/source3/passdb/machine_sid.c
@@ -0,0 +1,167 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2002
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Gerald (Jerry) Carter 2000
+
+ 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"
+
+
+/****************************************************************************
+ Read a SID from a file. This is for compatibility with the old MACHINE.SID
+ style of SID storage
+****************************************************************************/
+static BOOL read_sid_from_file(const char *fname, DOM_SID *sid)
+{
+ char **lines;
+ int numlines;
+ BOOL ret;
+
+ lines = file_lines_load(fname, &numlines);
+
+ if (!lines || numlines < 1) {
+ if (lines) file_lines_free(lines);
+ return False;
+ }
+
+ ret = string_to_sid(sid, lines[0]);
+ file_lines_free(lines);
+ return ret;
+}
+
+/*
+ generate a random sid - used to build our own sid if we don't have one
+*/
+static void generate_random_sid(DOM_SID *sid)
+{
+ int i;
+ uchar raw_sid_data[12];
+
+ memset((char *)sid, '\0', sizeof(*sid));
+ sid->sid_rev_num = 1;
+ sid->id_auth[5] = 5;
+ sid->num_auths = 0;
+ sid->sub_auths[sid->num_auths++] = 21;
+
+ generate_random_buffer(raw_sid_data, 12, True);
+ for (i = 0; i < 3; i++)
+ sid->sub_auths[sid->num_auths++] = IVAL(raw_sid_data, i*4);
+}
+
+/****************************************************************************
+ Generate the global machine sid.
+****************************************************************************/
+
+BOOL pdb_generate_sam_sid(void)
+{
+ char *fname = NULL;
+ extern pstring global_myname;
+ extern fstring global_myworkgroup;
+ BOOL is_dc = False;
+
+ generate_wellknown_sids();
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ is_dc = True;
+ break;
+ default:
+ is_dc = False;
+ break;
+ }
+
+ if (secrets_fetch_domain_sid(global_myname, &global_sam_sid)) {
+ DOM_SID domain_sid;
+
+ /* We got our sid. If not a pdc/bdc, we're done. */
+ if (!is_dc)
+ return True;
+
+ if (!secrets_fetch_domain_sid(global_myworkgroup, &domain_sid)) {
+
+ /* No domain sid and we're a pdc/bdc. Store it */
+
+ if (!secrets_store_domain_sid(global_myworkgroup, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n"));
+ return False;
+ }
+ return True;
+ }
+
+ if (!sid_equal(&domain_sid, &global_sam_sid)) {
+
+ /* Domain name sid doesn't match global sam sid. Re-store global sam sid as domain sid. */
+
+ DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n"));
+ if (!secrets_store_domain_sid(global_myworkgroup, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID as a pdc/bdc.\n"));
+ return False;
+ }
+ return True;
+ }
+
+ return True;
+
+ }
+
+ /* check for an old MACHINE.SID file for backwards compatibility */
+ asprintf(&fname, "%s/MACHINE.SID", lp_private_dir());
+
+ if (read_sid_from_file(fname, &global_sam_sid)) {
+ /* remember it for future reference and unlink the old MACHINE.SID */
+ if (!secrets_store_domain_sid(global_myname, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n"));
+ SAFE_FREE(fname);
+ return False;
+ }
+ unlink(fname);
+ if (is_dc) {
+ if (!secrets_store_domain_sid(global_myworkgroup, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n"));
+ SAFE_FREE(fname);
+ return False;
+ }
+ }
+
+ /* Stored the old sid from MACHINE.SID successfully.
+ Patch from Stefan "metze" Metzmacher <metze@metzemix.de>*/
+ SAFE_FREE(fname);
+ return True;
+ }
+
+ SAFE_FREE(fname);
+
+ /* we don't have the SID in secrets.tdb, we will need to
+ generate one and save it */
+ generate_random_sid(&global_sam_sid);
+
+ if (!secrets_store_domain_sid(global_myname, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n"));
+ return False;
+ }
+ if (is_dc) {
+ if (!secrets_store_domain_sid(global_myworkgroup, &global_sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c
new file mode 100644
index 0000000000..7eecbfd2cd
--- /dev/null
+++ b/source3/passdb/passdb.c
@@ -0,0 +1,1223 @@
+/*
+ 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"
+
+/*
+ * This is set on startup - it defines the SID for this
+ * machine, and therefore the SAM database for which it is
+ * responsible.
+ */
+
+extern DOM_SID global_sam_sid;
+
+/************************************************************
+ Fill the SAM_ACCOUNT with default values.
+ ***********************************************************/
+
+static void pdb_fill_default_sam(SAM_ACCOUNT *user)
+{
+ ZERO_STRUCT(user->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. */
+
+ user->private.init_flag = FLAG_SAM_UNINIT;
+ user->private.uid = user->private.gid = -1;
+
+ user->private.logon_time = (time_t)0;
+ user->private.pass_last_set_time = (time_t)0;
+ user->private.pass_can_change_time = (time_t)0;
+ user->private.logoff_time =
+ user->private.kickoff_time =
+ user->private.pass_must_change_time = get_time_t_max();
+ user->private.unknown_3 = 0x00ffffff; /* don't know */
+ user->private.logon_divs = 168; /* hours per week */
+ user->private.hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->private.hours, 0xff, user->private.hours_len); /* available at all hours */
+ user->private.unknown_5 = 0x00000000; /* don't know */
+ user->private.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.username = "";
+ user->private.domain = "";
+ user->private.nt_username = "";
+ user->private.full_name = "";
+ user->private.home_dir = "";
+ user->private.logon_script = "";
+ user->private.profile_path = "";
+ user->private.acct_desc = "";
+ user->private.workstations = "";
+ user->private.unknown_str = "";
+ user->private.munged_dial = "";
+}
+
+static void destroy_pdb_talloc(SAM_ACCOUNT **user)
+{
+ if (*user) {
+ talloc_destroy((*user)->mem_ctx);
+ *user = NULL;
+ }
+}
+
+
+/**********************************************************************
+ Alloc 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: 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=(SAM_ACCOUNT *)talloc(mem_ctx, sizeof(SAM_ACCOUNT));
+
+ if (*user==NULL) {
+ DEBUG(0,("pdb_init_sam: 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;
+}
+
+
+/*************************************************************
+ Alloc 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_named("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;
+}
+
+
+/*************************************************************
+ Initialises a struct sam_passwd with sane values.
+ ************************************************************/
+
+NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd)
+{
+ pstring str;
+ GROUP_MAP map;
+ uint32 rid;
+ NTSTATUS nt_status;
+
+ if (!pwd) {
+ new_sam_acct = NULL;
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(new_sam_acct))) {
+ new_sam_acct = NULL;
+ return nt_status;
+ }
+
+ pdb_set_username(*new_sam_acct, pwd->pw_name);
+ pdb_set_fullname(*new_sam_acct, pwd->pw_gecos);
+
+ pdb_set_uid(*new_sam_acct, pwd->pw_uid);
+ pdb_set_gid(*new_sam_acct, pwd->pw_gid);
+
+ /* let the backends set the rid!!
+ pdb_set_user_rid(*new_sam_acct, pdb_uid_to_user_rid(pwd->pw_uid));
+ -- simo */
+
+ /* call the mapping code here */
+ if(get_group_map_from_gid(pwd->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ }
+ else {
+ rid=pdb_gid_to_group_rid(pwd->pw_gid);
+ }
+
+ pdb_set_group_rid(*new_sam_acct, rid);
+
+ pstrcpy(str, lp_logon_path());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_profile_path(*new_sam_acct, str, False);
+
+ pstrcpy(str, lp_logon_home());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_homedir(*new_sam_acct, str, False);
+
+ pstrcpy(str, lp_logon_drive());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_dir_drive(*new_sam_acct, str, False);
+
+ pstrcpy(str, lp_logon_script());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_logon_script(*new_sam_acct, str, False);
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Free the contets of the SAM_ACCOUNT, but not the structure.
+ *
+ * Also wipes the LM and NT hashes from memory.
+ *
+ * @param user SAM_ACCOUNT to free members of.
+ **/
+
+static void pdb_free_sam_contents(SAM_ACCOUNT *user)
+{
+ /* As we start mallocing more strings this is where
+ we should free them. */
+
+ data_blob_clear_free(&(user->private.lm_pw));
+ data_blob_clear_free(&(user->private.nt_pw));
+}
+
+
+/************************************************************
+ 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.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *pdb_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 pdb_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 pdb_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 pdb_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);
+}
+
+#if 0 /* seem it is not used by anyone */
+/*******************************************************************
+ Group and User RID username mapping function
+ ********************************************************************/
+
+BOOL pdb_name_to_rid(const char *user_name, uint32 *u_rid, uint32 *g_rid)
+{
+ GROUP_MAP map;
+ struct passwd *pw = Get_Pwnam(user_name);
+
+ if (u_rid == NULL || g_rid == NULL || user_name == NULL)
+ return False;
+
+ if (!pw) {
+ DEBUG(1,("Username %s is invalid on this system\n", user_name));
+ return False;
+ }
+
+ /* turn the unix UID into a Domain RID. this is what the posix
+ sub-system does (adds 1000 to the uid) */
+ *u_rid = fallback_pdb_uid_to_user_rid(pw->pw_uid);
+
+ /* absolutely no idea what to do about the unix GID to Domain RID mapping */
+ /* map it ! */
+ if (get_group_map_from_gid(pw->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, g_rid);
+ } else
+ *g_rid = pdb_gid_to_group_rid(pw->pw_gid);
+
+ return True;
+}
+#endif /* seem it is not used by anyone */
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+static uid_t fallback_pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+static uint32 fallback_pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ Converts NT group RID to a UNIX gid.
+ ********************************************************************/
+
+gid_t pdb_group_rid_to_gid(uint32 group_rid)
+{
+ return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ converts NT Group RID to a UNIX uid.
+
+ warning: you must not call that function only
+ you must do a call to the group mapping first.
+ there is not anymore a direct link between the gid and the rid.
+ ********************************************************************/
+
+uint32 pdb_gid_to_group_rid(gid_t gid)
+{
+ return (((((uint32)gid)*RID_MULTIPLIER) + 1000) | GROUP_RID_TYPE);
+}
+
+/*******************************************************************
+ Decides if a RID is a well known RID.
+ ********************************************************************/
+
+static BOOL pdb_rid_is_well_known(uint32 rid)
+{
+ return (rid < 1000);
+}
+
+/*******************************************************************
+ Decides if a RID is a user or group RID.
+ ********************************************************************/
+
+BOOL pdb_rid_is_user(uint32 rid)
+{
+ /* lkcl i understand that NT attaches an enumeration to a RID
+ * such that it can be identified as either a user, group etc
+ * type. there are 5 such categories, and they are documented.
+ */
+ if(pdb_rid_is_well_known(rid)) {
+ /*
+ * The only well known user RIDs are DOMAIN_USER_RID_ADMIN
+ * and DOMAIN_USER_RID_GUEST.
+ */
+ if(rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST)
+ return True;
+ } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ Convert a rid into a name. Used in the lookup SID rpc.
+ ********************************************************************/
+
+BOOL local_lookup_sid(DOM_SID *sid, char *name, enum SID_NAME_USE *psid_name_use)
+{
+ uint32 rid;
+ BOOL is_user;
+ SAM_ACCOUNT *sam_account = NULL;
+ BOOL found = False;
+
+ sid_peek_rid(sid, &rid);
+ is_user = pdb_rid_is_user(rid);
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ DEBUG(5,("local_lookup_sid: looking up %s RID %u.\n", is_user ? "user" :
+ "group", (unsigned int)rid));
+
+ if(is_user) {
+ if(rid == DOMAIN_USER_RID_ADMIN) {
+ char **admin_list = lp_admin_users(-1);
+ *psid_name_use = SID_NAME_USER;
+ if (admin_list) {
+ char *p = *admin_list;
+ if(!next_token(&p, name, NULL, sizeof(fstring)))
+ fstrcpy(name, "Administrator");
+ } else {
+ fstrcpy(name, "Administrator");
+ }
+ } else if (rid == DOMAIN_USER_RID_GUEST) {
+ char *p = lp_guestaccount();
+ *psid_name_use = SID_NAME_USER;
+ if(!next_token(&p, name, NULL, sizeof(fstring)))
+ fstrcpy(name, "Guest");
+ } else {
+ uid_t uid;
+ struct passwd *pass;
+
+ /*
+ * Don't try to convert the rid to a name if
+ * running in appliance mode
+ */
+ if (lp_hide_local_users())
+ return False;
+
+ if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) {
+ return False;
+ }
+
+ if (pdb_getsampwrid(sam_account, rid)) {
+ fstrcpy(name, pdb_get_username(sam_account));
+ *psid_name_use = SID_NAME_USER;
+ found = True;
+ }
+
+ pdb_free_sam(&sam_account);
+
+ if (found) {
+ return True;
+ }
+
+ uid = fallback_pdb_user_rid_to_uid(rid);
+ pass = getpwuid_alloc(uid);
+
+ *psid_name_use = SID_NAME_USER;
+
+ DEBUG(5,("local_lookup_sid: looking up uid %u %s\n", (unsigned int)uid,
+ pass ? "succeeded" : "failed" ));
+
+ if(!pass) {
+ slprintf(name, sizeof(fstring)-1, "unix_user.%u", (unsigned int)uid);
+ return True;
+ }
+
+ fstrcpy(name, pass->pw_name);
+
+ DEBUG(5,("local_lookup_sid: found user %s for rid %u\n", name,
+ (unsigned int)rid ));
+
+ passwd_free(&pass);
+ }
+
+ } else {
+ gid_t gid;
+ struct group *gr;
+ GROUP_MAP map;
+
+ /*
+ * Don't try to convert the rid to a name if running
+ * in appliance mode
+ */
+
+ if (lp_hide_local_users())
+ return False;
+
+ /* check if it's a mapped group */
+ if (get_group_map_from_sid(*sid, &map, MAPPING_WITHOUT_PRIV)) {
+ if (map.gid!=-1) {
+ DEBUG(5,("local_lookup_sid: mapped group %s to gid %u\n", map.nt_name, (unsigned int)map.gid));
+ fstrcpy(name, map.nt_name);
+ *psid_name_use = map.sid_name_use;
+ return True;
+ }
+ }
+
+ gid = pdb_group_rid_to_gid(rid);
+ gr = getgrgid(gid);
+
+ *psid_name_use = SID_NAME_ALIAS;
+
+ DEBUG(5,("local_lookup_sid: looking up gid %u %s\n", (unsigned int)gid,
+ gr ? "succeeded" : "failed" ));
+
+ if(!gr) {
+ slprintf(name, sizeof(fstring)-1, "unix_group.%u", (unsigned int)gid);
+ return False;
+ }
+
+ fstrcpy( name, gr->gr_name);
+
+ DEBUG(5,("local_lookup_sid: found group %s for rid %u\n", name,
+ (unsigned int)rid ));
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Convert a name into a SID. Used in the lookup name rpc.
+ ********************************************************************/
+
+BOOL local_lookup_name(const char *c_user, DOM_SID *psid, enum SID_NAME_USE *psid_name_use)
+{
+ extern DOM_SID global_sid_World_Domain;
+ struct passwd *pass = NULL;
+ DOM_SID local_sid;
+ fstring user;
+ SAM_ACCOUNT *sam_account = NULL;
+ BOOL found = False;
+
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ /*
+ * user may be quoted a const string, and map_username and
+ * friends can modify it. Make a modifiable copy. JRA.
+ */
+
+ fstrcpy(user, c_user);
+
+ sid_copy(&local_sid, &global_sam_sid);
+
+ /*
+ * Special case for MACHINE\Everyone. Map to the world_sid.
+ */
+
+ if(strequal(user, "Everyone")) {
+ sid_copy( psid, &global_sid_World_Domain);
+ sid_append_rid(psid, 0);
+ *psid_name_use = SID_NAME_ALIAS;
+ return True;
+ }
+
+ /*
+ * Don't lookup local unix users if running in appliance mode
+ */
+ if (lp_hide_local_users())
+ return False;
+
+ (void)map_username(user);
+
+ if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) {
+ return False;
+ }
+
+ if (pdb_getsampwnam(sam_account, user)) {
+ sid_append_rid( &local_sid, pdb_get_user_rid(sam_account));
+ *psid_name_use = SID_NAME_USER;
+
+ sid_copy( psid, &local_sid);
+ found = True;
+ }
+
+ pdb_free_sam(&sam_account);
+
+ if (!found && (pass = Get_Pwnam(user))) {
+ sid_append_rid( &local_sid, fallback_pdb_uid_to_user_rid(pass->pw_uid));
+ *psid_name_use = SID_NAME_USER;
+ pdb_free_sam(&sam_account);
+
+ } else if (!found) {
+ /*
+ * Maybe it was a group ?
+ */
+ struct group *grp;
+ GROUP_MAP map;
+
+ pdb_free_sam(&sam_account);
+
+ /* check if it's a mapped group */
+ if (get_group_map_from_ntname(user, &map, MAPPING_WITHOUT_PRIV)) {
+ if (map.gid!=-1) {
+ /* yes it's a mapped group to a valid unix group */
+ sid_copy(&local_sid, &map.sid);
+ *psid_name_use = map.sid_name_use;
+ }
+ else
+ /* it's a correct name but not mapped so it points to nothing*/
+ return False;
+ } else {
+ /* it's not a mapped group */
+ grp = getgrnam(user);
+ if(!grp)
+ return False;
+
+ /*
+ *check if it's mapped, if it is reply it doesn't exist
+ *
+ * that's to prevent this case:
+ *
+ * unix group ug is mapped to nt group ng
+ * someone does a lookup on ug
+ * we must not reply as it doesn't "exist" anymore
+ * for NT. For NT only ng exists.
+ * JFM, 30/11/2001
+ */
+
+ if(get_group_map_from_gid(grp->gr_gid, &map, MAPPING_WITHOUT_PRIV)){
+ return False;
+ }
+
+ sid_append_rid( &local_sid, pdb_gid_to_group_rid(grp->gr_gid));
+ *psid_name_use = SID_NAME_ALIAS;
+ }
+ }
+
+ sid_copy( psid, &local_sid);
+
+ return True;
+}
+
+/****************************************************************************
+ Convert a uid to SID - locally.
+****************************************************************************/
+
+DOM_SID *local_uid_to_sid(DOM_SID *psid, uid_t uid)
+{
+ extern DOM_SID global_sam_sid;
+ struct passwd *pass;
+ SAM_ACCOUNT *sam_user = NULL;
+
+ sid_copy(psid, &global_sam_sid);
+
+ if(!(pass = getpwuid_alloc(uid)))
+ return NULL;
+
+ if (NT_STATUS_IS_ERR(pdb_init_sam(&sam_user))) {
+ passwd_free(&pass);
+ return NULL;
+ }
+
+ if (!pdb_getsampwnam(sam_user, pass->pw_name)) {
+ pdb_free_sam(&sam_user);
+ return NULL;
+ }
+
+ passwd_free(&pass);
+
+ sid_append_rid(psid, pdb_get_user_rid(sam_user));
+
+ pdb_free_sam(&sam_user);
+
+ return psid;
+}
+
+/****************************************************************************
+ Convert a SID to uid - locally.
+****************************************************************************/
+
+BOOL local_sid_to_uid(uid_t *puid, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern DOM_SID global_sam_sid;
+
+ DOM_SID dom_sid;
+ uint32 rid;
+ fstring str;
+ struct passwd *pass;
+ SAM_ACCOUNT *sam_user = NULL;
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ sid_copy(&dom_sid, psid);
+ sid_split_rid(&dom_sid, &rid);
+
+ if (!pdb_rid_is_user(rid))
+ return False;
+
+ /*
+ * We can only convert to a uid if this is our local
+ * Domain SID (ie. we are the controling authority).
+ */
+ if (!sid_equal(&global_sam_sid, &dom_sid))
+ return False;
+
+ if (NT_STATUS_IS_ERR(pdb_init_sam(&sam_user)))
+ return False;
+
+ if (!pdb_getsampwrid(sam_user, rid)) {
+ pdb_free_sam(&sam_user);
+ return False;
+ }
+
+ *puid = pdb_get_uid(sam_user);
+ if (*puid == -1)
+ return False;
+
+ pdb_free_sam(&sam_user);
+
+ /*
+ * Ensure this uid really does exist.
+ */
+ if(!(pass = getpwuid_alloc(*puid)))
+ return False;
+
+ DEBUG(10,("local_sid_to_uid: SID %s -> uid (%u) (%s).\n", sid_to_string( str, psid),
+ (unsigned int)*puid, pass->pw_name ));
+
+ passwd_free(&pass);
+
+ *name_type = SID_NAME_USER;
+
+ return True;
+}
+
+/****************************************************************************
+ Convert a gid to SID - locally.
+****************************************************************************/
+
+DOM_SID *local_gid_to_sid(DOM_SID *psid, gid_t gid)
+{
+ extern DOM_SID global_sam_sid;
+ GROUP_MAP map;
+
+ sid_copy(psid, &global_sam_sid);
+
+ if (get_group_map_from_gid(gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_copy(psid, &map.sid);
+ }
+ else {
+ sid_append_rid(psid, pdb_gid_to_group_rid(gid));
+ }
+
+ return psid;
+}
+
+/****************************************************************************
+ Convert a SID to gid - locally.
+****************************************************************************/
+
+BOOL local_sid_to_gid(gid_t *pgid, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern DOM_SID global_sam_sid;
+ DOM_SID dom_sid;
+ uint32 rid;
+ fstring str;
+ struct group *grp;
+ GROUP_MAP map;
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ sid_copy(&dom_sid, psid);
+ sid_split_rid(&dom_sid, &rid);
+
+ /*
+ * We can only convert to a gid if this is our local
+ * Domain SID (ie. we are the controling authority).
+ *
+ * Or in the Builtin SID too. JFM, 11/30/2001
+ */
+
+ if (!sid_equal(&global_sam_sid, &dom_sid))
+ return False;
+
+ if (pdb_rid_is_user(rid))
+ return False;
+
+ if (get_group_map_from_sid(*psid, &map, MAPPING_WITHOUT_PRIV)) {
+
+ /* the SID is in the mapping table but not mapped */
+ if (map.gid==-1)
+ return False;
+
+ sid_peek_rid(&map.sid, &rid);
+ *pgid = rid;
+ *name_type = map.sid_name_use;
+ } else {
+ *pgid = pdb_group_rid_to_gid(rid);
+ *name_type = SID_NAME_ALIAS;
+ }
+
+ /*
+ * Ensure this gid really does exist.
+ */
+
+ if(!(grp = getgrgid(*pgid)))
+ return False;
+
+ DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u) (%s).\n", sid_to_string( str, psid),
+ (unsigned int)*pgid, grp->gr_name ));
+
+ return True;
+}
+
+/**
+ * Quick hack to do an easy ucs2 -> mulitbyte conversion
+ * @return static buffer containing the converted string
+ **/
+
+static char *pdb_convert(const UNISTR2 *from)
+{
+ static pstring convert_buffer;
+ *convert_buffer = 0;
+ if (!from) {
+ return convert_buffer;
+ }
+
+ unistr2_to_ascii(convert_buffer, from, sizeof(pstring));
+ return convert_buffer;
+}
+
+/*************************************************************
+ Copies a SAM_USER_INFO_23 to a SAM_ACCOUNT
+ **************************************************************/
+
+void copy_id23_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_23 *from)
+{
+
+ if (from == NULL || to == NULL)
+ return;
+
+ pdb_set_logon_time(to,nt_time_to_unix(&from->logon_time), True);
+ pdb_set_logoff_time(to,nt_time_to_unix(&from->logoff_time), True);
+ pdb_set_kickoff_time(to, nt_time_to_unix(&from->kickoff_time), True);
+ pdb_set_pass_can_change_time(to, nt_time_to_unix(&from->pass_can_change_time), True);
+ pdb_set_pass_must_change_time(to, nt_time_to_unix(&from->pass_must_change_time), True);
+
+ pdb_set_pass_last_set_time(to, nt_time_to_unix(&from->pass_last_set_time));
+
+ if (from->uni_user_name.buffer)
+ pdb_set_username(to , pdb_convert(&from->uni_user_name ));
+ if (from->uni_full_name.buffer)
+ pdb_set_fullname(to , pdb_convert(&from->uni_full_name ));
+ if (from->uni_home_dir.buffer)
+ pdb_set_homedir(to , pdb_convert(&from->uni_home_dir ), True);
+ if (from->uni_dir_drive.buffer)
+ pdb_set_dir_drive(to , pdb_convert(&from->uni_dir_drive ), True);
+ if (from->uni_logon_script.buffer)
+ pdb_set_logon_script(to , pdb_convert(&from->uni_logon_script), True);
+ if (from->uni_profile_path.buffer)
+ pdb_set_profile_path(to , pdb_convert(&from->uni_profile_path), True);
+ if (from->uni_acct_desc.buffer)
+ pdb_set_acct_desc(to , pdb_convert(&from->uni_acct_desc ));
+ if (from->uni_workstations.buffer)
+ pdb_set_workstations(to , pdb_convert(&from->uni_workstations));
+ if (from->uni_unknown_str.buffer)
+ pdb_set_unknown_str(to , pdb_convert(&from->uni_unknown_str ));
+ if (from->uni_munged_dial.buffer)
+ pdb_set_munged_dial(to , pdb_convert(&from->uni_munged_dial ));
+
+ if (from->user_rid)
+ pdb_set_user_rid(to, from->user_rid);
+ if (from->group_rid)
+ pdb_set_group_rid(to, from->group_rid);
+
+ pdb_set_acct_ctrl(to, from->acb_info);
+ pdb_set_unknown_3(to, from->unknown_3);
+
+ pdb_set_logon_divs(to, from->logon_divs);
+ pdb_set_hours_len(to, from->logon_hrs.len);
+ pdb_set_hours(to, from->logon_hrs.hours);
+
+ pdb_set_unknown_5(to, from->unknown_5);
+ pdb_set_unknown_6(to, from->unknown_6);
+}
+
+
+/*************************************************************
+ Copies a sam passwd.
+ **************************************************************/
+
+void copy_id21_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_21 *from)
+{
+ if (from == NULL || to == NULL)
+ return;
+
+ pdb_set_logon_time(to,nt_time_to_unix(&from->logon_time), True);
+ pdb_set_logoff_time(to,nt_time_to_unix(&from->logoff_time), True);
+ pdb_set_kickoff_time(to, nt_time_to_unix(&from->kickoff_time), True);
+ pdb_set_pass_can_change_time(to, nt_time_to_unix(&from->pass_can_change_time), True);
+ pdb_set_pass_must_change_time(to, nt_time_to_unix(&from->pass_must_change_time), True);
+
+ pdb_set_pass_last_set_time(to, nt_time_to_unix(&from->pass_last_set_time));
+
+ if (from->uni_user_name.buffer)
+ pdb_set_username(to , pdb_convert(&from->uni_user_name ));
+ if (from->uni_full_name.buffer)
+ pdb_set_fullname(to , pdb_convert(&from->uni_full_name ));
+ if (from->uni_home_dir.buffer)
+ pdb_set_homedir(to , pdb_convert(&from->uni_home_dir ), True);
+ if (from->uni_dir_drive.buffer)
+ pdb_set_dir_drive(to , pdb_convert(&from->uni_dir_drive ), True);
+ if (from->uni_logon_script.buffer)
+ pdb_set_logon_script(to , pdb_convert(&from->uni_logon_script), True);
+ if (from->uni_profile_path.buffer)
+ pdb_set_profile_path(to , pdb_convert(&from->uni_profile_path), True);
+ if (from->uni_acct_desc.buffer)
+ pdb_set_acct_desc(to , pdb_convert(&from->uni_acct_desc ));
+ if (from->uni_workstations.buffer)
+ pdb_set_workstations(to , pdb_convert(&from->uni_workstations));
+ if (from->uni_unknown_str.buffer)
+ pdb_set_unknown_str(to , pdb_convert(&from->uni_unknown_str ));
+ if (from->uni_munged_dial.buffer)
+ pdb_set_munged_dial(to , pdb_convert(&from->uni_munged_dial ));
+
+ if (from->user_rid)
+ pdb_set_user_rid(to, from->user_rid);
+ if (from->group_rid)
+ pdb_set_group_rid(to, from->group_rid);
+
+ /* FIXME!! Do we need to copy the passwords here as well?
+ I don't know. Need to figure this out --jerry */
+
+ /* Passwords dealt with in caller --abartlet */
+
+ pdb_set_acct_ctrl(to, from->acb_info);
+ pdb_set_unknown_3(to, from->unknown_3);
+
+ pdb_set_logon_divs(to, from->logon_divs);
+ pdb_set_hours_len(to, from->logon_hrs.len);
+ pdb_set_hours(to, from->logon_hrs.hours);
+
+ pdb_set_unknown_5(to, from->unknown_5);
+ pdb_set_unknown_6(to, from->unknown_6);
+}
+
+
+/*************************************************************
+ Change a password entry in the local smbpasswd file.
+
+ FIXME!! The function needs to be abstracted into the
+ passdb interface or something. It is currently being called
+ by _api_samr_create_user() in rpc_server/srv_samr.c,
+ in SWAT and by smbpasswd/pdbedit.
+
+ --jerry
+ *************************************************************/
+
+BOOL local_password_change(const char *user_name, int local_flags,
+ const char *new_passwd,
+ char *err_str, size_t err_str_len,
+ char *msg_str, size_t msg_str_len)
+{
+ struct passwd *pwd = NULL;
+ SAM_ACCOUNT *sam_pass=NULL;
+
+ *err_str = '\0';
+ *msg_str = '\0';
+
+ /* Get the smb passwd entry for this user */
+ pdb_init_sam(&sam_pass);
+ if(!pdb_getsampwnam(sam_pass, user_name)) {
+ pdb_free_sam(&sam_pass);
+
+ if (local_flags & LOCAL_ADD_USER) {
+ pwd = getpwnam_alloc(user_name);
+ } else if (local_flags & LOCAL_DELETE_USER) {
+ /* Might not exist in /etc/passwd */
+ } else {
+ slprintf(err_str, err_str_len-1,"Failed to find entry for user %s.\n", user_name);
+ return False;
+ }
+
+ if (pwd) {
+ /* Local user found, so init from this */
+ if (!NT_STATUS_IS_OK(pdb_init_sam_pw(&sam_pass, pwd))){
+ slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
+ passwd_free(&pwd);
+ return False;
+ }
+
+ passwd_free(&pwd);
+ } else {
+ if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_pass))){
+ slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
+ return False;
+ }
+
+ if (!pdb_set_username(sam_pass, user_name)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set username for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'domain trust account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'normal account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ } else {
+ /* the entry already existed */
+ local_flags &= ~LOCAL_ADD_USER;
+ }
+
+ /*
+ * We are root - just write the new password
+ * and the valid last change time.
+ */
+
+ if (local_flags & LOCAL_DISABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED)) {
+ slprintf(err_str, err_str_len-1, "Failed to set 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_ENABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ if (local_flags & LOCAL_SET_NO_PASSWORD) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ)) {
+ slprintf(err_str, err_str_len-1, "Failed to set 'no password required' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_SET_PASSWORD) {
+ /*
+ * If we're dealing with setting a completely empty user account
+ * ie. One with a password of 'XXXX', but not set disabled (like
+ * an account created from scratch) then if the old password was
+ * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
+ * We remove that as we're giving this user their first password
+ * and the decision hasn't really been made to disable them (ie.
+ * don't create them disabled). JRA.
+ */
+ if ((pdb_get_lanman_passwd(sam_pass)==NULL) && (pdb_get_acct_ctrl(sam_pass)&ACB_DISABLED)) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'no password required' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) {
+ slprintf(err_str, err_str_len-1, "Failed to set password for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ if (local_flags & LOCAL_ADD_USER) {
+ if (pdb_add_sam_account(sam_pass)) {
+ slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return True;
+ } else {
+ slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_DELETE_USER) {
+ if (!pdb_delete_sam_account(sam_pass)) {
+ slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ slprintf(msg_str, msg_str_len-1, "Deleted user %s.\n", user_name);
+ } else {
+ if(!pdb_update_sam_account(sam_pass)) {
+ slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ if(local_flags & LOCAL_DISABLE_USER)
+ slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_ENABLE_USER)
+ slprintf(msg_str, msg_str_len-1, "Enabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_SET_NO_PASSWORD)
+ slprintf(msg_str, msg_str_len-1, "User %s password set to none.\n", user_name);
+ }
+
+ pdb_free_sam(&sam_pass);
+ return True;
+}
diff --git a/source3/passdb/passgrp.c b/source3/passdb/passgrp.c
new file mode 100644
index 0000000000..d7ed965648
--- /dev/null
+++ b/source3/passdb/passgrp.c
@@ -0,0 +1,216 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+
+ 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"
+
+/*
+ * NOTE. All these functions are abstracted into a structure
+ * that points to the correct function for the selected database. JRA.
+ *
+ * the API does NOT fill in the gaps if you set an API function
+ * to NULL: it will deliberately attempt to call the NULL function.
+ *
+ */
+
+static struct passgrp_ops *pwgrp_ops;
+
+/***************************************************************
+ Initialise the passgrp operations.
+***************************************************************/
+
+BOOL initialise_passgrp_db(void)
+{
+ if (pwgrp_ops)
+ {
+ return True;
+ }
+
+#ifdef WITH_NISPLUS
+ pwgrp_ops = nisplus_initialise_password_grp();
+#elif defined(WITH_LDAP)
+ pwgrp_ops = ldap_initialize_password_grp();
+#else
+ pwgrp_ops = file_initialise_password_grp();
+#endif
+
+ return (pwgrp_ops != NULL);
+}
+
+/*
+ * Functions that return/manipulate a struct smb_passwd.
+ */
+
+/************************************************************************
+ Utility function to search smb passwd by rid.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrprid(uint32 user_rid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return iterate_getsmbgrpuid(pwdb_user_rid_to_uid(user_rid),
+ grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Utility function to search smb passwd by uid. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrpuid(uid_t smb_userid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ struct smb_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by smb_userid: %x\n", (int)smb_userid));
+
+ /* Open the smb password database - not for update. */
+ fp = startsmbgrpent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb passgrp database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && pwd->smb_userid != smb_userid)
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid));
+ }
+
+ endsmbgrpent(fp);
+ return pwd;
+}
+
+/************************************************************************
+ Utility function to search smb passwd by name. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrpnam(char *name,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ struct smb_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the passgrp file - not for update. */
+ fp = startsmbgrpent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb passgrp database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && !strequal(pwd->smb_name, name))
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endsmbgrpent(fp);
+ return pwd;
+}
+
+/***************************************************************
+ Start to enumerate the smb or sam passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ Note that currently it is being assumed that a pointer returned
+ from this function may be used to enumerate struct sam_passwd
+ entries as well as struct smb_passwd entries. This may need
+ to change. JRA.
+
+****************************************************************/
+
+void *startsmbgrpent(BOOL update)
+{
+ return pwgrp_ops->startsmbgrpent(update);
+}
+
+/***************************************************************
+ End enumeration of the smb or sam passwd list.
+
+ Note that currently it is being assumed that a pointer returned
+ from this function may be used to enumerate struct sam_passwd
+ entries as well as struct smb_passwd entries. This may need
+ to change. JRA.
+
+****************************************************************/
+
+void endsmbgrpent(void *vp)
+{
+ pwgrp_ops->endsmbgrpent(vp);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smb passwd list.
+ *************************************************************************/
+
+struct smb_passwd *getsmbgrpent(void *vp,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpent(vp, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by name.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrpnam(char *name,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpnam(name, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by user rid.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrprid(uint32 user_rid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrprid(user_rid, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by uid.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrpuid(uid_t smb_userid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpuid(smb_userid, grps, num_grps, alss, num_alss);
+}
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
new file mode 100644
index 0000000000..cf77efd38f
--- /dev/null
+++ b/source3/passdb/pdb_get_set.c
@@ -0,0 +1,956 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM_ACCOUNT access routines
+ 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"
+
+/**
+ * @todo Redefine this to NULL, but this changes the API becouse
+ * much of samba assumes that the pdb_get...() funtions
+ * return pstrings. (ie not null-pointers).
+ * See also pdb_fill_default_sam().
+ */
+
+#define PDB_NOT_QUITE_NULL ""
+
+/*********************************************************************
+ Collection of get...() functions for SAM_ACCOUNT_INFO.
+ ********************************************************************/
+
+uint16 pdb_get_acct_ctrl (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.acct_ctrl);
+ else
+ return (ACB_DISABLED);
+}
+
+time_t pdb_get_logon_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.logon_time);
+ else
+ return (0);
+}
+
+time_t pdb_get_logoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.logoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_kickoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.kickoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_last_set_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.pass_last_set_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_can_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.pass_can_change_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_must_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.pass_must_change_time);
+ else
+ return (-1);
+}
+
+uint16 pdb_get_logon_divs (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.logon_divs);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_hours_len (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.hours_len);
+ else
+ return (-1);
+}
+
+const uint8* pdb_get_hours (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.hours);
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_nt_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass) {
+ SMB_ASSERT((!sampass->private.nt_pw.data)
+ || sampass->private.nt_pw.length == NT_HASH_LEN);
+ return ((uint8*)sampass->private.nt_pw.data);
+ }
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass) {
+ SMB_ASSERT((!sampass->private.lm_pw.data)
+ || sampass->private.lm_pw.length == LM_HASH_LEN);
+ return ((uint8*)sampass->private.lm_pw.data);
+ }
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_user_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.user_rid);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_group_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.group_rid);
+ else
+ return (-1);
+}
+
+/**
+ * Get flags showing what is initalised in the SAM_ACCOUNT
+ * @param sampass the SAM_ACCOUNT in question
+ * @return the flags indicating the members initialised in the struct.
+ **/
+
+uint32 pdb_get_init_flag (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return sampass->private.init_flag;
+ else
+ return FLAG_SAM_UNINIT;
+}
+
+uid_t pdb_get_uid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.uid);
+ else
+ return (-1);
+}
+
+gid_t pdb_get_gid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.gid);
+ else
+ return (-1);
+}
+
+const char* pdb_get_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_domain (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.domain);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_nt_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.nt_username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_fullname (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.full_name);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_homedir (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.home_dir);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_dirdrive (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.dir_drive);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_logon_script (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.logon_script);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_profile_path (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.profile_path);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_acct_desc (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.acct_desc);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_workstations (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.workstations);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_unknown_str (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.unknown_str);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_munged_dial (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.munged_dial);
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_unknown3 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.unknown_3);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown5 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.unknown_5);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown6 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.unknown_6);
+ else
+ return (-1);
+}
+
+/*********************************************************************
+ Collection of set...() functions for SAM_ACCOUNT_INFO.
+ ********************************************************************/
+
+BOOL pdb_set_acct_ctrl (SAM_ACCOUNT *sampass, uint16 flags)
+{
+ if (!sampass)
+ return False;
+
+ if (sampass) {
+ sampass->private.acct_ctrl = flags;
+ return True;
+ }
+
+ return False;
+}
+
+BOOL pdb_set_logon_time (SAM_ACCOUNT *sampass, time_t mytime, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.logon_time = mytime;
+
+ if (store)
+ pdb_set_init_flag(sampass, FLAG_SAM_LOGONTIME);
+
+ return True;
+}
+
+BOOL pdb_set_logoff_time (SAM_ACCOUNT *sampass, time_t mytime, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.logoff_time = mytime;
+
+ if (store)
+ pdb_set_init_flag(sampass, FLAG_SAM_LOGOFFTIME);
+
+ return True;
+}
+
+BOOL pdb_set_kickoff_time (SAM_ACCOUNT *sampass, time_t mytime, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.kickoff_time = mytime;
+
+ if (store)
+ pdb_set_init_flag(sampass, FLAG_SAM_KICKOFFTIME);
+
+ return True;
+}
+
+BOOL pdb_set_pass_can_change_time (SAM_ACCOUNT *sampass, time_t mytime, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.pass_can_change_time = mytime;
+
+ if (store)
+ pdb_set_init_flag(sampass, FLAG_SAM_CANCHANGETIME);
+
+ return True;
+}
+
+BOOL pdb_set_pass_must_change_time (SAM_ACCOUNT *sampass, time_t mytime, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.pass_must_change_time = mytime;
+
+ if (store)
+ pdb_set_init_flag(sampass, FLAG_SAM_MUSTCHANGETIME);
+
+ return True;
+}
+
+BOOL pdb_set_pass_last_set_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.pass_last_set_time = mytime;
+
+ return True;
+}
+
+BOOL pdb_set_hours_len (SAM_ACCOUNT *sampass, uint32 len)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.hours_len = len;
+ return True;
+}
+
+BOOL pdb_set_logon_divs (SAM_ACCOUNT *sampass, uint16 hours)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.logon_divs = hours;
+ return True;
+}
+
+/**
+ * Set flags showing what is initalised in the SAM_ACCOUNT
+ * @param sampass the SAM_ACCOUNT in question
+ * @param flag The *new* flag to be set. Old flags preserved
+ * this flag is only added.
+ **/
+
+BOOL pdb_set_init_flag (SAM_ACCOUNT *sampass, uint32 flag)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.init_flag |= flag;
+
+ return True;
+}
+
+BOOL pdb_set_uid (SAM_ACCOUNT *sampass, const uid_t uid)
+{
+ if (!sampass)
+ return False;
+
+ DEBUG(10, ("pdb_set_uid: setting uid %d, was %d\n",
+ (int)uid, (int)sampass->private.uid));
+
+ sampass->private.uid = uid;
+ pdb_set_init_flag(sampass, FLAG_SAM_UID);
+
+ return True;
+
+}
+
+BOOL pdb_set_gid (SAM_ACCOUNT *sampass, const gid_t gid)
+{
+ if (!sampass)
+ return False;
+
+ DEBUG(10, ("pdb_set_gid: setting gid %d, was %d\n",
+ (int)gid, (int)sampass->private.gid));
+
+ sampass->private.gid = gid;
+ pdb_set_init_flag(sampass, FLAG_SAM_GID);
+
+ return True;
+
+}
+
+BOOL pdb_set_user_rid (SAM_ACCOUNT *sampass, uint32 rid)
+{
+ if (!sampass)
+ return False;
+
+ DEBUG(10, ("pdb_set_rid: setting user rid %d, was %d\n",
+ rid, sampass->private.user_rid));
+
+ sampass->private.user_rid = rid;
+ return True;
+}
+
+BOOL pdb_set_group_rid (SAM_ACCOUNT *sampass, uint32 grid)
+{
+ if (!sampass)
+ return False;
+
+ DEBUG(10, ("pdb_set_group_rid: setting group rid %d, was %d\n",
+ grid, sampass->private.group_rid));
+
+ sampass->private.group_rid = grid;
+ return True;
+}
+
+/*********************************************************************
+ Set the user's UNIX name.
+ ********************************************************************/
+
+BOOL pdb_set_username(SAM_ACCOUNT *sampass, const char *username)
+{
+ if (!sampass)
+ return False;
+
+ if (username) {
+ DEBUG(10, ("pdb_set_username: setting username %s, was %s\n", username,
+ (sampass->private.username)?(sampass->private.username):"NULL"));
+
+ sampass->private.username = talloc_strdup(sampass->mem_ctx, username);
+
+ if (!sampass->private.username) {
+ DEBUG(0, ("pdb_set_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.username = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+BOOL pdb_set_domain(SAM_ACCOUNT *sampass, const char *domain)
+{
+ if (!sampass)
+ return False;
+
+ if (domain) {
+ DEBUG(10, ("pdb_set_domain: setting domain %s, was %s\n", domain,
+ (sampass->private.domain)?(sampass->private.domain):"NULL"));
+
+ sampass->private.domain = talloc_strdup(sampass->mem_ctx, domain);
+
+ if (!sampass->private.domain) {
+ DEBUG(0, ("pdb_set_domain: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.domain = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT name.
+ ********************************************************************/
+
+BOOL pdb_set_nt_username(SAM_ACCOUNT *sampass, const char *nt_username)
+{
+ if (!sampass)
+ return False;
+
+ if (nt_username) {
+ DEBUG(10, ("pdb_set_nt_username: setting nt username %s, was %s\n", nt_username,
+ (sampass->private.nt_username)?(sampass->private.nt_username):"NULL"));
+
+ sampass->private.nt_username = talloc_strdup(sampass->mem_ctx, nt_username);
+
+ if (!sampass->private.nt_username) {
+ DEBUG(0, ("pdb_set_nt_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.nt_username = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's full name.
+ ********************************************************************/
+
+BOOL pdb_set_fullname(SAM_ACCOUNT *sampass, const char *full_name)
+{
+ if (!sampass)
+ return False;
+
+ if (full_name) {
+ DEBUG(10, ("pdb_set_full_name: setting full name %s, was %s\n", full_name,
+ (sampass->private.full_name)?(sampass->private.full_name):"NULL"));
+
+ sampass->private.full_name = talloc_strdup(sampass->mem_ctx, full_name);
+
+ if (!sampass->private.full_name) {
+ DEBUG(0, ("pdb_set_fullname: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.full_name = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's logon script.
+ ********************************************************************/
+
+BOOL pdb_set_logon_script(SAM_ACCOUNT *sampass, const char *logon_script, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ if (logon_script) {
+ DEBUG(10, ("pdb_set_logon_script: setting logon script %s, was %s\n", logon_script,
+ (sampass->private.logon_script)?(sampass->private.logon_script):"NULL"));
+
+ sampass->private.logon_script = talloc_strdup(sampass->mem_ctx, logon_script);
+
+ if (!sampass->private.logon_script) {
+ DEBUG(0, ("pdb_set_logon_script: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.logon_script = PDB_NOT_QUITE_NULL;
+ }
+
+ if (store) {
+ DEBUG(10, ("pdb_set_logon_script: setting logon script sam flag!"));
+ pdb_set_init_flag(sampass, FLAG_SAM_LOGONSCRIPT);
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's profile path.
+ ********************************************************************/
+
+BOOL pdb_set_profile_path (SAM_ACCOUNT *sampass, const char *profile_path, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ if (profile_path) {
+ DEBUG(10, ("pdb_set_profile_path: setting profile path %s, was %s\n", profile_path,
+ (sampass->private.profile_path)?(sampass->private.profile_path):"NULL"));
+
+ sampass->private.profile_path = talloc_strdup(sampass->mem_ctx, profile_path);
+
+ if (!sampass->private.profile_path) {
+ DEBUG(0, ("pdb_set_profile_path: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.profile_path = PDB_NOT_QUITE_NULL;
+ }
+
+ if (store) {
+ DEBUG(10, ("pdb_set_profile_path: setting profile path sam flag!"));
+ pdb_set_init_flag(sampass, FLAG_SAM_PROFILE);
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's directory drive.
+ ********************************************************************/
+
+BOOL pdb_set_dir_drive (SAM_ACCOUNT *sampass, const char *dir_drive, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ if (dir_drive) {
+ DEBUG(10, ("pdb_set_dir_drive: setting dir drive %s, was %s\n", dir_drive,
+ (sampass->private.dir_drive)?(sampass->private.dir_drive):"NULL"));
+
+ sampass->private.dir_drive = talloc_strdup(sampass->mem_ctx, dir_drive);
+
+ if (!sampass->private.dir_drive) {
+ DEBUG(0, ("pdb_set_dir_drive: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.dir_drive = PDB_NOT_QUITE_NULL;
+ }
+
+ if (store) {
+ DEBUG(10, ("pdb_set_dir_drive: setting dir drive sam flag!"));
+ pdb_set_init_flag(sampass, FLAG_SAM_DRIVE);
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's home directory.
+ ********************************************************************/
+
+BOOL pdb_set_homedir (SAM_ACCOUNT *sampass, const char *home_dir, BOOL store)
+{
+ if (!sampass)
+ return False;
+
+ if (home_dir) {
+ DEBUG(10, ("pdb_set_homedir: setting home dir %s, was %s\n", home_dir,
+ (sampass->private.home_dir)?(sampass->private.home_dir):"NULL"));
+
+ sampass->private.home_dir = talloc_strdup(sampass->mem_ctx, home_dir);
+
+ if (!sampass->private.home_dir) {
+ DEBUG(0, ("pdb_set_home_dir: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.home_dir = PDB_NOT_QUITE_NULL;
+ }
+
+ if (store) {
+ DEBUG(10, ("pdb_set_homedir: setting home dir sam flag!"));
+ pdb_set_init_flag(sampass, FLAG_SAM_SMBHOME);
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's account description.
+ ********************************************************************/
+
+BOOL pdb_set_acct_desc (SAM_ACCOUNT *sampass, const char *acct_desc)
+{
+ if (!sampass)
+ return False;
+
+ if (acct_desc) {
+ sampass->private.acct_desc = talloc_strdup(sampass->mem_ctx, acct_desc);
+
+ if (!sampass->private.acct_desc) {
+ DEBUG(0, ("pdb_set_acct_desc: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.acct_desc = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's workstation allowed list.
+ ********************************************************************/
+
+BOOL pdb_set_workstations (SAM_ACCOUNT *sampass, const char *workstations)
+{
+ if (!sampass)
+ return False;
+
+ if (workstations) {
+ DEBUG(10, ("pdb_set_workstations: setting workstations %s, was %s\n", workstations,
+ (sampass->private.workstations)?(sampass->private.workstations):"NULL"));
+
+ sampass->private.workstations = talloc_strdup(sampass->mem_ctx, workstations);
+
+ if (!sampass->private.workstations) {
+ DEBUG(0, ("pdb_set_workstations: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.workstations = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's 'unknown_str', whatever the heck this actually is...
+ ********************************************************************/
+
+BOOL pdb_set_unknown_str (SAM_ACCOUNT *sampass, const char *unknown_str)
+{
+ if (!sampass)
+ return False;
+
+ if (unknown_str) {
+ sampass->private.unknown_str = talloc_strdup(sampass->mem_ctx, unknown_str);
+
+ if (!sampass->private.unknown_str) {
+ DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.unknown_str = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's dial string.
+ ********************************************************************/
+
+BOOL pdb_set_munged_dial (SAM_ACCOUNT *sampass, const char *munged_dial)
+{
+ if (!sampass)
+ return False;
+
+ if (munged_dial) {
+ sampass->private.munged_dial = talloc_strdup(sampass->mem_ctx, munged_dial);
+
+ if (!sampass->private.munged_dial) {
+ DEBUG(0, ("pdb_set_munged_dial: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->private.munged_dial = PDB_NOT_QUITE_NULL;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT hash.
+ ********************************************************************/
+
+BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ data_blob_clear_free(&sampass->private.nt_pw);
+
+ sampass->private.nt_pw = data_blob(pwd, NT_HASH_LEN);
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's LM hash.
+ ********************************************************************/
+
+BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ data_blob_clear_free(&sampass->private.lm_pw);
+
+ sampass->private.lm_pw = data_blob(pwd, LM_HASH_LEN);
+
+ return True;
+}
+
+BOOL pdb_set_unknown_3 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.unknown_3 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_5 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.unknown_5 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_6 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.unknown_6 = unkn;
+ return True;
+}
+
+BOOL pdb_set_hours (SAM_ACCOUNT *sampass, const uint8 *hours)
+{
+ if (!sampass)
+ return False;
+
+ if (!hours) {
+ memset ((char *)sampass->private.hours, 0, MAX_HOURS_LEN);
+ return True;
+ }
+
+ memcpy (sampass->private.hours, hours, MAX_HOURS_LEN);
+
+ return True;
+}
+
+
+/* Helpful interfaces to the above */
+
+/*********************************************************************
+ Sets the last changed times and must change times for a normal
+ password change.
+ ********************************************************************/
+
+BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass)
+{
+ uint32 expire;
+
+ if (!sampass)
+ return False;
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL)))
+ return False;
+
+ account_policy_get(AP_MAX_PASSWORD_AGE, &expire);
+
+ if (expire==(uint32)-1) {
+ if (!pdb_set_pass_must_change_time (sampass, get_time_t_max(), False))
+ return False;
+ } else {
+ if (!pdb_set_pass_must_change_time (sampass,
+ pdb_get_pass_last_set_time(sampass)
+ + expire, True))
+ return False;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's PLAINTEXT password. Used as an interface to the above.
+ Also sets the last change time to NOW.
+ ********************************************************************/
+
+BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext)
+{
+ uchar new_lanman_p16[16];
+ uchar new_nt_p16[16];
+
+ if (!sampass || !plaintext)
+ return False;
+
+ nt_lm_owf_gen (plaintext, new_nt_p16, new_lanman_p16);
+
+ if (!pdb_set_nt_passwd (sampass, new_nt_p16))
+ return False;
+
+ if (!pdb_set_lanman_passwd (sampass, new_lanman_p16))
+ return False;
+
+ if (!pdb_set_pass_changed_now (sampass))
+ return False;
+
+ return True;
+}
+
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
new file mode 100644
index 0000000000..435b627da6
--- /dev/null
+++ b/source3/passdb/pdb_interface.c
@@ -0,0 +1,391 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 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"
+
+/** List of various built-in passdb modules */
+
+const struct pdb_init_function_entry builtin_pdb_init_functions[] = {
+ { "smbpasswd", pdb_init_smbpasswd },
+ { "smbpasswd_nua", pdb_init_smbpasswd_nua },
+ { "tdbsam", pdb_init_tdbsam },
+ { "tdbsam_nua", pdb_init_tdbsam_nua },
+ { "ldapsam", pdb_init_ldapsam },
+ { "ldapsam_nua", pdb_init_ldapsam_nua },
+#if 0
+ { "nisplus", pdb_init_nisplus },
+ { "unix", pdb_init_unix },
+#endif
+ { "plugin", pdb_init_plugin },
+ { NULL, NULL}
+};
+
+static BOOL context_setsampwent(struct pdb_context *context, BOOL update)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ return context->pdb_selected->setsampwent(context, update);
+}
+
+static void context_endsampwent(struct pdb_context *context)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return;
+ }
+
+ context->pdb_selected->endsampwent(context);
+}
+
+static BOOL context_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ return context->pdb_selected->getsampwent(context, user);
+}
+
+static BOOL context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ return context->pdb_selected->getsampwnam(context, sam_acct, username);
+}
+
+static BOOL context_getsampwrid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, uint32 rid)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ return context->pdb_selected->getsampwrid(context, sam_acct, rid);
+}
+
+static BOOL context_add_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ /** @todo This is where a 're-read on add' should be done */
+
+ return context->pdb_selected->add_sam_account(context, sam_acct);
+}
+
+static BOOL context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ /** @todo This is where a 're-read on update' should be done */
+
+ return context->pdb_selected->update_sam_account(context, sam_acct);
+}
+
+static BOOL context_delete_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
+{
+ if ((!context) || (!context->pdb_selected)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return False;
+ }
+
+ return context->pdb_selected->delete_sam_account(context, sam_acct);
+}
+
+static void free_pdb_context(struct pdb_context **context)
+{
+ if (((*context)->pdb_selected) && ((*context)->pdb_selected->free_private_data)) {
+ (*context)->pdb_selected->free_private_data((*context)->pdb_selected->private_data);
+ }
+
+ talloc_destroy((*context)->mem_ctx);
+ *context = NULL;
+}
+
+/******************************************************************
+ Make a pdb_context from scratch.
+*******************************************************************/
+
+static NTSTATUS make_pdb_context(struct pdb_context **context)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init_named("pdb_context internal allocation context");
+
+ if (!mem_ctx) {
+ DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *context = talloc(mem_ctx, sizeof(**context));
+ if (!*context) {
+ DEBUG(0, ("make_pdb_context: talloc failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*context);
+
+ (*context)->mem_ctx = mem_ctx;
+
+ (*context)->pdb_setsampwent = context_setsampwent;
+ (*context)->pdb_endsampwent = context_endsampwent;
+ (*context)->pdb_getsampwent = context_getsampwent;
+ (*context)->pdb_getsampwnam = context_getsampwnam;
+ (*context)->pdb_getsampwrid = context_getsampwrid;
+ (*context)->pdb_add_sam_account = context_add_sam_account;
+ (*context)->pdb_update_sam_account = context_update_sam_account;
+ (*context)->pdb_delete_sam_account = context_delete_sam_account;
+
+ (*context)->free_fn = free_pdb_context;
+
+ return NT_STATUS_OK;
+}
+
+
+/******************************************************************
+ Make a pdb_context, given a text string.
+*******************************************************************/
+
+NTSTATUS make_pdb_context_name(struct pdb_context **context, const char *selected)
+{
+ /* HINT: Don't store 'selected' becouse its often an lp_ string and
+ will 'go away' */
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ int i;
+ char *module_name = smb_xstrdup(selected);
+ char *module_location = NULL;
+ char *p;
+
+ p = strchr(module_name, ':');
+
+ if (p) {
+ *p = 0;
+
+ module_location = p+1;
+
+ trim_string(module_location, " ", " ");
+ }
+
+ trim_string(module_name, " ", " ");
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context)))
+ goto done;
+
+ DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n",
+ selected, module_name));
+
+ for (i = 0; builtin_pdb_init_functions[i].name; i++) {
+ if (strequal(builtin_pdb_init_functions[i].name,
+ module_name)) {
+
+ DEBUG(5,("Found pdb backend %s (at pos %d)\n",
+ module_name, i));
+
+ if (NT_STATUS_IS_OK(nt_status = builtin_pdb_init_functions[i].init(*context, &(*context)->pdb_selected, module_location))) {
+ DEBUG(5,("pdb backend %s has a valid init\n", selected));
+ } else {
+ DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
+ (*context)->pdb_selected = NULL;
+ }
+ break;
+ }
+ }
+
+ if (!(*context)->pdb_selected) {
+ DEBUG(0,("failed to select passdb backed!\n"));
+ talloc_destroy((*context)->mem_ctx);
+ *context = NULL;
+ goto done;
+ }
+
+ nt_status = NT_STATUS_OK;
+
+ done:
+ SAFE_FREE(module_name);
+
+ return nt_status;
+}
+
+
+/******************************************************************
+ Return an already initialised pdb_context, to facilitate backward
+ compatibility (see functions below).
+*******************************************************************/
+
+static struct pdb_context *pdb_get_static_context(BOOL reload)
+{
+ static struct pdb_context *pdb_context = NULL;
+
+ if ((pdb_context) && (reload)) {
+ pdb_context->free_fn(&pdb_context);
+ if (!NT_STATUS_IS_OK(make_pdb_context_name(&pdb_context, lp_passdb_backend()))) {
+ return NULL;
+ }
+ }
+
+ if (!pdb_context) {
+ if (!NT_STATUS_IS_OK(make_pdb_context_name(&pdb_context, lp_passdb_backend()))) {
+ return NULL;
+ }
+ }
+
+ return pdb_context;
+}
+
+#if !defined(WITH_NISPLUS_SAM)
+
+/******************************************************************
+ Backward compatibility functions for the original passdb interface
+*******************************************************************/
+
+BOOL pdb_setsampwent(BOOL update)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_setsampwent(pdb_context, update);
+}
+
+void pdb_endsampwent(void)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return;
+ }
+
+ pdb_context->pdb_endsampwent(pdb_context);
+}
+
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_getsampwent(pdb_context, user);
+}
+
+BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_getsampwnam(pdb_context, sam_acct, username);
+}
+
+BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct, uint32 rid)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_getsampwrid(pdb_context, sam_acct, rid);
+}
+
+BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_add_sam_account(pdb_context, sam_acct);
+}
+
+BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_update_sam_account(pdb_context, sam_acct);
+}
+
+BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return pdb_context->pdb_delete_sam_account(pdb_context, sam_acct);
+}
+
+#endif /* !defined(WITH_NISPLUS_SAM) */
+
+/***************************************************************
+ Initialize the static context (at smbd startup etc).
+
+ If uninitialised, context will auto-init on first use.
+***************************************************************/
+
+BOOL initialize_password_db(BOOL reload)
+{
+ return (pdb_get_static_context(reload) != NULL);
+}
+
+
+NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
+{
+ *methods = talloc(mem_ctx, sizeof(struct pdb_methods));
+
+ if (!*methods) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*methods);
+
+ return NT_STATUS_OK;
+}
+
+
+
+
+
+
+
+
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
new file mode 100644
index 0000000000..02bb43b7ff
--- /dev/null
+++ b/source3/passdb/pdb_ldap.c
@@ -0,0 +1,1537 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Gerald Carter 2001
+ Copyright (C) Shahms King 2001
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Andrew Bartlett 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"
+
+#ifdef WITH_LDAP_SAM
+/* TODO:
+* persistent connections: if using NSS LDAP, many connections are made
+* however, using only one within Samba would be nice
+*
+* Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
+*
+* Other LDAP based login attributes: accountExpires, etc.
+* (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
+* structures don't have fields for some of these attributes)
+*
+* SSL is done, but can't get the certificate based authentication to work
+* against on my test platform (Linux 2.4, OpenLDAP 2.x)
+*/
+
+/* NOTE: this will NOT work against an Active Directory server
+* due to the fact that the two password fields cannot be retrieved
+* from a server; recommend using security = domain in this situation
+* and/or winbind
+*/
+
+#include <lber.h>
+#include <ldap.h>
+
+#ifndef SAM_ACCOUNT
+#define SAM_ACCOUNT struct sam_passwd
+#endif
+
+struct ldapsam_privates {
+
+ /* Former statics */
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ int index;
+
+ /* retrive-once info */
+ const char *uri;
+
+ BOOL permit_non_unix_accounts;
+
+ uint32 low_nua_rid;
+ uint32 high_nua_rid;
+};
+
+static uint32 ldapsam_get_next_available_nua_rid(struct ldapsam_privates *ldap_state);
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+static uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+static uint32 pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ find the ldap password
+******************************************************************/
+static BOOL fetch_ldapsam_pw(char *dn, char* pw, int len)
+{
+ fstring key;
+ char *p;
+ void *data = NULL;
+ size_t size;
+
+ pstrcpy(key, dn);
+ for (p=key; *p; p++)
+ if (*p == ',') *p = '/';
+
+ data=secrets_fetch(key, &size);
+ if (!size) {
+ DEBUG(0,("fetch_ldap_pw: no ldap secret retrieved!\n"));
+ return False;
+ }
+
+ if (size > len-1)
+ {
+ DEBUG(0,("fetch_ldap_pw: ldap secret is too long (%d > %d)!\n", size, len-1));
+ return False;
+ }
+
+ memcpy(pw, data, size);
+ pw[size] = '\0';
+
+ return True;
+}
+
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static BOOL ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct)
+{
+
+ if (geteuid() != 0) {
+ DEBUG(0, ("ldap_open_connection: cannot access LDAP when not root..\n"));
+ return False;
+ }
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+ DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
+
+ if (ldap_initialize(ldap_struct, ldap_state->uri) != LDAP_SUCCESS) {
+ DEBUG(0, ("ldap_initialize: %s\n", strerror(errno)));
+ return (False);
+ }
+#else
+
+ /* Parse the string manually */
+
+ {
+ int rc;
+ int tls = LDAP_OPT_X_TLS_HARD;
+ int port = 0;
+ int version;
+ fstring protocol;
+ fstring host;
+ const char *p = ldap_state->uri;
+ SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
+
+ /* skip leading "URL:" (if any) */
+ if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
+ p += 4;
+ }
+
+ sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
+
+ if (port == 0) {
+ if (strequal(protocol, "ldap")) {
+ port = LDAP_PORT;
+ } else if (strequal(protocol, "ldaps")) {
+ port = LDAPS_PORT;
+ } else {
+ DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
+ }
+ }
+
+ if ((*ldap_struct = ldap_init(host, port)) == NULL) {
+ DEBUG(0, ("ldap_init failed !\n"));
+ return False;
+ }
+
+ /* Connect to older servers using SSL and V2 rather than Start TLS */
+ if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version != LDAP_VERSION2)
+ {
+ version = LDAP_VERSION2;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ }
+ }
+
+ if (strequal(protocol, "ldaps")) {
+ if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
+ if (ldap_get_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ }
+ }
+ if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
+ {
+ DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
+ ldap_err2string(rc)));
+ return False;
+ }
+ DEBUG (2, ("StartTLS issued: using a TLS connection\n"));
+ } else {
+
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+ }
+ } else {
+ /*
+ * No special needs to setup options prior to the LDAP
+ * bind (which should be called next via ldap_connect_system()
+ */
+ }
+ }
+#endif
+
+ DEBUG(2, ("ldap_open_connection: connection opened\n"));
+ return True;
+}
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static BOOL ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ldap_struct)
+{
+ int rc;
+ static BOOL got_pw = False;
+ static pstring ldap_secret;
+
+ /* get the password if we don't have it already */
+ if (!got_pw && !(got_pw=fetch_ldapsam_pw(lp_ldap_admin_dn(), ldap_secret, sizeof(pstring))))
+ {
+ DEBUG(0, ("ldap_connect_system: Failed to retrieve password for %s from secrets.tdb\n",
+ lp_ldap_admin_dn()));
+ return False;
+ }
+
+ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
+ (OpenLDAP) doesnt' seem to support it */
+
+ DEBUG(10,("ldap_connect_system: Binding to ldap server as \"%s\"\n",
+ lp_ldap_admin_dn()));
+
+ if ((rc = ldap_simple_bind_s(ldap_struct, lp_ldap_admin_dn(),
+ ldap_secret)) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Bind failed: %s\n", ldap_err2string(rc)));
+ return False;
+ }
+
+ DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return True;
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldapsam_search_one_user (struct ldapsam_privates *ldap_state, LDAP * ldap_struct, const char *filter, LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+
+ DEBUG(2, ("ldapsam_search_one_user: searching for:[%s]\n", filter));
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix (), scope, filter, NULL, 0, result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_search_one_user: Problem during the LDAP search: %s\n",
+ ldap_err2string (rc)));
+ DEBUG(3,("ldapsam_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(),
+ filter));
+ }
+
+ return rc;
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldapsam_search_one_user_by_name (struct ldapsam_privates *ldap_state, LDAP * ldap_struct, const char *user,
+ LDAPMessage ** result)
+{
+ pstring filter;
+
+ /*
+ * in the filter expression, replace %u with the real name
+ * so in ldap filter, %u MUST exist :-)
+ */
+ pstrcpy(filter, lp_ldap_filter());
+
+ /*
+ * have to use this here because $ is filtered out
+ * in pstring_sub
+ */
+ all_string_sub(filter, "%u", user, sizeof(pstring));
+
+ return ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static int ldapsam_search_one_user_by_uid(struct ldapsam_privates *ldap_state,
+ LDAP * ldap_struct, int uid,
+ LDAPMessage ** result)
+{
+ struct passwd *user;
+ pstring filter;
+
+ /* Get the username from the system and look that up in the LDAP */
+
+ if ((user = getpwuid_alloc(uid)) == NULL) {
+ DEBUG(3,("ldapsam_search_one_user_by_uid: Failed to locate uid [%d]\n", uid));
+ return LDAP_NO_SUCH_OBJECT;
+ }
+
+ pstrcpy(filter, lp_ldap_filter());
+
+ all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
+
+ passwd_free(&user);
+
+ return ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by rid.
+******************************************************************/
+static int ldapsam_search_one_user_by_rid (struct ldapsam_privates *ldap_state,
+ LDAP * ldap_struct, uint32 rid,
+ LDAPMessage ** result)
+{
+ pstring filter;
+ int rc;
+
+ /* check if the user rid exsists, if not, try searching on the uid */
+
+ snprintf(filter, sizeof(filter) - 1, "rid=%i", rid);
+ rc = ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
+
+ if (rc != LDAP_SUCCESS)
+ rc = ldapsam_search_one_user_by_uid(ldap_state, ldap_struct,
+ pdb_user_rid_to_uid(rid),
+ result);
+
+ return rc;
+}
+
+/*******************************************************************
+search an attribute and return the first value found.
+******************************************************************/
+static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ char *attribute, char *value)
+{
+ char **values;
+
+ if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
+ value = NULL;
+ DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
+
+ return False;
+ }
+
+ pstrcpy(value, values[0]);
+ ldap_value_free(values);
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
+#endif
+ return True;
+}
+
+/************************************************************************
+Routine to manage the LDAPMod structure array
+manage memory used by the array, by each struct, and values
+
+************************************************************************/
+static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
+{
+ LDAPMod **mods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (attribute == NULL || *attribute == '\0')
+ return;
+
+ if (value == NULL || *value == '\0')
+ return;
+
+ if (mods == NULL)
+ {
+ mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[0] = NULL;
+ }
+
+ for (i = 0; mods[i] != NULL; ++i) {
+ if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
+ break;
+ }
+
+ if (mods[i] == NULL)
+ {
+ mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
+ if (mods[i] == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i]->mod_op = modop;
+ mods[i]->mod_values = NULL;
+ mods[i]->mod_type = strdup(attribute);
+ mods[i + 1] = NULL;
+ }
+
+ if (value != NULL)
+ {
+ j = 0;
+ if (mods[i]->mod_values != NULL) {
+ for (; mods[i]->mod_values[j] != NULL; j++);
+ }
+ mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
+ (j + 2) * sizeof (char *));
+
+ if (mods[i]->mod_values == NULL) {
+ DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
+ return;
+ }
+ mods[i]->mod_values[j] = strdup(value);
+ mods[i]->mod_values[j + 1] = NULL;
+ }
+ *modlist = mods;
+}
+
+/* New Interface is being implemented here */
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_sam_from_buffer in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
+ SAM_ACCOUNT * sampass,
+ LDAP * ldap_struct, LDAPMessage * entry)
+{
+ time_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ pstring username,
+ domain,
+ nt_username,
+ fullname,
+ homedir,
+ dir_drive,
+ logon_script,
+ profile_path,
+ acct_desc,
+ munged_dial,
+ workstations;
+ struct passwd *pw;
+ uint32 user_rid,
+ group_rid;
+ uint8 smblmpwd[16],
+ smbntpwd[16];
+ uint16 acct_ctrl,
+ logon_divs;
+ uint32 hours_len;
+ uint8 hours[MAX_HOURS_LEN];
+ pstring temp;
+ uid_t uid = -1;
+ gid_t gid = getegid();
+
+
+ /*
+ * do a little initialization
+ */
+ username[0] = '\0';
+ domain[0] = '\0';
+ nt_username[0] = '\0';
+ fullname[0] = '\0';
+ homedir[0] = '\0';
+ dir_drive[0] = '\0';
+ logon_script[0] = '\0';
+ profile_path[0] = '\0';
+ acct_desc[0] = '\0';
+ munged_dial[0] = '\0';
+ workstations[0] = '\0';
+
+
+ if (sampass == NULL || ldap_struct == NULL || entry == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
+ return False;
+ }
+
+ get_single_attribute(ldap_struct, entry, "uid", username);
+ DEBUG(2, ("Entry found for user: %s\n", username));
+
+ pstrcpy(nt_username, username);
+
+ pstrcpy(domain, lp_workgroup());
+
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user_rid = (uint32)atol(temp);
+ if (!get_single_attribute(ldap_struct, entry, "primaryGroupID", temp)) {
+ group_rid = 0;
+ } else {
+ group_rid = (uint32)atol(temp);
+ }
+
+ if ((ldap_state->permit_non_unix_accounts)
+ && (user_rid >= ldap_state->low_nua_rid)
+ && (user_rid <= ldap_state->high_nua_rid)) {
+
+ } else {
+
+ /* These values MAY be in LDAP, but they can also be retrieved through
+ * sys_getpw*() which is how we're doing it
+ */
+
+ pw = getpwnam_alloc(username);
+ if (pw == NULL) {
+ DEBUG (2,("init_sam_from_ldap: User [%s] does not ave a uid!\n", username));
+ return False;
+ }
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+
+ passwd_free(&pw);
+
+ pdb_set_uid(sampass, uid);
+ pdb_set_gid(sampass, gid);
+
+ if (group_rid == 0) {
+ GROUP_MAP map;
+ /* call the mapping code here */
+ if(get_group_map_from_gid(gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &group_rid);
+ }
+ else {
+ group_rid=pdb_gid_to_group_rid(gid);
+ }
+ }
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "pwdLastSet", temp)) {
+ /* leave as default */
+ } else {
+ pass_last_set_time = (time_t) atol(temp);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "logonTime", temp)) {
+ /* leave as default */
+ } else {
+ logon_time = (time_t) atol(temp);
+ pdb_set_logon_time(sampass, logon_time, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "logoffTime", temp)) {
+ /* leave as default */
+ } else {
+ logoff_time = (time_t) atol(temp);
+ pdb_set_logoff_time(sampass, logoff_time, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "kickoffTime", temp)) {
+ /* leave as default */
+ } else {
+ kickoff_time = (time_t) atol(temp);
+ pdb_set_kickoff_time(sampass, kickoff_time, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "pwdCanChange", temp)) {
+ /* leave as default */
+ } else {
+ pass_can_change_time = (time_t) atol(temp);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "pwdMustChange", temp)) {
+ /* leave as default */
+ } else {
+ pass_must_change_time = (time_t) atol(temp);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time, True);
+ }
+
+ /* recommend that 'gecos' and 'displayName' should refer to the same
+ * attribute OID. userFullName depreciated, only used by Samba
+ * primary rules of LDAP: don't make a new attribute when one is already defined
+ * that fits your needs; using cn then displayName rather than 'userFullName'
+ */
+
+ if (!get_single_attribute(ldap_struct, entry, "cn", fullname)) {
+ if (!get_single_attribute(ldap_struct, entry, "displayName", fullname)) {
+ /* leave as default */
+ } else {
+ pdb_set_fullname(sampass, fullname);
+ }
+ } else {
+ pdb_set_fullname(sampass, fullname);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive)) {
+ pstrcpy(dir_drive, lp_logon_drive());
+ standard_sub_advanced(-1, username, "", gid, username, dir_drive);
+ DEBUG(5,("homeDrive fell back to %s\n",dir_drive));
+ pdb_set_dir_drive(sampass, dir_drive, False);
+ } else {
+ pdb_set_dir_drive(sampass, dir_drive, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "smbHome", homedir)) {
+ pstrcpy(homedir, lp_logon_home());
+ standard_sub_advanced(-1, username, "", gid, username, homedir);
+ DEBUG(5,("smbHome fell back to %s\n",homedir));
+ pdb_set_homedir(sampass, homedir, False);
+ } else {
+ pdb_set_homedir(sampass, homedir, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "scriptPath", logon_script)) {
+ pstrcpy(logon_script, lp_logon_script());
+ standard_sub_advanced(-1, username, "", gid, username, logon_script);
+ DEBUG(5,("scriptPath fell back to %s\n",logon_script));
+ pdb_set_logon_script(sampass, logon_script, False);
+ } else {
+ pdb_set_logon_script(sampass, logon_script, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "profilePath", profile_path)) {
+ pstrcpy(profile_path, lp_logon_path());
+ standard_sub_advanced(-1, username, "", gid, username, profile_path);
+ DEBUG(5,("profilePath fell back to %s\n",profile_path));
+ pdb_set_profile_path(sampass, profile_path, False);
+ } else {
+ pdb_set_profile_path(sampass, profile_path, True);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "description", acct_desc)) {
+ /* leave as default */
+ } else {
+ pdb_set_acct_desc(sampass, acct_desc);
+ }
+
+ if (!get_single_attribute(ldap_struct, entry, "userWorkstations", workstations)) {
+ /* leave as default */;
+ } else {
+ pdb_set_workstations(sampass, workstations);
+ }
+
+ /* FIXME: hours stuff should be cleaner */
+
+ logon_divs = 168;
+ hours_len = 21;
+ memset(hours, 0xff, hours_len);
+
+ if (!get_single_attribute (ldap_struct, entry, "lmPassword", temp)) {
+ /* leave as default */
+ } else {
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd))
+ return False;
+ }
+
+ if (!get_single_attribute (ldap_struct, entry, "ntPassword", temp)) {
+ /* leave as default */
+ } else {
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ if (!pdb_set_nt_passwd(sampass, smbntpwd))
+ return False;
+ }
+
+ if (!get_single_attribute (ldap_struct, entry, "acctFlags", temp)) {
+ acct_ctrl |= ACB_NORMAL;
+ } else {
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0)
+ acct_ctrl |= ACB_NORMAL;
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ }
+
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_logon_divs(sampass, logon_divs);
+
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+
+ pdb_set_username(sampass, username);
+
+ pdb_set_domain(sampass, domain);
+ pdb_set_nt_username(sampass, nt_username);
+
+ pdb_set_munged_dial(sampass, munged_dial);
+
+ /* pdb_set_unknown_3(sampass, unknown3); */
+ /* pdb_set_unknown_5(sampass, unknown5); */
+ /* pdb_set_unknown_6(sampass, unknown6); */
+
+ pdb_set_hours(sampass, hours);
+
+ return True;
+}
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_buffer_from_sam in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
+ LDAPMod *** mods, int ldap_op,
+ const SAM_ACCOUNT * sampass)
+{
+ pstring temp;
+ uint32 rid;
+
+ if (mods == NULL || sampass == NULL) {
+ DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
+ return False;
+ }
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+
+ make_a_mod(mods, ldap_op, "uid", pdb_get_username(sampass));
+ DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ if ( pdb_get_user_rid(sampass) ) {
+ rid = pdb_get_user_rid(sampass);
+ } else if (IS_SAM_SET(sampass, FLAG_SAM_UID)) {
+ rid = pdb_uid_to_user_rid(pdb_get_uid(sampass));
+ } else if (ldap_state->permit_non_unix_accounts) {
+ rid = ldapsam_get_next_available_nua_rid(ldap_state);
+ if (rid == 0) {
+ DEBUG(0, ("NO user RID specified on account %s, and findining next available NUA RID failed, cannot store!\n", pdb_get_username(sampass)));
+ return False;
+ }
+ } else {
+ DEBUG(0, ("NO user RID specified on account %s, cannot store!\n", pdb_get_username(sampass)));
+ return False;
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "%i", rid);
+ make_a_mod(mods, ldap_op, "rid", temp);
+
+ if ( pdb_get_group_rid(sampass) ) {
+ rid = pdb_get_group_rid(sampass);
+ } else if (IS_SAM_SET(sampass, FLAG_SAM_GID)) {
+ rid = pdb_gid_to_group_rid(pdb_get_gid(sampass));
+ } else if (ldap_state->permit_non_unix_accounts) {
+ rid = DOMAIN_GROUP_RID_USERS;
+ } else {
+ DEBUG(0, ("NO group RID specified on account %s, cannot store!\n", pdb_get_username(sampass)));
+ return False;
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "%i", rid);
+ make_a_mod(mods, ldap_op, "primaryGroupID", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
+ make_a_mod(mods, ldap_op, "pwdLastSet", temp);
+
+ /* displayName, cn, and gecos should all be the same
+ * most easily accomplished by giving them the same OID
+ * gecos isn't set here b/c it should be handled by the
+ * add-user script
+ */
+
+ make_a_mod(mods, ldap_op, "displayName", pdb_get_fullname(sampass));
+ make_a_mod(mods, ldap_op, "cn", pdb_get_fullname(sampass));
+ make_a_mod(mods, ldap_op, "description", pdb_get_acct_desc(sampass));
+ make_a_mod(mods, ldap_op, "userWorkstations", pdb_get_workstations(sampass));
+
+ /*
+ * Only updates fields which have been set (not defaults from smb.conf)
+ */
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_SMBHOME))
+ make_a_mod(mods, ldap_op, "smbHome", pdb_get_homedir(sampass));
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_DRIVE))
+ make_a_mod(mods, ldap_op, "homeDrive", pdb_get_dirdrive(sampass));
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_LOGONSCRIPT))
+ make_a_mod(mods, ldap_op, "scriptPath", pdb_get_logon_script(sampass));
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_PROFILE))
+ make_a_mod(mods, ldap_op, "profilePath", pdb_get_profile_path(sampass));
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_LOGONTIME)) {
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
+ make_a_mod(mods, ldap_op, "logonTime", temp);
+ }
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_LOGOFFTIME)) {
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
+ make_a_mod(mods, ldap_op, "logoffTime", temp);
+ }
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_KICKOFFTIME)) {
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
+ make_a_mod(mods, ldap_op, "kickoffTime", temp);
+ }
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_CANCHANGETIME)) {
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
+ make_a_mod(mods, ldap_op, "pwdCanChange", temp);
+ }
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_MUSTCHANGETIME)) {
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
+ make_a_mod(mods, ldap_op, "pwdMustChange", temp);
+ }
+
+ /* FIXME: Hours stuff goes in LDAP */
+ pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_op, "lmPassword", temp);
+
+ pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_op, "ntPassword", temp);
+
+ make_a_mod (mods, ldap_op, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ return True;
+}
+
+
+/**********************************************************************
+Connect to LDAP server and find the next available RID.
+*********************************************************************/
+static uint32 check_nua_rid_is_avail(struct ldapsam_privates *ldap_state, uint32 top_rid, LDAP *ldap_struct)
+{
+ LDAPMessage *result;
+ uint32 final_rid = (top_rid & (~USER_RID_TYPE)) + RID_MULTIPLIER;
+ if (top_rid == 0) {
+ return 0;
+ }
+
+ if (final_rid < ldap_state->low_nua_rid || final_rid > ldap_state->high_nua_rid) {
+ return 0;
+ }
+
+ if (ldapsam_search_one_user_by_rid(ldap_state, ldap_struct, final_rid, &result) != LDAP_SUCCESS) {
+ DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the confirmation search failed!\n", final_rid, final_rid));
+ final_rid = 0;
+ ldap_msgfree(result);
+ }
+
+ if (ldap_count_entries(ldap_struct, result) != 0)
+ {
+ DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the RID is already in use!!\n", final_rid, final_rid));
+ final_rid = 0;
+ ldap_msgfree(result);
+ }
+
+ DEBUG(5, ("NUA RID %d (0x%x), declared valid\n", final_rid, final_rid));
+ return final_rid;
+}
+
+/**********************************************************************
+Extract the RID from an LDAP entry
+*********************************************************************/
+static uint32 entry_to_user_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, LDAP *ldap_struct) {
+ uint32 rid;
+ SAM_ACCOUNT *user = NULL;
+ if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
+ return 0;
+ }
+
+ if (init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
+ rid = pdb_get_user_rid(user);
+ } else {
+ rid =0;
+ }
+ pdb_free_sam(&user);
+ if (rid >= ldap_state->low_nua_rid && rid <= ldap_state->high_nua_rid) {
+ return rid;
+ }
+ return 0;
+}
+
+
+/**********************************************************************
+Connect to LDAP server and find the next available RID.
+*********************************************************************/
+static uint32 search_top_nua_rid(struct ldapsam_privates *ldap_state, LDAP *ldap_struct)
+{
+ int rc;
+ pstring filter;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ char *final_filter = NULL;
+ uint32 top_rid = 0;
+ uint32 count;
+ uint32 rid;
+
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", "*", sizeof(pstring));
+
+#if 0
+ asprintf(&final_filter, "(&(%s)(&(rid>=%d)(rid<=%d)))", filter, ldap_state->low_nua_rid, ldap_state->high_nua_rid);
+#else
+ final_filter = strdup(filter);
+#endif
+ DEBUG(2, ("ldapsam_get_next_available_nua_rid: searching for:[%s]\n", final_filter));
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, final_filter, NULL, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ {
+
+ DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
+ DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
+
+ free(final_filter);
+ ldap_msgfree(result);
+ result = NULL;
+ return 0;
+ }
+
+ count = ldap_count_entries(ldap_struct, result);
+ DEBUG(2, ("search_top_nua_rid: %d entries in the base!\n", count));
+
+ if (count == 0) {
+ DEBUG(3, ("LDAP search returned no records, assuming no non-unix-accounts present!: %s\n", ldap_err2string(rc)));
+ DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
+ free(final_filter);
+ ldap_msgfree(result);
+ result = NULL;
+ return ldap_state->low_nua_rid;
+ }
+
+ free(final_filter);
+ entry = ldap_first_entry(ldap_struct,result);
+
+ top_rid = entry_to_user_rid(ldap_state, entry, ldap_struct);
+
+ while ((entry = ldap_next_entry(ldap_struct, entry))) {
+
+ rid = entry_to_user_rid(ldap_state, entry, ldap_struct);
+ if (rid > top_rid) {
+ top_rid = rid;
+ }
+ }
+
+ ldap_msgfree(result);
+ return top_rid;
+}
+
+/**********************************************************************
+Connect to LDAP server and find the next available RID.
+*********************************************************************/
+static uint32 ldapsam_get_next_available_nua_rid(struct ldapsam_privates *ldap_state) {
+ LDAP *ldap_struct;
+ uint32 next_nua_rid;
+ uint32 top_nua_rid;
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+ {
+ return 0;
+ }
+ if (!ldapsam_connect_system(ldap_state, ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return 0;
+ }
+
+ top_nua_rid = search_top_nua_rid(ldap_state, ldap_struct);
+
+ next_nua_rid = check_nua_rid_is_avail(ldap_state,
+ top_nua_rid, ldap_struct);
+
+ ldap_unbind(ldap_struct);
+ return next_nua_rid;
+}
+
+/**********************************************************************
+Connect to LDAP server for password enumeration
+*********************************************************************/
+static BOOL ldapsam_setsampwent(struct pdb_context *context, BOOL update)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ int rc;
+ pstring filter;
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_state->ldap_struct))
+ {
+ return False;
+ }
+ if (!ldapsam_connect_system(ldap_state, ldap_state->ldap_struct))
+ {
+ ldap_unbind(ldap_state->ldap_struct);
+ return False;
+ }
+
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", "*", sizeof(pstring));
+
+ rc = ldap_search_s(ldap_state->ldap_struct, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0,
+ &ldap_state->result);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
+ DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+ ldap_msgfree(ldap_state->result);
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ ldap_state->result = NULL;
+ return False;
+ }
+
+ DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
+ ldap_count_entries(ldap_state->ldap_struct,
+ ldap_state->result)));
+
+ ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
+ ldap_state->result);
+ ldap_state->index = 0;
+
+ return True;
+}
+
+/**********************************************************************
+End enumeration of the LDAP password list
+*********************************************************************/
+static void ldapsam_endsampwent(struct pdb_context *context)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ if (ldap_state->ldap_struct && ldap_state->result)
+ {
+ ldap_msgfree(ldap_state->result);
+ ldap_unbind(ldap_state->ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ ldap_state->result = NULL;
+ }
+}
+
+/**********************************************************************
+Get the next entry in the LDAP password database
+*********************************************************************/
+static BOOL ldapsam_getsampwent(struct pdb_context *context, SAM_ACCOUNT * user)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ BOOL ret = False;
+
+ while (!ret) {
+ if (!ldap_state->entry)
+ return False;
+
+ ldap_state->index++;
+ ret = init_sam_from_ldap(ldap_state, user, ldap_state->ldap_struct,
+ ldap_state->entry);
+
+ ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
+ ldap_state->entry);
+
+ }
+
+ return True;
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by username
+*********************************************************************/
+static BOOL ldapsam_getsampwnam(struct pdb_context *context, SAM_ACCOUNT * user, const char *sname)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+ return False;
+ if (!ldapsam_connect_system(ldap_state, ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldapsam_search_one_user_by_name(ldap_state, ldap_struct, sname, &result) != LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(4,
+ ("We don't find this user [%s] count=%d\n", sname,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ if (!init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
+ DEBUG(0,("ldapsam_getsampwnam: init_sam_from_ldap failed!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by rid
+*********************************************************************/
+static BOOL ldapsam_getsampwrid(struct pdb_context *context, SAM_ACCOUNT * user, uint32 rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+ return False;
+
+ if (!ldapsam_connect_system(ldap_state, ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldapsam_search_one_user_by_rid(ldap_state, ldap_struct, rid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this rid [%i] count=%d\n", rid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ if (!init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
+ DEBUG(0,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+Delete entry from LDAP for username
+*********************************************************************/
+static BOOL ldapsam_delete_sam_account(struct pdb_context *context, const SAM_ACCOUNT * sam_acct)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ const char *sname;
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *entry;
+ LDAPMessage *result;
+
+ if (!sam_acct) {
+ DEBUG(0, ("sam_acct was NULL!\n"));
+ return False;
+ }
+
+ sname = pdb_get_username(sam_acct);
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+ return False;
+
+ DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
+
+ if (!ldapsam_connect_system(ldap_state, ldap_struct)) {
+ ldap_unbind (ldap_struct);
+ DEBUG(0, ("Failed to delete user %s from LDAP.\n", sname));
+ return False;
+ }
+
+ rc = ldapsam_search_one_user_by_name(ldap_state, ldap_struct, sname, &result);
+ if (ldap_count_entries (ldap_struct, result) == 0) {
+ DEBUG (0, ("User doesn't exit!\n"));
+ ldap_msgfree (result);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry (ldap_struct, result);
+ dn = ldap_get_dn (ldap_struct, entry);
+
+ rc = ldap_delete_s (ldap_struct, dn);
+
+ ldap_memfree (dn);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error;
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG (0,("failed to delete user with uid = %s with: %s\n\t%s\n",
+ sname, ldap_err2string (rc), ld_error));
+ free (ld_error);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ DEBUG (2,("successfully deleted uid = %s from the LDAP database\n", sname));
+ ldap_unbind (ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Update SAM_ACCOUNT
+*********************************************************************/
+static BOOL ldapsam_update_sam_account(struct pdb_context *context, const SAM_ACCOUNT * newpwd)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ LDAPMod **mods;
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct)) /* open a connection to the server */
+ return False;
+
+ if (!ldapsam_connect_system(ldap_state, ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ rc = ldapsam_search_one_user_by_name(ldap_state, ldap_struct,
+ pdb_get_username(newpwd), &result);
+
+ if (ldap_count_entries(ldap_struct, result) == 0)
+ {
+ DEBUG(0, ("No user to modify!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (!init_ldap_from_sam(ldap_state, &mods, LDAP_MOD_REPLACE, newpwd)) {
+ DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry(ldap_struct, result);
+ dn = ldap_get_dn(ldap_struct, entry);
+
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+ ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,
+ ("failed to modify user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string(rc),
+ ld_error));
+ free(ld_error);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,
+ ("successfully modified uid = %s in the LDAP database\n",
+ pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Add SAM_ACCOUNT to LDAP
+*********************************************************************/
+static BOOL ldapsam_add_sam_account(struct pdb_context *context, const SAM_ACCOUNT * newpwd)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)context->pdb_selected->private_data;
+ int rc;
+ pstring filter;
+ LDAP *ldap_struct = NULL;
+ LDAPMessage *result = NULL;
+ pstring dn;
+ LDAPMod **mods = NULL;
+ int ldap_op;
+ uint32 num_result;
+
+ const char *username = pdb_get_username(newpwd);
+ if (!username || !*username) {
+ DEBUG(0, ("Cannot add user without a username!\n"));
+ return False;
+ }
+
+ if (!ldapsam_open_connection(ldap_state, &ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldapsam_connect_system(ldap_state, ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ rc = ldapsam_search_one_user_by_name (ldap_state, ldap_struct, username, &result);
+
+ if (ldap_count_entries(ldap_struct, result) != 0)
+ {
+ DEBUG(0,("User already in the base, with samba properties\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_msgfree(result);
+
+ slprintf (filter, sizeof (filter) - 1, "uid=%s", username);
+ rc = ldapsam_search_one_user(ldap_state, ldap_struct, filter, &result);
+ num_result = ldap_count_entries(ldap_struct, result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
+ ldap_msgfree(result);
+ return False;
+ }
+
+ /* Check if we need to update an existing entry */
+ if (num_result == 1) {
+ char *tmp;
+ LDAPMessage *entry;
+
+ DEBUG(3,("User exists without samba properties: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (ldap_struct, result);
+ tmp = ldap_get_dn (ldap_struct, entry);
+ slprintf (dn, sizeof (dn) - 1, "%s", tmp);
+ ldap_memfree (tmp);
+ }
+ else {
+ /* Check if we need to add an entry */
+ DEBUG(3,("Adding new user\n"));
+ ldap_op = LDAP_MOD_ADD;
+ if (username[strlen(username)-1] == '$') {
+ slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
+ } else {
+ slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
+ }
+ }
+
+ ldap_msgfree(result);
+
+ if (!init_ldap_from_sam(ldap_state, &mods, ldap_op, newpwd)) {
+ DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
+
+ if (ldap_op == LDAP_MOD_REPLACE) {
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+ }
+ else {
+ rc = ldap_add_s(ldap_struct, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(0,("failed to modify/add user with uid = %s (dn = %s) with: %s\n\t%s\n",
+ pdb_get_username(newpwd), dn, ldap_err2string (rc), ld_error));
+ free(ld_error);
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+static void free_private_data(void **vp)
+{
+ struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+
+ if ((*ldap_state)->ldap_struct) {
+ ldap_unbind((*ldap_state)->ldap_struct);
+ }
+
+ *ldap_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam";
+
+ (*pdb_method)->setsampwent = ldapsam_setsampwent;
+ (*pdb_method)->endsampwent = ldapsam_endsampwent;
+ (*pdb_method)->getsampwent = ldapsam_getsampwent;
+ (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
+ (*pdb_method)->getsampwrid = ldapsam_getsampwrid;
+ (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
+ (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
+
+ /* TODO: Setup private data and free */
+
+ ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
+
+ if (!ldap_state) {
+ DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (location) {
+ ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
+ } else {
+ ldap_state->uri = "ldap://localhost";
+ }
+
+ (*pdb_method)->private_data = ldap_state;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state;
+ uint32 low_nua_uid, high_nua_uid;
+
+ if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam(pdb_context, pdb_method, location))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam_nua";
+
+ ldap_state = (*pdb_method)->private_data;
+
+ ldap_state->permit_non_unix_accounts = True;
+
+ if (!lp_non_unix_account_range(&low_nua_uid, &high_nua_uid)) {
+ DEBUG(0, ("cannot use ldapsam_nua without 'non unix account range' in smb.conf!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ldap_state->low_nua_rid=pdb_uid_to_user_rid(low_nua_uid);
+
+ ldap_state->high_nua_rid=pdb_uid_to_user_rid(high_nua_uid);
+
+ return NT_STATUS_OK;
+}
+
+
+#else
+
+NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ DEBUG(0, ("ldapsam not compiled in!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ DEBUG(0, ("ldapsam_nua not compiled in!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+#endif
diff --git a/source3/passdb/pdb_nisplus.c b/source3/passdb/pdb_nisplus.c
new file mode 100644
index 0000000000..145e1d4f0c
--- /dev/null
+++ b/source3/passdb/pdb_nisplus.c
@@ -0,0 +1,1428 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
+ * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
+ *
+ * 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"
+
+#ifdef WITH_NISPLUS_SAM
+
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
+
+#if defined(GROUP)
+#undef GROUP
+#endif
+
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
+
+#endif
+
+#include <rpcsvc/nis.h>
+
+extern int DEBUGLEVEL;
+
+struct nisp_enum_info
+{
+ nis_result *result;
+ int enum_entry;
+};
+
+static struct nisp_enum_info global_nisp_ent;
+static VOLATILE sig_atomic_t gotalarm;
+
+/***************************************************************
+
+ the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
+
+ name=S,nogw=r
+ uid=S,nogw=r
+ user_rid=S,nogw=r
+ smb_grpid=,nw+r
+ group_rid=,nw+r
+ acb=,nw+r
+
+ lmpwd=C,nw=,g=r,o=rm
+ ntpwd=C,nw=,g=r,o=rm
+
+ logon_t=,nw+r
+ logoff_t=,nw+r
+ kick_t=,nw+r
+ pwdlset_t=,nw+r
+ pwdlchg_t=,nw+r
+ pwdmchg_t=,nw+r
+
+ full_name=,nw+r
+ home_dir=,nw+r
+ dir_drive=,nw+r
+ logon_script=,nw+r
+ profile_path=,nw+r
+ acct_desc=,nw+r
+ workstations=,nw+r
+
+ hours=,nw+r
+
+****************************************************************/
+
+#define NPF_NAME 0
+#define NPF_UID 1
+#define NPF_USER_RID 2
+#define NPF_SMB_GRPID 3
+#define NPF_GROUP_RID 4
+#define NPF_ACB 5
+#define NPF_LMPWD 6
+#define NPF_NTPWD 7
+#define NPF_LOGON_T 8
+#define NPF_LOGOFF_T 9
+#define NPF_KICK_T 10
+#define NPF_PWDLSET_T 11
+#define NPF_PWDCCHG_T 12
+#define NPF_PWDMCHG_T 13
+#define NPF_FULL_NAME 14
+#define NPF_HOME_DIR 15
+#define NPF_DIR_DRIVE 16
+#define NPF_LOGON_SCRIPT 17
+#define NPF_PROFILE_PATH 18
+#define NPF_ACCT_DESC 19
+#define NPF_WORKSTATIONS 20
+#define NPF_HOURS 21
+
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+static uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+static uint32 pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ make_nisname_from_user_rid
+ ****************************************************************/
+static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_uid
+ ****************************************************************/
+static char *make_nisname_from_uid(int uid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_name
+ ****************************************************************/
+static char *make_nisname_from_name(const char *user_name, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
+ safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/*************************************************************************
+ gets a NIS+ attribute
+ *************************************************************************/
+static void get_single_attribute(const nis_object *new_obj, int col,
+ char *val, int len)
+{
+ int entry_len;
+
+ if (new_obj == NULL || val == NULL) return;
+
+ entry_len = ENTRY_LEN(new_obj, col);
+ if (len > entry_len)
+ {
+ len = entry_len;
+ }
+
+ safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ object.
+ ************************************************************************/
+static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, const nis_object *obj)
+{
+ char *ptr;
+ pstring full_name; /* this must be translated to dos code page */
+ pstring acct_desc; /* this must be translated to dos code page */
+ pstring home_dir; /* set default value from smb.conf for user */
+ pstring home_drive; /* set default value from smb.conf for user */
+ pstring logon_script; /* set default value from smb.conf for user */
+ pstring profile_path; /* set default value from smb.conf for user */
+ pstring hours;
+ int hours_len;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+
+ /*
+ * time values. note: this code assumes 32bit time_t!
+ */
+
+ /* Don't change these timestamp settings without a good reason. They are
+ important for NT member server compatibility. */
+
+ pdb_set_logon_time(pw_buf, (time_t)0, True);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGON_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16), True);
+ }
+ }
+
+ pdb_set_logoff_time(pw_buf, get_time_t_max(), True);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGOFF_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16), True);
+ }
+ }
+
+ pdb_set_kickoff_time(pw_buf, get_time_t_max(), True);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_KICK_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16), True);
+ }
+ }
+
+ pdb_set_pass_last_set_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDLSET_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_can_change_time(pw_buf, (time_t)0, True);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDCCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16), True);
+ }
+ }
+
+ pdb_set_pass_must_change_time(pw_buf, get_time_t_max(), True); /* Password never expires. */
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDMCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16), True);
+ }
+ }
+
+ /* string values */
+ pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
+ pdb_set_domain(pw_buf, lp_workgroup());
+ /* pdb_set_nt_username() -- cant set it here... */
+
+ get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
+#if 0
+ unix_to_dos(full_name, True);
+#endif
+ pdb_set_fullname(pw_buf, full_name);
+
+ pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
+ NPF_ACB)));
+
+ get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
+#if 0
+ unix_to_dos(acct_desc, True);
+#endif
+ pdb_set_acct_desc(pw_buf, acct_desc);
+
+ pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
+ pdb_set_munged_dial(pw_buf, NULL);
+
+ pdb_set_uid(pw_buf, atoi(ENTRY_VAL(obj, NPF_UID)));
+ pdb_set_gid(pw_buf, atoi(ENTRY_VAL(obj, NPF_SMB_GRPID)));
+ pdb_set_user_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_USER_RID)));
+ pdb_set_group_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_GROUP_RID)));
+
+ /* values, must exist for user */
+ if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
+
+ get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
+ if( !(home_dir && *home_dir) ) {
+ pstrcpy(home_dir, lp_logon_home());
+ pdb_set_homedir(pw_buf, home_dir, False);
+ }
+ else
+ pdb_set_homedir(pw_buf, home_dir, True);
+
+ get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
+ if( !(home_drive && *home_drive) ) {
+ pstrcpy(home_drive, lp_logon_drive());
+ pdb_set_dir_drive(pw_buf, home_drive, False);
+ }
+ else
+ pdb_set_dir_drive(pw_buf, home_drive, True);
+
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
+ sizeof(pstring));
+ if( !(logon_script && *logon_script) ) {
+ pstrcpy(logon_script, lp_logon_script());
+ }
+ else
+ pdb_set_logon_script(pw_buf, logon_script, True);
+
+ get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
+ if( !(profile_path && *profile_path) ) {
+ pstrcpy(profile_path, lp_logon_path());
+ pdb_set_profile_path(pw_buf, profile_path, False);
+ }
+ else
+ pdb_set_profile_path(pw_buf, profile_path, True);
+
+ }
+ else
+ {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS);
+ }
+
+ /* Check the lanman password column. */
+ ptr = (char *)ENTRY_VAL(obj, NPF_LMPWD);
+ if (!pdb_set_lanman_passwd(pw_buf, NULL))
+ return False;
+
+ if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
+ pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
+ } else {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
+ DEBUG(0, ("malformed LM pwd entry: %s.\n",
+ pdb_get_username(pw_buf)));
+ return False;
+ }
+ if (!pdb_set_lanman_passwd(pw_buf, smbpwd))
+ return False;
+ }
+
+ /* Check the NT password column. */
+ ptr = ENTRY_VAL(obj, NPF_NTPWD);
+ if (!pdb_set_nt_passwd(pw_buf, NULL))
+ return False;
+
+ if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
+ strncasecmp(ptr, "NO PASSWORD", 11)) {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
+ DEBUG(0, ("malformed NT pwd entry:\
+ uid = %d.\n",
+ pdb_get_uid(pw_buf)));
+ return False;
+ }
+ if (!pdb_set_nt_passwd(pw_buf, smbntpwd))
+ return False;
+ }
+
+ pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
+ pdb_set_logon_divs(pw_buf, 168); /* hours per week */
+
+ if( (hours_len = ENTRY_LEN(obj, NPF_HOURS)) == 21 ) {
+ memcpy(hours, ENTRY_VAL(obj, NPF_HOURS), hours_len);
+ } else {
+ hours_len = 21; /* 21 times 8 bits = 168 */
+ /* available at all hours */
+ memset(hours, 0xff, hours_len);
+ }
+ pdb_set_hours_len(pw_buf, hours_len);
+ pdb_set_hours(pw_buf, hours);
+
+ pdb_set_unknown_5(pw_buf, 0x00020000); /* don't know */
+ pdb_set_unknown_6(pw_buf, 0x000004ec); /* don't know */
+
+ return True;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisresult(SAM_ACCOUNT *pw_buf, const nis_result *result)
+{
+ if (pw_buf == NULL || result == NULL) return False;
+
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(0, ("NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("WARNING: Multiple entries for user in NIS+ table!\n"));
+ }
+
+ /* Grab the first hit. */
+ return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
+}
+
+/*************************************************************************
+ sets a NIS+ attribute
+ *************************************************************************/
+static void set_single_attribute(nis_object *new_obj, int col,
+ const char *val, int len, int flags)
+{
+ if (new_obj == NULL) return;
+
+ ENTRY_VAL(new_obj, col) = val;
+ ENTRY_LEN(new_obj, col) = len+1;
+
+ if (flags != 0)
+ {
+ new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
+ }
+}
+
+/***************************************************************
+ copy or modify nis object. this object is used to add or update
+ nisplus table entry.
+ ****************************************************************/
+static BOOL init_nisp_from_sam(nis_object *obj, const SAM_ACCOUNT *sampass,
+ nis_object *old)
+{
+ /*
+ * Fill nis_object for entry add or update.
+ * if we are updateing, we have to find out differences and set
+ * EN_MODIFIED flag. also set need_to_modify to trigger
+ * nis_modify_entry() call in pdb_update_sam_account().
+ *
+ * TODO:
+ * get data from SAM
+ * if (modify) get data from nis_object, compare and store if
+ * different + set EN_MODIFIED and need_to_modify
+ * else
+ * store
+ */
+ BOOL need_to_modify = False;
+ const char *name = pdb_get_username(sampass); /* from SAM */
+ /* these must be static or allocate and free entry columns! */
+ static fstring uid; /* from SAM */
+ static fstring user_rid; /* from SAM */
+ static fstring gid; /* from SAM */
+ static fstring group_rid; /* from SAM */
+ char *acb; /* from SAM */
+ static fstring smb_passwd; /* from SAM */
+ static fstring smb_nt_passwd; /* from SAM */
+ static fstring logon_t; /* from SAM */
+ static fstring logoff_t; /* from SAM */
+ static fstring kickoff_t; /* from SAM */
+ static fstring pwdlset_t; /* from SAM */
+ static fstring pwdlchg_t; /* from SAM */
+ static fstring pwdmchg_t; /* from SAM */
+ static fstring full_name; /* from SAM */
+ static fstring acct_desc; /* from SAM */
+ static char empty[1]; /* just an empty string */
+
+ slprintf(uid, sizeof(uid)-1, "%u", pdb_get_uid(sampass));
+ slprintf(user_rid, sizeof(user_rid)-1, "%u",
+ pdb_get_user_rid(sampass)? pdb_get_user_rid(sampass):
+ pdb_uid_to_user_rid(pdb_get_uid(sampass)));
+ slprintf(gid, sizeof(gid)-1, "%u", pdb_get_gid(sampass));
+
+ {
+ uint32 rid;
+ GROUP_MAP map;
+
+ rid=pdb_get_group_rid(sampass);
+
+ if (rid==0) {
+ if (get_group_map_from_gid(pdb_get_gid(sampass), &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ } else
+ rid=pdb_gid_to_group_rid(pdb_get_gid(sampass));
+ }
+
+ slprintf(group_rid, sizeof(group_rid)-1, "%u", rid);
+ }
+
+ acb = pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN);
+ pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ slprintf(logon_t, 13, "LNT-%08X",
+ (uint32)pdb_get_logon_time(sampass));
+ slprintf(logoff_t, 13, "LOT-%08X",
+ (uint32)pdb_get_logoff_time(sampass));
+ slprintf(kickoff_t, 13, "KOT-%08X",
+ (uint32)pdb_get_kickoff_time(sampass));
+ slprintf(pwdlset_t, 13, "LCT-%08X",
+ (uint32)pdb_get_pass_last_set_time(sampass));
+ slprintf(pwdlchg_t, 13, "CCT-%08X",
+ (uint32)pdb_get_pass_can_change_time(sampass));
+ slprintf(pwdmchg_t, 13, "MCT-%08X",
+ (uint32)pdb_get_pass_must_change_time(sampass));
+ safe_strcpy(full_name, pdb_get_fullname(sampass), sizeof(full_name)-1);
+ safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
+
+#if 0
+
+ /* Not sure what to do with these guys. -tpot */
+
+ dos_to_unix(full_name, True);
+ dos_to_unix(acct_desc, True);
+
+#endif
+
+ if( old ) {
+ /* name */
+ if(strcmp(ENTRY_VAL(old, NPF_NAME), name))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NAME, name, strlen(name),
+ EN_MODIFIED);
+ }
+
+
+ /* uid */
+ if(pdb_get_uid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_UID) || strcmp(ENTRY_VAL(old, NPF_UID), uid))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_UID, uid,
+ strlen(uid), EN_MODIFIED);
+ }
+ }
+
+ /* user_rid */
+ if (pdb_get_user_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_USER_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_USER_RID), user_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), EN_MODIFIED);
+ }
+ }
+
+ /* smb_grpid */
+ if (pdb_get_gid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_SMB_GRPID) ||
+ strcmp(ENTRY_VAL(old, NPF_SMB_GRPID), gid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_SMB_GRPID, gid,
+ strlen(gid), EN_MODIFIED);
+ }
+ }
+
+ /* group_rid */
+ if (pdb_get_group_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_GROUP_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_GROUP_RID), group_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), EN_MODIFIED);
+ }
+ }
+
+ /* acb */
+ if (!ENTRY_VAL(old, NPF_ACB) ||
+ strcmp(ENTRY_VAL(old, NPF_ACB), acb)) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), EN_MODIFIED);
+ }
+
+ /* lmpwd */
+ if(!ENTRY_VAL(old, NPF_LMPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_LMPWD), smb_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* ntpwd */
+ if(!ENTRY_VAL(old, NPF_NTPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_NTPWD), smb_nt_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* logon_t */
+ if( pdb_get_logon_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGON_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGON_T), logon_t ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), EN_MODIFIED);
+ }
+
+ /* logoff_t */
+ if( pdb_get_logoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGOFF_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGOFF_T), logoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), EN_MODIFIED);
+ }
+
+ /* kick_t */
+ if( pdb_get_kickoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_KICK_T) ||
+ strcmp(ENTRY_VAL(old, NPF_KICK_T), kickoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t), EN_MODIFIED);
+ }
+
+ /* pwdlset_t */
+ if( pdb_get_pass_last_set_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDLSET_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDLSET_T), pwdlset_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), EN_MODIFIED);
+ }
+
+ /* pwdlchg_t */
+ if( pdb_get_pass_can_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDCCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDCCHG_T), pwdlchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), EN_MODIFIED);
+ }
+
+ /* pwdmchg_t */
+ if( pdb_get_pass_must_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDMCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDMCHG_T), pwdmchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), EN_MODIFIED);
+ }
+
+ /* full_name */
+ /* must support set, unset and change */
+ if ( (pdb_get_fullname(sampass) &&
+ !ENTRY_VAL(old, NPF_FULL_NAME)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ !pdb_get_fullname(sampass)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ pdb_get_fullname(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_FULL_NAME), full_name ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_FULL_NAME, full_name,
+ strlen(full_name), EN_MODIFIED);
+ }
+
+ /* home_dir */
+ /* must support set, unset and change */
+ if( (pdb_get_homedir(sampass) &&
+ !ENTRY_VAL(old, NPF_HOME_DIR)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ !pdb_get_homedir(sampass)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ pdb_get_homedir(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_HOME_DIR),
+ pdb_get_homedir(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_HOME_DIR, pdb_get_homedir(sampass),
+ strlen(pdb_get_homedir(sampass)), EN_MODIFIED);
+ }
+
+ /* dir_drive */
+ /* must support set, unset and change */
+ if( (pdb_get_dirdrive(sampass) &&
+ !ENTRY_VAL(old, NPF_DIR_DRIVE)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ !pdb_get_dirdrive(sampass)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ pdb_get_dirdrive(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_DIR_DRIVE),
+ pdb_get_dirdrive(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_DIR_DRIVE, pdb_get_dirdrive(sampass),
+ strlen(pdb_get_dirdrive(sampass)), EN_MODIFIED);
+ }
+
+ /* logon_script */
+ /* must support set, unset and change */
+ if( (pdb_get_logon_script(sampass) &&
+ !ENTRY_VAL(old, NPF_LOGON_SCRIPT) ||
+ (ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ !pdb_get_logon_script(sampass)) ||
+ ( ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ pdb_get_logon_script(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_LOGON_SCRIPT),
+ pdb_get_logon_script(sampass))))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ pdb_get_logon_script(sampass),
+ strlen(pdb_get_logon_script(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* profile_path */
+ /* must support set, unset and change */
+ if( (pdb_get_profile_path(sampass) &&
+ !ENTRY_VAL(old, NPF_PROFILE_PATH)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ !pdb_get_profile_path(sampass)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ pdb_get_profile_path(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_PROFILE_PATH),
+ pdb_get_profile_path(sampass) ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ pdb_get_profile_path(sampass),
+ strlen(pdb_get_profile_path(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* acct_desc */
+ /* must support set, unset and change */
+ if( (pdb_get_acct_desc(sampass) &&
+ !ENTRY_VAL(old, NPF_ACCT_DESC)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ !pdb_get_acct_desc(sampass)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ pdb_get_acct_desc(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_ACCT_DESC), acct_desc ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACCT_DESC, acct_desc,
+ strlen(acct_desc), EN_MODIFIED);
+ }
+
+ /* workstations */
+ /* must support set, unset and change */
+ if ( (pdb_get_workstations(sampass) &&
+ !ENTRY_VAL(old, NPF_WORKSTATIONS) ) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ !pdb_get_workstations(sampass)) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ pdb_get_workstations(sampass)) &&
+ strcmp( ENTRY_VAL(old, NPF_WORKSTATIONS),
+ pdb_get_workstations(sampass))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ pdb_get_workstations(sampass),
+ strlen(pdb_get_workstations(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* hours */
+ if ((pdb_get_hours_len(sampass) != ENTRY_LEN(old, NPF_HOURS)) ||
+ memcmp(pdb_get_hours(sampass), ENTRY_VAL(old, NPF_HOURS),
+ ENTRY_LEN(old, NPF_HOURS))) {
+ need_to_modify = True;
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS, pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, EN_MODIFIED);
+ }
+ } else {
+ const char *homedir, *dirdrive, *logon_script, *profile_path, *workstations;
+
+ *empty = '\0'; /* empty string */
+
+ set_single_attribute(obj, NPF_NAME, name, strlen(name), 0);
+ set_single_attribute(obj, NPF_UID, uid, strlen(uid), 0);
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), 0);
+ set_single_attribute(obj, NPF_SMB_GRPID, gid, strlen(gid), 0);
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), 0);
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), 0);
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), 0);
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t),0);
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), 0);
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), 0);
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), 0);
+ set_single_attribute(obj, NPF_FULL_NAME ,
+ full_name, strlen(full_name), 0);
+
+ if(!(homedir = pdb_get_homedir(sampass)))
+ homedir = empty;
+
+ set_single_attribute(obj, NPF_HOME_DIR,
+ homedir, strlen(homedir), 0);
+
+ if(!(dirdrive = pdb_get_dirdrive(sampass)))
+ dirdrive = empty;
+
+ set_single_attribute(obj, NPF_DIR_DRIVE,
+ dirdrive, strlen(dirdrive), 0);
+
+ if(!(logon_script = pdb_get_logon_script(sampass)))
+ logon_script = empty;
+
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ logon_script, strlen(logon_script), 0);
+
+ if(!(profile_path = pdb_get_profile_path(sampass)))
+ profile_path = empty;
+
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ profile_path, strlen(profile_path), 0);
+
+ set_single_attribute(obj, NPF_ACCT_DESC,
+ acct_desc, strlen(acct_desc), 0);
+
+ if(!(workstations = pdb_get_workstations(sampass)))
+ workstations = empty;
+
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ workstations, strlen(workstations), 0);
+
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS,
+ pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, 0);
+ }
+
+ return need_to_modify;
+}
+
+/***************************************************************
+ calls nis_list, returns results.
+ ****************************************************************/
+static nis_result *nisp_get_nis_list(const char *nis_name, unsigned int flags)
+{
+ nis_result *result;
+ int i;
+
+ if( ! flags)
+ flags = FOLLOW_LINKS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP;
+
+ for(i = 0; i<2;i++ ) {
+ alarm(60); /* hopefully ok for long searches */
+ result = nis_list(nis_name, flags,NULL,NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+ if( !(flags & MASTER_ONLY) && NIS_RES_NUMOBJ(result) <= 0 ) {
+ /* nis replicas are not in sync perhaps?
+ * this can happen, if account was just added.
+ */
+ DEBUG(10,("will try master only\n"));
+ nis_freeresult(result);
+ flags |= MASTER_ONLY;
+ } else
+ break;
+ }
+ return result;
+}
+
+/***************************************************************
+ Start to enumerate the nisplus passwd list.
+ ****************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ char *sp, * p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ pdb_endsampwent(); /* just in case */
+ global_nisp_ent.result = nisp_get_nis_list( pfiletmp, 0 );
+ global_nisp_ent.enum_entry = 0;
+ return global_nisp_ent.result != NULL ? True : False;
+}
+
+/***************************************************************
+ End enumeration of the nisplus passwd list.
+****************************************************************/
+void pdb_endsampwent(void)
+{
+ if( global_nisp_ent.result )
+ nis_freeresult(global_nisp_ent.result);
+ global_nisp_ent.result = NULL;
+ global_nisp_ent.enum_entry = 0;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+ *************************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ int enum_entry = (int)(global_nisp_ent.enum_entry);
+ nis_result *result = global_nisp_ent.result;
+
+ if (user==NULL) {
+ DEBUG(0,("SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ if (result == NULL ||
+ enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ(result) - 1))
+ {
+ return False;
+ }
+
+ if(!make_sam_from_nisp_object(user, &NIS_RES_OBJECT(result)[enum_entry]) )
+ {
+ DEBUG(0,("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
+ return False;
+ }
+ (int)(global_nisp_ent.enum_entry)++;
+ return True;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
+{
+ /* Static buffers we will return. */
+ nis_result *result = NULL;
+ pstring nisname;
+ BOOL ret;
+ char *pfile = lp_smb_passwd_file();
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+ DEBUG(10, ("search by nisname: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+ char *sp, *p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if (!*p)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ nisname = make_nisname_from_user_rid(rid, pfiletmp);
+
+ DEBUG(10, ("search by rid: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to remove entry from the nisplus smbpasswd table
+ *************************************************************************/
+BOOL pdb_delete_sam_account(SAM_ACCOUNT * user)
+{
+ const char *sname;
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ nis_result *result, *delresult;
+ nis_object *obj;
+ int i;
+
+ if (!user) {
+ DEBUG(0, ("no SAM_ACCOUNT specified!\n"));
+ return False;
+ }
+
+ sname = pdb_get_username(user);
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s", sname, obj->zo_name,
+ obj->zo_domain);
+
+ DEBUG(10, ("removing name: %s\n", nisname));
+ delresult = nis_remove_entry(nisname, obj,
+ MASTER_ONLY|REM_MULTIPLE|ALL_RESULTS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+
+ nis_freeresult(result);
+
+ if(delresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(delresult->status)));
+ nis_freeresult(delresult);
+ return False;
+ }
+ nis_freeresult(delresult);
+ return True;
+}
+
+/************************************************************************
+ Routine to add an entry to the nisplus passwd file.
+*************************************************************************/
+BOOL pdb_add_sam_account(SAM_ACCOUNT * newpwd)
+{
+ int local_user = 0;
+ char *pfile;
+ pstring pfiletmp;
+ char *nisname;
+ nis_result *result = NULL,
+ *tblresult = NULL;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+
+ /*
+ * 1. find user domain.
+ * a. try nis search in passwd.org_dir - if found use domain from result.
+ * b. try getpwnam. this may be needed if user is defined
+ * in /etc/passwd file (or elsewere) and not in passwd.org_dir.
+ * if found, use host default domain.
+ * c. exit with False - no such user.
+ *
+ * 2. add user
+ * a. find smbpasswd table
+ * search pfile in user domain if not found, try host default
+ * domain.
+ * b. smbpasswd domain is found, fill data and add entry.
+ *
+ * pfile should contain ONLY table name, org_dir will be concated.
+ * so, at first we will clear path prefix from pfile, and
+ * then we will use pfiletmp as playground to put together full
+ * nisname string.
+ * such approach will make it possible to specify samba private dir
+ * AND still use NIS+ table. as all domain related data is normally
+ * stored in org_dir.DOMAIN, this should be ok do do.
+ */
+
+ pfile = lp_smb_passwd_file();
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ /*
+ * Check if user is already there.
+ */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ if(pdb_get_username(newpwd) != NULL) {
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ pfiletmp);
+ } else {
+ return False;
+ }
+
+ if(!(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+ if (result->status != NIS_SUCCESS &&
+ result->status != NIS_NOTFOUND) {
+ DEBUG(3, ( "nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
+ {
+ DEBUG(3, ("User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(result); /* no such user, free results */
+
+ /*
+ * check for user in unix password database. we need this to get
+ * domain, where smbpasswd entry should be stored.
+ */
+
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ "passwd.org_dir");
+
+ result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP);
+
+ if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0)
+ {
+ struct passwd *passwd;
+ DEBUG(3, ("nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+
+ if (!(passwd = getpwnam_alloc(pdb_get_username(newpwd)))) {
+ /* no such user in system! */
+ return False;
+ }
+ passwd_free(&passwd);
+
+ /*
+ * user is defined, but not in passwd.org_dir.
+ */
+ local_user = 1;
+ } else {
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(result)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ nis_freeresult(result); /* not needed any more */
+
+ tblresult = nisp_get_nis_list(pfiletmp,
+ MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ }
+
+ if (local_user || tblresult->status != NIS_SUCCESS)
+ {
+ /*
+ * no user domain or
+ * smbpasswd table not found in user domain, fallback to
+ * default domain.
+ */
+ if (!local_user) /* free previous failed search result */
+ nis_freeresult(tblresult);
+
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ tblresult = nis_lookup(pfiletmp, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ /* still nothing. bail out */
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "nis_lookup failure: %s\n",
+ nis_sperrno(tblresult->status)));
+ return False;
+ }
+ /* we need full name for nis_add_entry() */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(tblresult)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ }
+
+ memset((char *)&new_obj, 0, sizeof (new_obj));
+ /* fill entry headers */
+ /* we do not free these. */
+ new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
+ new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
+ new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
+ new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
+ /* uints */
+ new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
+ new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
+
+ new_obj.zo_data.zo_type = ENTRY_OBJ;
+ new_obj.EN_data.en_type =
+ NIS_RES_OBJECT(tblresult)->TA_data.ta_type;
+
+ ta_maxcol = NIS_RES_OBJECT(tblresult)->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(tblresult);
+ return False;
+ }
+
+ memset((char *)ecol, 0, ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ init_nisp_from_sam(&new_obj, newpwd, NULL);
+
+ DEBUG(10, ( "add NIS+ entry: %s\n", nisname));
+ result = nis_add_entry(pfiletmp, &new_obj, 0);
+
+ free(ecol); /* free allocated entry space */
+
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to modify the nisplus passwd entry.
+************************************************************************/
+BOOL pdb_update_sam_account(SAM_ACCOUNT * newpwd)
+{
+ nis_result *result, *addresult;
+ nis_object *obj;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir",
+ pdb_get_username(newpwd), pfile);
+
+ DEBUG(10, ("search by name: %s\n", nisname));
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ DEBUG(6,("entry found in %s\n", obj->zo_domain));
+
+ /* we must create new stub object with EN_MODIFIED flag.
+ this is because obj from result is going to be freed and
+ we do not want to break it or cause memory leaks or corruption.
+ */
+
+ memmove((char *)&new_obj, obj, sizeof (new_obj));
+ ta_maxcol = obj->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ memmove((char *)ecol, obj->EN_data.en_cols.en_cols_val,
+ ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ if ( init_nisp_from_sam(&new_obj, newpwd, obj) == True ) {
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s",
+ pdb_get_username(newpwd), pfile, obj->zo_domain);
+
+ DEBUG(10, ("NIS+ table update: %s\n", nisname));
+ addresult =
+ nis_modify_entry(nisname, &new_obj,
+ MOD_SAMEOBJ | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ if(addresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ free(ecol);
+ return False;
+ }
+
+ DEBUG(6,("password changed\n"));
+ nis_freeresult(addresult);
+ } else {
+ DEBUG(6,("nothing to change!\n"));
+ }
+
+ free(ecol);
+ nis_freeresult(result);
+
+ return True;
+}
+
+#else
+ void nisplus_dummy_function(void);
+ void nisplus_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_NISPLUSSAM */
diff --git a/source3/passdb/pdb_plugin.c b/source3/passdb/pdb_plugin.c
new file mode 100644
index 0000000000..1de61abd5f
--- /dev/null
+++ b/source3/passdb/pdb_plugin.c
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ Loadable passdb module interface.
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Andrew Bartlett 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"
+
+NTSTATUS pdb_init_plugin(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ void * dl_handle;
+ char *plugin_location, *plugin_name, *p;
+ pdb_init_function plugin_init;
+
+ if (location == NULL) {
+ DEBUG(0, ("The plugin module needs an argument!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ plugin_name = smb_xstrdup(location);
+ p = strchr(plugin_name, ':');
+ if (p) {
+ *p = 0;
+ plugin_location = p+1;
+ trim_string(plugin_location, " ", " ");
+ } else plugin_location = NULL;
+ trim_string(plugin_name, " ", " ");
+
+ DEBUG(5, ("Trying to load sam plugin %s\n", plugin_name));
+ dl_handle = sys_dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL );
+ if (!dl_handle) {
+ DEBUG(0, ("Failed to load sam plugin %s using sys_dlopen (%s)\n", plugin_name, sys_dlerror()));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ plugin_init = sys_dlsym(dl_handle, "pdb_init");
+ if (!plugin_init){
+ DEBUG(0, ("Failed to find function 'pdb_init' using sys_dlsym in sam plugin %s (%s)\n", plugin_name, sys_dlerror()));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("Starting sam plugin %s with location %s\n", plugin_name, plugin_location));
+ return plugin_init(pdb_context, pdb_method, plugin_location);
+}
diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c
new file mode 100644
index 0000000000..89a4217c3b
--- /dev/null
+++ b/source3/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1660 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001
+ * Modified by Andrew Bartlett 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"
+
+
+/*
+ smb_passwd is analogous to sam_passwd used everywhere
+ else. However, smb_passwd is limited to the information
+ stored by an smbpasswd entry
+ */
+
+struct smb_passwd
+{
+ BOOL smb_userid_set; /* this is actually the unix uid_t */
+ uint32 smb_userid; /* this is actually the unix uid_t */
+ const char *smb_name; /* username string */
+
+ const unsigned char *smb_passwd; /* Null if no password */
+ const unsigned char *smb_nt_passwd; /* Null if no password */
+
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ time_t pass_last_set_time; /* password last set time */
+};
+
+struct smbpasswd_privates
+{
+ /* used for maintain locks on the smbpasswd file */
+ int pw_file_lock_depth;
+
+ /* Global File pointer */
+ FILE *pw_file;
+
+ /* formerly static variables */
+ struct smb_passwd pw_buf;
+ pstring user_name;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+ /* retrive-once info */
+ const char *smbpasswd_file;
+
+ BOOL permit_non_unix_accounts;
+
+ uint32 low_nua_userid;
+ uint32 high_nua_userid;
+
+};
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+static uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+static uint32 pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ if(*plock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ (*plock_depth)++;
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_unlock(int fd, int *plock_depth)
+{
+ BOOL ret=True;
+
+ if(*plock_depth == 1)
+ ret = do_file_lock(fd, 5, F_UNLCK);
+
+ if (*plock_depth > 0)
+ (*plock_depth)--;
+
+ if(!ret)
+ DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+
+/**************************************************************
+ Intialize a smb_passwd struct
+ *************************************************************/
+
+static void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL)
+ return;
+ ZERO_STRUCTP (user);
+
+ user->pass_last_set_time = (time_t)0;
+}
+
+/***************************************************************
+ Internal fn to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module. Checks for atomic
+ rename of smbpasswd file on update or create once the lock has
+ been granted to prevent race conditions. JRA.
+****************************************************************/
+
+static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
+{
+ FILE *fp = NULL;
+ const char *open_mode = NULL;
+ int race_loop = 0;
+ int lock_type = F_RDLCK;
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+
+ switch(type) {
+ case PWF_READ:
+ open_mode = "rb";
+ lock_type = F_RDLCK;
+ break;
+ case PWF_UPDATE:
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ case PWF_CREATE:
+ /*
+ * Ensure atomic file creation.
+ */
+ {
+ int i, fd = -1;
+
+ for(i = 0; i < 5; i++) {
+ if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
+ break;
+ sys_usleep(200); /* Spin, spin... */
+ }
+ if(fd == -1) {
+ DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
+ return NULL;
+ }
+ close(fd);
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ }
+ }
+
+ for(race_loop = 0; race_loop < 5; race_loop++) {
+ DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+ if((fp = sys_fopen(pfile, open_mode)) == NULL) {
+ DEBUG(2, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
+ return NULL;
+ }
+
+ if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
+ fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Only check for replacement races on update or create.
+ * For read we don't mind if the data is one record out of date.
+ */
+
+ if(type == PWF_READ) {
+ break;
+ } else {
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ /*
+ * Avoid the potential race condition between the open and the lock
+ * by doing a stat on the filename and an fstat on the fd. If the
+ * two inodes differ then someone did a rename between the open and
+ * the lock. Back off and try the open again. Only do this 5 times to
+ * prevent infinate loops. JRA.
+ */
+
+ if (sys_stat(pfile,&sbuf1) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (sys_fstat(fileno(fp),&sbuf2) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if( sbuf1.st_ino == sbuf2.st_ino) {
+ /* No race. */
+ break;
+ }
+
+ /*
+ * Race occurred - back off and try again...
+ */
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ }
+ }
+
+ if(race_loop == 5) {
+ DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+ /* Make sure it is only rw by the owner */
+ if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+ DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
+Error was %s\n.", pfile, strerror(errno) ));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* We have a lock on the file. */
+ return fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+static void endsmbfilepwent(FILE *fp, int *lock_depth)
+{
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+
+static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
+{
+ /* Static buffers we will return. */
+ struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
+ char *user_name = smbpasswd_state->user_name;
+ unsigned char *smbpwd = smbpasswd_state->smbpwd;
+ unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
+ char linebuf[256];
+ unsigned char c;
+ unsigned char *p;
+ long uidval;
+ size_t linebuf_len;
+
+ if(fp == NULL) {
+ DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pdb_init_smb(pw_buf);
+
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, 256, fp);
+ if (ferror(fp)) {
+ return NULL;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ if ((linebuf_len = strlen(linebuf)) == 0)
+ continue;
+
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n')
+ break;
+ }
+ } else
+ linebuf[linebuf_len - 1] = '\0';
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+ break;
+ }
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ * [Account type] is an ascii encoding of the type of account.
+ * LCT-(8 hex digits) is the time_t value of the last change time.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+ continue;
+ }
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+ continue;
+ }
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+
+ p++; /* Go past ':' */
+
+ if(*p == '-') {
+ DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
+ continue;
+ }
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
+ continue;
+ }
+
+ uidval = atoi((char *) p);
+
+ while (*p && isdigit(*p))
+ p++;
+
+ if (*p != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
+ continue;
+ }
+
+ pw_buf->smb_name = user_name;
+ pw_buf->smb_userid = uidval;
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+
+ /* Skip the ':' */
+ p++;
+
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
+ pw_buf->smb_nt_passwd = NULL;
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_DISABLED;
+ return pw_buf;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
+ continue;
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
+ continue;
+ }
+
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (!pdb_gethexpwd((char *)p, smbpwd)) {
+ DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
+ continue;
+ }
+ pw_buf->smb_passwd = smbpwd;
+ }
+
+ /*
+ * Now check if the NT compatible password is
+ * available.
+ */
+ pw_buf->smb_nt_passwd = NULL;
+
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if(pdb_gethexpwd((char *)p,smbntpwd))
+ pw_buf->smb_nt_passwd = smbntpwd;
+ }
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+ }
+
+ DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+ user_name, uidval));
+
+ if (*p == '[')
+ {
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+ pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+ /* Must have some account type set. */
+ if(pw_buf->acct_ctrl == 0)
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ /* Now try and get the last change time. */
+ if(end_p)
+ p = end_p + 1;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
+ pw_buf->acct_ctrl &= ~ACB_NORMAL;
+ pw_buf->acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ return pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Create a new smbpasswd entry - malloced space returned.
+*************************************************************************/
+
+static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
+{
+ int new_entry_length;
+ char *new_entry;
+ char *p;
+ int i;
+
+ new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
+
+ if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
+ DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
+ return NULL;
+ }
+
+ slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
+ p = &new_entry[strlen(new_entry)];
+
+ if(newpwd->smb_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
+ }
+ } else {
+ i=0;
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ if(newpwd->smb_nt_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ /* Add the account encoding and the last change time. */
+ slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
+ pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)newpwd->pass_last_set_time);
+
+ return new_entry;
+}
+
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, struct smb_passwd *newpwd)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ int wr_len;
+ int fd;
+ size_t new_entry_length;
+ char *new_entry;
+ SMB_OFF_T offpos;
+ uint32 max_found_uid = 0;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &(smbpasswd_state->pw_file_lock_depth));
+ }
+
+ if (fp == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL)
+ {
+ if (strequal(newpwd->smb_name, pwd->smb_name))
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ }
+
+ /* Look for a free uid for use in non-unix accounts */
+ if (pwd->smb_userid > max_found_uid) {
+ max_found_uid = pwd->smb_userid;
+ }
+ }
+
+ /* Ok - entry doesn't exist. We can add it */
+
+ /* Account not in /etc/passwd hack!!! */
+ if (!newpwd->smb_userid_set) {
+ if (!smbpasswd_state->permit_non_unix_accounts) {
+ DEBUG(0, ("add_smbfilepwd_entry: cannot add account %s without unix identity\n", newpwd->smb_name));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ }
+
+ if (max_found_uid < smbpasswd_state->low_nua_userid) {
+ newpwd->smb_userid = smbpasswd_state->low_nua_userid;
+ newpwd->smb_userid_set = True;
+ } else if (max_found_uid >= smbpasswd_state->high_nua_userid) {
+ DEBUG(0, ("add_smbfilepwd_entry: cannot add machine %s, no uids are free! \n", newpwd->smb_name));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ } else {
+ newpwd->smb_userid = max_found_uid + 1;
+ newpwd->smb_userid_set = True;
+ }
+ }
+
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ /*
+ * The add user write needs to be atomic - so get the fd from
+ * the fp and do a raw write() call.
+ */
+ fd = fileno(fp);
+
+ if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ }
+
+ if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
+ fd, new_entry_length, new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
+Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
+
+ /* Remove the entry we just wrote. */
+ if(sys_ftruncate(fd, offpos) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ newpwd->smb_name, strerror(errno)));
+ }
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return True;
+}
+
+/************************************************************************
+ Routine to search the smbpasswd file for an entry matching the username.
+ and then modify its password entry. We can't use the startsmbpwent()/
+ getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+************************************************************************/
+
+static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
+{
+ /* Static buffers we will return. */
+ char * user_name = smbpasswd_state->user_name;
+
+ char linebuf[256];
+ char readbuf[1024];
+ unsigned char c;
+ fstring ascii_p16;
+ fstring encode_bits;
+ unsigned char *p = NULL;
+ size_t linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ BOOL found_entry = False;
+ BOOL got_pass_last_set_time = False;
+
+ SMB_OFF_T pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile) {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, "r+");
+
+ if (fp == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ lockfd = fileno(fp);
+
+ if (!pw_file_lock(lockfd, F_WRLCK, 5, &(smbpasswd_state->pw_file_lock_depth))) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ pwd_seekpos = sys_ftell(fp);
+
+ linebuf[0] = '\0';
+
+ fgets(linebuf, sizeof(linebuf), fp);
+ if (ferror(fp)) {
+ pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+
+ if (p == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name)) {
+ found_entry = True;
+ break;
+ }
+ }
+
+ if (!found_entry) {
+ pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
+ pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ while (*p && isdigit(*p))
+ p++;
+ if (*p != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
+ pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+ p++;
+
+ /* Record exact password position */
+ pwd_seekpos += PTR_DIFF(p, linebuf);
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ /* Now check if the NT compatible password is
+ available. */
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+
+ if (*p == '[') {
+
+ i = 0;
+ encode_bits[i++] = *p++;
+ while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
+ encode_bits[i++] = *p++;
+
+ encode_bits[i++] = ']';
+ encode_bits[i++] = '\0';
+
+ if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ } else {
+ DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format. This is no longer supported.!\n"));
+ DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
+ return False;
+ }
+
+ /* Go past the ']' */
+ if(linebuf_len > PTR_DIFF(p, linebuf))
+ p++;
+
+ if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+ p++;
+
+ /* We should be pointing at the LCT entry. */
+ if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
+
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* *p && StrnCaseCmp() */
+ } /* p == ':' */
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+ /* Create the 32 byte representation of the new p16 */
+ if(pwd->smb_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ wr_len = 66;
+ if (pwd->smb_nt_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ ascii_p16[65] = ':';
+ ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+ /* Add on the account info bits and the time of last
+ password change. */
+
+ if(got_pass_last_set_time) {
+ slprintf(&ascii_p16[strlen(ascii_p16)],
+ sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+ "%s:LCT-%08X:",
+ encode_bits, (uint32)pwd->pass_last_set_time );
+ wr_len = strlen(ascii_p16);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbfilepwd_entry: "));
+ dump_data(100, ascii_p16, wr_len);
+#endif
+
+ if(wr_len > sizeof(linebuf)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return (False);
+ }
+
+ /*
+ * Do an atomic write into the file at the position defined by
+ * seekpos.
+ */
+
+ /* The mod user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+
+ fd = fileno(fp);
+
+ if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ /* Sanity check - ensure the areas we are writing are framed by ':' */
+ if (read(fd, linebuf, wr_len+1) != wr_len+1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
+ DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ if (write(fd, ascii_p16, wr_len) != wr_len) {
+ DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ pstring pfile2;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ FILE *fp_write = NULL;
+ int pfile2_lockdepth = 0;
+
+ slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
+
+ /*
+ * Open the smbpassword file - for update. It needs to be update
+ * as we need any other processes to wait until we have replaced
+ * it.
+ */
+
+ if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth))) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ return False;
+ }
+
+ /*
+ * Create the replacement password file.
+ */
+ if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ char *new_entry;
+ size_t new_entry_length;
+
+ if (strequal(name, pwd->smb_name)) {
+ DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
+ continue;
+ }
+
+ /*
+ * We need to copy the entry out into the second file.
+ */
+
+ if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+ if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ }
+
+ /*
+ * Ensure pfile2 is flushed before rename.
+ */
+
+ if(fflush(fp_write) != 0)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return False;
+ }
+
+ /*
+ * Do an atomic rename - then release the locks.
+ */
+
+ if(rename(pfile2,pfile) != 0) {
+ unlink(pfile2);
+ }
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return True;
+}
+
+/*********************************************************************
+ Create a smb_passwd struct from a SAM_ACCOUNT.
+ We will not allocate any new memory. The smb_passwd struct
+ should only stay around as long as the SAM_ACCOUNT does.
+ ********************************************************************/
+static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
+{
+ uid_t uid;
+
+ if (sampass == NULL)
+ return False;
+
+ ZERO_STRUCTP(smb_pw);
+
+ if (!IS_SAM_UNIX_USER(sampass)) {
+ smb_pw->smb_userid_set = False;
+ DEBUG(5,("build_sam_pass: storing user without a UNIX uid or gid. \n"));
+ } else {
+ uint32 rid = pdb_get_user_rid(sampass);
+ smb_pw->smb_userid_set = True;
+ uid = pdb_get_uid(sampass);
+
+ /* If the user specified a RID, make sure its able to be both stored and retreived */
+ if (rid && uid != pdb_user_rid_to_uid(rid)) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
+ return False;
+ }
+
+ smb_pw->smb_userid=uid;
+ }
+
+ smb_pw->smb_name=(const char*)pdb_get_username(sampass);
+
+ smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
+ smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
+
+ smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
+ smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
+
+#if 0
+ /*
+ * ifdef'out by JFM on 11/29/2001.
+ * this assertion is no longer valid
+ * and I don't understand the goal
+ * and doing the same thing with the group mapping code
+ * is hairy !
+ *
+ * We just have the RID, in which SID is it valid ?
+ * our domain SID ? well known SID ? local SID ?
+ */
+
+ if (gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
+ DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
+ return False;
+ }
+#endif
+
+ return True;
+}
+
+/*********************************************************************
+ Create a SAM_ACCOUNT from a smb_passwd struct
+ ********************************************************************/
+static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
+{
+ struct passwd *pwfile;
+
+ if (sam_pass==NULL) {
+ DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
+ return False;
+ }
+
+ if ((smbpasswd_state->permit_non_unix_accounts)
+ && (pw_buf->smb_userid >= smbpasswd_state->low_nua_userid)
+ && (pw_buf->smb_userid <= smbpasswd_state->high_nua_userid)) {
+
+ pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pw_buf->smb_userid));
+
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here.
+
+ This was down the bottom for machines, but it looks pretty good as
+ a general default for non-unix users. --abartlet 2002-01-08
+ */
+ pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS);
+
+ } else {
+
+ uint32 grid;
+ GROUP_MAP map;
+
+ /* Verify in system password file...
+ FIXME!!! This is where we should look up an internal
+ mapping of allocated uid for machine accounts as well
+ --jerry */
+ pwfile = getpwnam_alloc(pw_buf->smb_name);
+ if (pwfile == NULL) {
+ DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s not in unix passwd database!\n", pw_buf->smb_name));
+ return False;
+ }
+
+ pdb_set_uid (sam_pass, pwfile->pw_uid);
+ pdb_set_gid (sam_pass, pwfile->pw_gid);
+
+ pdb_set_fullname(sam_pass, pwfile->pw_gecos);
+
+ pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
+
+ if (get_group_map_from_gid(pwfile->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &grid);
+ } else {
+ grid=pdb_gid_to_group_rid(pwfile->pw_gid);
+ }
+
+ pdb_set_group_rid(sam_pass, grid);
+
+ /* check if this is a user account or a machine account */
+ if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$')
+ {
+ pstring str;
+
+ pstrcpy(str, lp_logon_path());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_profile_path(sam_pass, str, False);
+
+ pstrcpy(str, lp_logon_home());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_homedir(sam_pass, str, False);
+
+ pstrcpy(str, lp_logon_drive());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_dir_drive(sam_pass, str, False);
+
+ pstrcpy(str, lp_logon_script());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_logon_script(sam_pass, str, False);
+
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ /*pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS); */
+ }
+
+ passwd_free(&pwfile);
+ }
+
+ pdb_set_username (sam_pass, pw_buf->smb_name);
+ pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
+ pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
+ pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
+ pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
+ pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, True);
+ pdb_set_domain (sam_pass, lp_workgroup());
+
+ pdb_set_dir_drive (sam_pass, lp_logon_drive(), False);
+
+#if 0 /* JERRY */
+ /* the smbpasswd format doesn't have a must change time field, so
+ we can't get this right. The best we can do is to set this to
+ some time in the future. 21 days seems as reasonable as any other value :)
+ */
+ pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
+#endif
+ return True;
+}
+
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+static BOOL smbpasswd_setsampwent (struct pdb_context *context, BOOL update)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+
+ smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
+ update ? PWF_UPDATE : PWF_READ,
+ &(smbpasswd_state->pw_file_lock_depth));
+
+ /* did we fail? Should we try to create it? */
+ if (!smbpasswd_state->pw_file && update && errno == ENOENT)
+ {
+ FILE *fp;
+ /* slprintf(msg_str,msg_str_len-1,
+ "smbpasswd file did not exist - attempting to create it.\n"); */
+ DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
+ fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w");
+ if (fp)
+ {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ }
+
+ smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
+ update ? PWF_UPDATE : PWF_READ,
+ &(smbpasswd_state->pw_file_lock_depth));
+ }
+
+ return (smbpasswd_state->pw_file != NULL);
+}
+
+static void smbpasswd_endsampwent (struct pdb_context *context)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth));
+}
+
+/*****************************************************************
+ ****************************************************************/
+static BOOL smbpasswd_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ struct smb_passwd *pw_buf=NULL;
+ BOOL done = False;
+ DEBUG(5,("pdb_getsampwent\n"));
+
+ if (user==NULL) {
+ DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to getsampwent (smbpasswd)\n");
+#endif
+ return False;
+ }
+
+ while (!done)
+ {
+ /* do we have an entry? */
+ pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file);
+ if (pw_buf == NULL)
+ return False;
+
+ /* build the SAM_ACCOUNT entry from the smb_passwd struct.
+ We loop in case the user in the pdb does not exist in
+ the local system password file */
+ if (build_sam_account(smbpasswd_state, user, pw_buf))
+ done = True;
+ }
+
+ DEBUG(5,("getsampwent (smbpasswd): done\n"));
+
+ /* success */
+ return True;
+}
+
+
+/****************************************************************
+ Search smbpasswd file by iterating over the entries. Do not
+ call getpwnam() for unix account information until we have found
+ the correct entry
+ ***************************************************************/
+static BOOL smbpasswd_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+ char *domain = NULL;
+ char *user = NULL;
+ fstring name;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
+
+
+ /* break the username from the domain if we have
+ been given a string in the form 'DOMAIN\user' */
+ fstrcpy (name, username);
+ if ((user=strchr_m(name, '\\')) != NULL) {
+ domain = name;
+ *user = '\0';
+ user++;
+ }
+
+ /* if a domain was specified and it wasn't ours
+ then there is no chance of matching */
+ if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
+ return False;
+
+ /* startsmbfilepwent() is used here as we don't want to lookup
+ the UNIX account in the local system password file until
+ we have a match. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ /* if we have a domain name, then we should map it to a UNIX
+ username first */
+ if ( domain )
+ map_username(user);
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwnam (smbpasswd): SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwnam\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+
+static BOOL smbpasswd_getsampwrid(struct pdb_context *context, SAM_ACCOUNT *sam_acct,uint32 rid)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwrid: (smbpasswd) SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwrid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+static BOOL smbpasswd_add_sam_account(struct pdb_context *context, const SAM_ACCOUNT *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ return False;
+ }
+
+ /* add the entry */
+ if(!add_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL smbpasswd_update_sam_account(struct pdb_context *context, const SAM_ACCOUNT *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ if (!build_smb_pass(&smb_pw, sampass))
+ return False;
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw))
+ return False;
+
+ return True;
+}
+
+static BOOL smbpasswd_delete_sam_account (struct pdb_context *context, const SAM_ACCOUNT *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)context->pdb_selected->private_data;
+
+ const char *username = pdb_get_username(sampass);
+
+ return del_smbfilepwd_entry(smbpasswd_state, username);
+}
+
+static void free_private_data(void **vp)
+{
+ struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
+
+ endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
+
+ *privates = NULL;
+ /* No need to free any further, as it is talloc()ed */
+}
+
+
+NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct smbpasswd_privates *privates;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "smbpasswd";
+
+ (*pdb_method)->setsampwent = smbpasswd_setsampwent;
+ (*pdb_method)->endsampwent = smbpasswd_endsampwent;
+ (*pdb_method)->getsampwent = smbpasswd_getsampwent;
+ (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
+ (*pdb_method)->getsampwrid = smbpasswd_getsampwrid;
+ (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
+ (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
+ (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
+
+ /* Setup private data and free function */
+
+ privates = talloc_zero(pdb_context->mem_ctx, sizeof(struct smbpasswd_privates));
+
+ if (!privates) {
+ DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Store some config details */
+
+ if (location) {
+ privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, location);
+ } else {
+ privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, lp_smb_passwd_file());
+ }
+
+ if (!privates->smbpasswd_file) {
+ DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*pdb_method)->private_data = privates;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_init_smbpasswd_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct smbpasswd_privates *privates;
+
+ if (!NT_STATUS_IS_OK(nt_status = pdb_init_smbpasswd(pdb_context, pdb_method, location))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "smbpasswd_nua";
+
+ privates = (*pdb_method)->private_data;
+
+ privates->permit_non_unix_accounts = True;
+
+ if (!lp_non_unix_account_range(&privates->low_nua_userid, &privates->high_nua_userid)) {
+ DEBUG(0, ("cannot use smbpasswd_nua without 'non unix account range' in smb.conf!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
new file mode 100644
index 0000000000..a8edac917e
--- /dev/null
+++ b/source3/passdb/pdb_tdb.c
@@ -0,0 +1,938 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000
+ * Copyright (C) Gerald Carter 2000
+ * Copyright (C) Jeremy Allison 2001
+ * Copyright (C) Andrew Bartlett 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"
+
+#ifdef WITH_TDB_SAM
+
+#define PDB_VERSION "20010830"
+#define PASSDB_FILE_NAME "passdb.tdb"
+#define TDB_FORMAT_STRING "ddddddBBBBBBBBBBBBddBBwdwdBdd"
+#define USERPREFIX "USER_"
+#define RIDPREFIX "RID_"
+
+struct tdbsam_privates {
+ TDB_CONTEXT *passwd_tdb;
+ TDB_DATA key;
+
+ /* retrive-once info */
+ const char *tdbsam_location;
+
+ BOOL permit_non_unix_accounts;
+
+/* uint32 low_nua_rid;
+ uint32 high_nua_rid; */
+};
+
+/**********************************************************************
+ Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
+ *********************************************************************/
+
+static BOOL init_sam_from_buffer (struct tdbsam_privates *tdb_state,
+ SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username;
+ char *domain;
+ char *nt_username;
+ char *dir_drive;
+ char *unknown_str;
+ char *munged_dial;
+ char *fullname;
+ char *homedir;
+ char *logon_script;
+ char *profile_path;
+ char *acct_desc;
+ char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 user_rid, group_rid, unknown_3, hours_len, unknown_5, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint8 *hours;
+ static uint8 *lm_pw_ptr, *nt_pw_ptr;
+ uint32 len = 0;
+ uint32 lmpwlen, ntpwlen, hourslen;
+ BOOL ret = True;
+ BOOL setflag;
+ pstring sub_buffer;
+ struct passwd *pw;
+ uid_t uid;
+ gid_t gid = -1; /* This is what standard sub advanced expects if no gid is known */
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_sam_from_buffer: NULL parameters found!\n"));
+ return False;
+ }
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING,
+ &logon_time,
+ &logoff_time,
+ &kickoff_time,
+ &pass_last_set_time,
+ &pass_can_change_time,
+ &pass_must_change_time,
+ &username_len, &username,
+ &domain_len, &domain,
+ &nt_username_len, &nt_username,
+ &fullname_len, &fullname,
+ &homedir_len, &homedir,
+ &dir_drive_len, &dir_drive,
+ &logon_script_len, &logon_script,
+ &profile_path_len, &profile_path,
+ &acct_desc_len, &acct_desc,
+ &workstations_len, &workstations,
+ &unknown_str_len, &unknown_str,
+ &munged_dial_len, &munged_dial,
+ &user_rid,
+ &group_rid,
+ &lmpwlen, &lm_pw_ptr,
+ &ntpwlen, &nt_pw_ptr,
+ &acct_ctrl,
+ &unknown_3,
+ &logon_divs,
+ &hours_len,
+ &hourslen, &hours,
+ &unknown_5,
+ &unknown_6);
+
+ if (len == -1) {
+ ret = False;
+ goto done;
+ }
+
+ /* validate the account and fill in UNIX uid and gid. Standard
+ * getpwnam() is used instead of Get_Pwnam() as we do not need
+ * to try case permutations
+ */
+ if (!username || !(pw = getpwnam_alloc(username))) {
+ if (!(tdb_state->permit_non_unix_accounts)) {
+ DEBUG(0,("tdbsam: getpwnam_alloc(%s) return NULL. User does not exist!\n", username));
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (pw) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+
+ passwd_free(&pw);
+
+ pdb_set_uid(sampass, uid);
+ pdb_set_gid(sampass, gid);
+ }
+
+ pdb_set_logon_time(sampass, logon_time, True);
+ pdb_set_logoff_time(sampass, logoff_time, True);
+ pdb_set_kickoff_time(sampass, kickoff_time, True);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, True);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time, True);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_username (sampass, username);
+ pdb_set_domain (sampass, domain);
+ pdb_set_nt_username (sampass, nt_username);
+ pdb_set_fullname (sampass, fullname);
+
+ if (homedir) setflag = True;
+ else {
+ setflag = False;
+ pstrcpy(sub_buffer, lp_logon_home());
+ /* standard_sub_advanced() assumes pstring is passed!! */
+ standard_sub_advanced(-1, username, "", gid, username, sub_buffer);
+ homedir = strdup(sub_buffer);
+ if(!homedir) { ret = False; goto done; }
+ DEBUG(5,("Home directory set back to %s\n", homedir));
+ }
+ pdb_set_homedir(sampass, homedir, setflag);
+
+ if (dir_drive) setflag = True;
+ else {
+ setflag = False;
+ pstrcpy(sub_buffer, lp_logon_drive());
+ standard_sub_advanced(-1, username, "", gid, username, sub_buffer);
+ dir_drive = strdup(sub_buffer);
+ if(!dir_drive) { ret = False; goto done; }
+ DEBUG(5,("Drive set back to %s\n", dir_drive));
+ }
+ pdb_set_dir_drive(sampass, dir_drive, setflag);
+
+ if (logon_script) setflag = True;
+ else {
+ setflag = False;
+ pstrcpy(sub_buffer, lp_logon_script());
+ standard_sub_advanced(-1, username, "", gid, username, sub_buffer);
+ logon_script = strdup(sub_buffer);
+ if(!logon_script) { ret = False; goto done; }
+ DEBUG(5,("Logon script set back to %s\n", logon_script));
+ }
+ pdb_set_logon_script(sampass, logon_script, setflag);
+
+ if (profile_path) setflag = True;
+ else {
+ setflag = False;
+ pstrcpy(sub_buffer, lp_logon_path());
+ standard_sub_advanced(-1, username, "", gid, username, sub_buffer);
+ profile_path = strdup(sub_buffer);
+ if(!profile_path) { ret = False; goto done; }
+ DEBUG(5,("Profile path set back to %s\n", profile_path));
+ }
+ pdb_set_profile_path(sampass, profile_path, setflag);
+
+ pdb_set_acct_desc (sampass, acct_desc);
+ pdb_set_workstations (sampass, workstations);
+ pdb_set_munged_dial (sampass, munged_dial);
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr)) {
+ ret = False;
+ goto done;
+ }
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr)) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+ pdb_set_unknown_3(sampass, unknown_3);
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_unknown_5(sampass, unknown_5);
+ pdb_set_unknown_6(sampass, unknown_6);
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logon_divs(sampass, logon_divs);
+ pdb_set_hours(sampass, hours);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+
+ return ret;
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a SAM_ACCOUNT struct
+ *********************************************************************/
+static uint32 init_buffer_from_sam (struct tdbsam_privates *tdb_state,
+ uint8 **buf, const SAM_ACCOUNT *sampass)
+{
+ size_t len, buflen;
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+
+ uint32 user_rid, group_rid;
+
+ const char *username;
+ const char *domain;
+ const char *nt_username;
+ const char *dir_drive;
+ const char *unknown_str;
+ const char *munged_dial;
+ const char *fullname;
+ const char *homedir;
+ const char *logon_script;
+ const char *profile_path;
+ const char *acct_desc;
+ const char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ const uint8 *lm_pw;
+ const uint8 *nt_pw;
+ uint32 lm_pw_len = 16;
+ uint32 nt_pw_len = 16;
+
+ /* do we have a valid SAM_ACCOUNT pointer? */
+ if (sampass == NULL) {
+ DEBUG(0, ("init_buffer_from_sam: SAM_ACCOUNT is NULL!\n"));
+ return -1;
+ }
+
+ *buf = NULL;
+ buflen = 0;
+
+ logon_time = (uint32)pdb_get_logon_time(sampass);
+ logoff_time = (uint32)pdb_get_logoff_time(sampass);
+ kickoff_time = (uint32)pdb_get_kickoff_time(sampass);
+ pass_can_change_time = (uint32)pdb_get_pass_can_change_time(sampass);
+ pass_must_change_time = (uint32)pdb_get_pass_must_change_time(sampass);
+ pass_last_set_time = (uint32)pdb_get_pass_last_set_time(sampass);
+
+ user_rid = pdb_get_user_rid(sampass);
+ group_rid = pdb_get_group_rid(sampass);
+
+ username = pdb_get_username(sampass);
+ if (username) username_len = strlen(username) +1;
+ else username_len = 0;
+
+ domain = pdb_get_domain(sampass);
+ if (domain) domain_len = strlen(domain) +1;
+ else domain_len = 0;
+
+ nt_username = pdb_get_nt_username(sampass);
+ if (nt_username) nt_username_len = strlen(nt_username) +1;
+ else nt_username_len = 0;
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname) fullname_len = strlen(fullname) +1;
+ else fullname_len = 0;
+
+ /*
+ * Only updates fields which have been set (not defaults from smb.conf)
+ */
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_DRIVE)) dir_drive = pdb_get_dirdrive(sampass);
+ else dir_drive = NULL;
+ if (dir_drive) dir_drive_len = strlen(dir_drive) +1;
+ else dir_drive_len = 0;
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_SMBHOME)) homedir = pdb_get_homedir(sampass);
+ else homedir = NULL;
+ if (homedir) homedir_len = strlen(homedir) +1;
+ else homedir_len = 0;
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_LOGONSCRIPT)) logon_script = pdb_get_logon_script(sampass);
+ else logon_script = NULL;
+ if (logon_script) logon_script_len = strlen(logon_script) +1;
+ else logon_script_len = 0;
+
+ if (IS_SAM_SET(sampass, FLAG_SAM_PROFILE)) profile_path = pdb_get_profile_path(sampass);
+ else profile_path = NULL;
+ if (profile_path) profile_path_len = strlen(profile_path) +1;
+ else profile_path_len = 0;
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ if (!lm_pw) lm_pw_len = 0;
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ if (!nt_pw) nt_pw_len = 0;
+
+ acct_desc = pdb_get_acct_desc(sampass);
+ if (acct_desc) acct_desc_len = strlen(acct_desc) +1;
+ else acct_desc_len = 0;
+
+ workstations = pdb_get_workstations(sampass);
+ if (workstations) workstations_len = strlen(workstations) +1;
+ else workstations_len = 0;
+
+ unknown_str = NULL;
+ unknown_str_len = 0;
+
+ munged_dial = pdb_get_munged_dial(sampass);
+ if (munged_dial) munged_dial_len = strlen(munged_dial) +1;
+ else munged_dial_len = 0;
+
+ /* one time to get the size needed */
+ len = tdb_pack(NULL, 0, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ user_rid,
+ group_rid,
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* malloc the space needed */
+ if ( (*buf=(uint8*)malloc(len)) == NULL) {
+ DEBUG(0,("init_buffer_from_sam: Unable to malloc() memory for buffer!\n"));
+ return (-1);
+ }
+
+ /* now for the real call to tdb_pack() */
+ buflen = tdb_pack(*buf, len, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ user_rid,
+ group_rid,
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* check to make sure we got it correct */
+ if (buflen != len) {
+ DEBUG(0, ("init_buffer_from_sam: somthing odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n",
+ buflen, len));
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+/***************************************************************
+ Open the TDB passwd database for SAM account enumeration.
+****************************************************************/
+
+static BOOL tdbsam_setsampwent(struct pdb_context *context, BOOL update)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+
+ /* Open tdb passwd */
+ if (!(tdb_state->passwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)))
+ {
+ DEBUG(0, ("Unable to open/create TDB passwd\n"));
+ return False;
+ }
+
+ tdb_state->key = tdb_firstkey(tdb_state->passwd_tdb);
+
+ return True;
+}
+
+static void close_tdb(struct tdbsam_privates *tdb_state)
+{
+ if (tdb_state->passwd_tdb) {
+ tdb_close(tdb_state->passwd_tdb);
+ tdb_state->passwd_tdb = NULL;
+ }
+}
+
+/***************************************************************
+ End enumeration of the TDB passwd list.
+****************************************************************/
+
+static void tdbsam_endsampwent(struct pdb_context *context)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ close_tdb(tdb_state);
+
+ DEBUG(7, ("endtdbpwent: closed sam database.\n"));
+}
+
+/*****************************************************************
+ Get one SAM_ACCOUNT from the TDB (next in line)
+*****************************************************************/
+
+static BOOL tdbsam_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ TDB_DATA data;
+ char *prefix = USERPREFIX;
+ int prefixlen = strlen (prefix);
+
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_get_sampwent: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* skip all non-USER entries (eg. RIDs) */
+ while ((tdb_state->key.dsize != 0) && (strncmp(tdb_state->key.dptr, prefix, prefixlen)))
+ /* increment to next in line */
+ tdb_state->key = tdb_nextkey(tdb_state->passwd_tdb, tdb_state->key);
+
+ /* do we have an valid interation pointer? */
+ if(tdb_state->passwd_tdb == NULL) {
+ DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
+ return False;
+ }
+
+ data = tdb_fetch(tdb_state->passwd_tdb, tdb_state->key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer(tdb_state, user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* increment to next in line */
+ tdb_state->key = tdb_nextkey(tdb_state->passwd_tdb, tdb_state->key);
+
+ return True;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+static BOOL tdbsam_getsampwnam (struct pdb_context *context, SAM_ACCOUNT *user, const char *sname)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* Data is stored in all lower-case */
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch(pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ DEBUGADD(5, (" Key: %s\n", keystr));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer(tdb_state, user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ tdb_close(pwd_tdb);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* no further use for database, close it now */
+ tdb_close(pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+static BOOL tdbsam_getsampwrid (struct pdb_context *context, SAM_ACCOUNT *user, uint32 rid)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ fstrcpy (name, data.dptr);
+ SAFE_FREE(data.dptr);
+
+ tdb_close (pwd_tdb);
+
+ return tdbsam_getsampwnam (context, user, name);
+}
+
+/***************************************************************************
+ Delete a SAM_ACCOUNT
+****************************************************************************/
+
+static BOOL tdbsam_delete_sam_account(struct pdb_context *context, const SAM_ACCOUNT *sam_pass)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA key;
+ fstring keystr;
+ uint32 rid;
+ fstring name;
+
+ unix_strlower(pdb_get_username(sam_pass), -1, name, sizeof(name));
+
+ /* open the TDB */
+ if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR, 0600))) {
+ DEBUG(0, ("Unable to open TDB passwd!"));
+ return False;
+ }
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ /* delete also the RID key */
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ tdb_close(pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Update the TDB SAM
+****************************************************************************/
+
+static BOOL tdb_update_sam(struct pdb_context *context, const SAM_ACCOUNT* newpwd, int flag)
+{
+ struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)context->pdb_selected->private_data;
+ TDB_CONTEXT *pwd_tdb = NULL;
+ TDB_DATA key, data;
+ uint8 *buf = NULL;
+ fstring keystr;
+ fstring name;
+ BOOL ret = True;
+ uint32 user_rid;
+ int32 tdb_ret;
+
+ /* invalidate the existing TDB iterator if it is open */
+ if (tdb_state->passwd_tdb) {
+ tdb_close(tdb_state->passwd_tdb);
+ tdb_state->passwd_tdb = NULL;
+ }
+
+ /* open the account TDB passwd*/
+ pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+ if (!pwd_tdb)
+ {
+ DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
+ return False;
+ }
+
+ /* if flag == TDB_INSERT then make up a new RID else throw an error. */
+ if (!(user_rid = pdb_get_user_rid(newpwd))) {
+ if (flag & TDB_INSERT) {
+ user_rid = BASE_RID;
+ tdb_ret = tdb_change_int32_atomic(pwd_tdb, "RID_COUNTER", &user_rid, RID_MULTIPLIER);
+ if (tdb_ret == -1) {
+ ret = False;
+ goto done;
+ }
+ pdb_set_user_rid(newpwd, user_rid);
+ } else {
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a RID\n",pdb_get_username(newpwd)));
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (!pdb_get_group_rid(newpwd)) {
+ if (flag & TDB_INSERT) {
+ if (!tdb_state->permit_non_unix_accounts) {
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd)));
+ ret = False;
+ goto done;
+ } else {
+ /* This seems like a good default choice for non-unix users */
+ pdb_set_group_rid(newpwd, DOMAIN_GROUP_RID_USERS);
+ }
+ } else {
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd)));
+ ret = False;
+ goto done;
+ }
+ }
+
+ /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
+ if ((data.dsize=init_buffer_from_sam (tdb_state, &buf, newpwd)) == -1) {
+ DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
+ ret = False;
+ goto done;
+ }
+ data.dptr = buf;
+
+ unix_strlower(pdb_get_username(newpwd), -1, name, sizeof(name));
+
+ DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid));
+
+ /* setup the USER index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* add the account */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify passwd TDB!"));
+ DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb)));
+ DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr));
+ ret = False;
+ goto done;
+ }
+
+ /* setup RID data */
+ data.dsize = sizeof(fstring);
+ data.dptr = name;
+
+ /* setup the RID index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* add the reference */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify TDB passwd !"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
+ ret = False;
+ goto done;
+ }
+
+done:
+ /* cleanup */
+ tdb_close (pwd_tdb);
+ SAFE_FREE(buf);
+
+ return (ret);
+}
+
+/***************************************************************************
+ Modifies an existing SAM_ACCOUNT
+****************************************************************************/
+
+static BOOL tdbsam_update_sam_account (struct pdb_context *context, const SAM_ACCOUNT *newpwd)
+{
+ return (tdb_update_sam(context, newpwd, TDB_MODIFY));
+}
+
+/***************************************************************************
+ Adds an existing SAM_ACCOUNT
+****************************************************************************/
+
+static BOOL tdbsam_add_sam_account (struct pdb_context *context, const SAM_ACCOUNT *newpwd)
+{
+ return (tdb_update_sam(context, newpwd, TDB_INSERT));
+}
+
+static void free_private_data(void **vp)
+{
+ struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp;
+ close_tdb(*tdb_state);
+ *tdb_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+
+NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct tdbsam_privates *tdb_state;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "tdbsam";
+
+ (*pdb_method)->setsampwent = tdbsam_setsampwent;
+ (*pdb_method)->endsampwent = tdbsam_endsampwent;
+ (*pdb_method)->getsampwent = tdbsam_getsampwent;
+ (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
+ (*pdb_method)->getsampwrid = tdbsam_getsampwrid;
+ (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
+ (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
+
+ tdb_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct tdbsam_privates));
+
+ if (!tdb_state) {
+ DEBUG(0, ("talloc() failed for tdbsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (location) {
+ tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, location);
+ } else {
+ pstring tdbfile;
+ get_private_directory(tdbfile);
+ pstrcat(tdbfile, "/");
+ pstrcat(tdbfile, PASSDB_FILE_NAME);
+ tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, tdbfile);
+ }
+
+ (*pdb_method)->private_data = tdb_state;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_init_tdbsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct tdbsam_privates *tdb_state;
+ uint32 low_nua_uid, high_nua_uid;
+
+ if (!NT_STATUS_IS_OK(nt_status = pdb_init_tdbsam(pdb_context, pdb_method, location))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "tdbsam_nua";
+
+ tdb_state = (*pdb_method)->private_data;
+
+ tdb_state->permit_non_unix_accounts = True;
+
+ if (!lp_non_unix_account_range(&low_nua_uid, &high_nua_uid)) {
+ DEBUG(0, ("cannot use tdbsam_nua without 'non unix account range' in smb.conf!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+/* tdb_state->low_nua_rid=fallback_pdb_uid_to_user_rid(low_nua_uid);
+
+ tdb_state->high_nua_rid=fallback_pdb_uid_to_user_rid(high_nua_uid);
+*/
+ return NT_STATUS_OK;
+}
+
+
+#else
+
+NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ DEBUG(0, ("tdbsam not compiled in!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS pdb_init_tdbsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+{
+ DEBUG(0, ("tdbsam_nua not compiled in!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+#endif
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
new file mode 100644
index 0000000000..b3507a1392
--- /dev/null
+++ b/source3/passdb/secrets.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+
+ 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.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb;
+
+/* open up the secrets database */
+BOOL secrets_init(void)
+{
+ pstring fname;
+
+ if (tdb)
+ return True;
+
+ pstrcpy(fname, lp_private_dir());
+ pstrcat(fname,"/secrets.tdb");
+
+ tdb = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+
+ if (!tdb) {
+ DEBUG(0,("Failed to open %s\n", fname));
+ return False;
+ }
+ return True;
+}
+
+/* read a entry from the secrets database - the caller must free the result
+ if size is non-null then the size of the entry is put in there
+ */
+void *secrets_fetch(char *key, size_t *size)
+{
+ TDB_DATA kbuf, dbuf;
+ secrets_init();
+ if (!tdb)
+ return NULL;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (size)
+ *size = dbuf.dsize;
+ return dbuf.dptr;
+}
+
+/* store a secrets entry
+ */
+BOOL secrets_store(char *key, void *data, size_t size)
+{
+ TDB_DATA kbuf, dbuf;
+ secrets_init();
+ if (!tdb)
+ return False;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ dbuf.dptr = data;
+ dbuf.dsize = size;
+ return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) == 0;
+}
+
+
+/* delete a secets database entry
+ */
+BOOL secrets_delete(char *key)
+{
+ TDB_DATA kbuf;
+ secrets_init();
+ if (!tdb)
+ return False;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ return tdb_delete(tdb, kbuf) == 0;
+}
+
+BOOL secrets_store_domain_sid(char *domain, DOM_SID *sid)
+{
+ fstring key;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
+ strupper(key);
+ return secrets_store(key, sid, sizeof(DOM_SID));
+}
+
+BOOL secrets_fetch_domain_sid(char *domain, DOM_SID *sid)
+{
+ DOM_SID *dyn_sid;
+ fstring key;
+ size_t size;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
+ strupper(key);
+ dyn_sid = (DOM_SID *)secrets_fetch(key, &size);
+
+ if (dyn_sid == NULL)
+ return False;
+
+ if (size != sizeof(DOM_SID))
+ {
+ SAFE_FREE(dyn_sid);
+ return False;
+ }
+
+ *sid = *dyn_sid;
+ SAFE_FREE(dyn_sid);
+ return True;
+}
+
+
+/************************************************************************
+form a key for fetching the machine trust account password
+************************************************************************/
+char *trust_keystr(char *domain)
+{
+ static fstring keystr;
+
+ slprintf(keystr,sizeof(keystr)-1,"%s/%s",
+ SECRETS_MACHINE_ACCT_PASS, domain);
+ strupper(keystr);
+
+ return keystr;
+}
+
+/**
+ * Form a key for fetching a trusted domain password
+ *
+ * @param domain domain name
+ *
+ * @return stored password's key
+ **/
+char *trustdom_keystr(char *domain)
+{
+ static char* keystr;
+
+ asprintf(&keystr, "%s/%s", SECRETS_DOMTRUST_ACCT_PASS, domain);
+ strupper(keystr);
+
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get the machine trust account password for a domain.
+************************************************************************/
+BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16],
+ time_t *pass_last_set_time)
+{
+ struct machine_acct_pass *pass;
+ char *plaintext;
+ size_t size;
+
+ plaintext = secrets_fetch_machine_password();
+ if (plaintext) {
+ /* we have an ADS password - use that */
+ DEBUG(4,("Using ADS machine password\n"));
+ E_md4hash((uchar *)plaintext, ret_pwd);
+ SAFE_FREE(plaintext);
+ return True;
+ }
+
+ if (!(pass = secrets_fetch(trust_keystr(domain), &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ if (size != sizeof(*pass)) {
+ DEBUG(0, ("secrets were of incorrect size!\n"));
+ return False;
+ }
+
+ if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
+ memcpy(ret_pwd, pass->hash, 16);
+ SAFE_FREE(pass);
+ return True;
+}
+
+/************************************************************************
+ Routine to get account password to trusted domain
+************************************************************************/
+BOOL secrets_fetch_trusted_domain_password(char *domain, char** pwd,
+ DOM_SID *sid, time_t *pass_last_set_time)
+{
+ struct trusted_dom_pass *pass;
+ size_t size;
+
+ if (!(pass = secrets_fetch(trustdom_keystr(domain), &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ if (size != sizeof(*pass)) {
+ DEBUG(0, ("secrets were of incorrect size!\n"));
+ return False;
+ }
+
+ if (pwd) {
+ *pwd = strdup(pass->pass);
+ if (!*pwd) {
+ return False;
+ }
+ }
+
+ if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
+
+ memcpy(&sid, &(pass->domain_sid), sizeof(sid));
+ SAFE_FREE(pass);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to set the trust account password for a domain.
+************************************************************************/
+BOOL secrets_store_trust_account_password(char *domain, uint8 new_pwd[16])
+{
+ struct machine_acct_pass pass;
+
+ pass.mod_time = time(NULL);
+ memcpy(pass.hash, new_pwd, 16);
+
+ return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass));
+}
+
+/**
+ * Routine to set the password for trusted domain
+ *
+ * @param domain remote domain name
+ * @param pwd plain text password of trust relationship
+ * @param sid remote domain sid
+ *
+ * @return true if succeeded
+ **/
+
+BOOL secrets_store_trusted_domain_password(char* domain, char* pwd,
+ DOM_SID sid)
+{
+ struct trusted_dom_pass pass;
+ ZERO_STRUCT(pass);
+
+ pass.mod_time = time(NULL);
+
+ pass.pass_len = strlen(pwd);
+ fstrcpy(pass.pass, pwd);
+
+ memcpy(&(pass.domain_sid), &sid, sizeof(sid));
+
+ return secrets_store(trustdom_keystr(domain), (void *)&pass, sizeof(pass));
+}
+
+/************************************************************************
+ Routine to set the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+BOOL secrets_store_machine_password(char *pass)
+{
+ char *key;
+ BOOL ret;
+ asprintf(&key, "%s/%s", SECRETS_MACHINE_PASSWORD, lp_workgroup());
+ strupper(key);
+ ret = secrets_store(key, pass, strlen(pass)+1);
+ free(key);
+ return ret;
+}
+
+
+/************************************************************************
+ Routine to fetch the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+char *secrets_fetch_machine_password(void)
+{
+ char *key;
+ char *ret;
+ asprintf(&key, "%s/%s", SECRETS_MACHINE_PASSWORD, lp_workgroup());
+ strupper(key);
+ ret = (char *)secrets_fetch(key, NULL);
+ free(key);
+ return ret;
+}
+
+
+
+/************************************************************************
+ Routine to delete the machine trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_delete(char *domain)
+{
+ return secrets_delete(trust_keystr(domain));
+}
+
+/************************************************************************
+ Routine to delete the password for trusted domain
+************************************************************************/
+BOOL trusted_domain_password_delete(char *domain)
+{
+ return secrets_delete(trustdom_keystr(domain));
+}
+
+
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+void reset_globals_after_fork(void)
+{
+ unsigned char dummy;
+
+ secrets_init();
+
+ /*
+ * Increment the global seed value to ensure every smbd starts
+ * with a new random seed.
+ */
+
+ if (tdb) {
+ uint32 initial_val = sys_getpid();
+ tdb_change_int32_atomic(tdb, "INFO/random_seed", (int *)&initial_val, 1);
+ set_rand_reseed_data((unsigned char *)&initial_val, sizeof(initial_val));
+ }
+
+ /*
+ * Re-seed the random crypto generator, so all smbd's
+ * started from the same parent won't generate the same
+ * sequence.
+ */
+ generate_random_buffer( &dummy, 1, True);
+}
+
+BOOL secrets_store_ldap_pw(char* dn, char* pw)
+{
+ fstring key;
+ char *p;
+
+ pstrcpy(key, dn);
+ for (p=key; *p; p++)
+ if (*p == ',') *p = '/';
+
+ return secrets_store(key, pw, strlen(pw));
+}
+
diff --git a/source3/passdb/smbpass.c b/source3/passdb/smbpass.c
deleted file mode 100644
index 2dec15ffb4..0000000000
--- a/source3/passdb/smbpass.c
+++ /dev/null
@@ -1,304 +0,0 @@
-#ifdef SMB_PASSWD
-/*
- * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
- * Copyright (C) Andrew Tridgell 1992-1995 Modified by Jeremy Allison 1995.
- *
- * 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"
-#include "loadparm.h"
-
-extern int DEBUGLEVEL;
-
-int gotalarm;
-
-void
-gotalarm_sig()
-{
- gotalarm = 1;
-}
-
-int
-do_pw_lock(int fd, int waitsecs, int type)
-{
- struct flock lock;
- int ret;
-
- gotalarm = 0;
- signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 1;
- lock.l_pid = 0;
-
- alarm(5);
- ret = fcntl(fd, F_SETLKW, &lock);
- alarm(0);
- signal(SIGALRM, SIGNAL_CAST SIG_DFL);
-
- if (gotalarm) {
- DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n",
- type == F_UNLCK ? "unlock" : "lock"));
- return -1;
- }
- return ret;
-}
-
-int
-pw_file_lock(char *name, int type, int secs)
-{
- int fd = open(name, O_RDWR | O_CREAT, 0666);
- if (fd < 0)
- return (-1);
- if (do_pw_lock(fd, secs, type)) {
- close(fd);
- return -1;
- }
- return fd;
-}
-
-int
-pw_file_unlock(int fd)
-{
- do_pw_lock(fd, 5, F_UNLCK);
- return close(fd);
-}
-
-/*
- * Routine to get the next 32 hex characters and turn them
- * into a 16 byte array.
- */
-
-static int gethexpwd(char *p, char *pwd)
-{
- int i;
- unsigned char lonybble, hinybble;
- char *hexchars = "0123456789ABCDEF";
- char *p1, *p2;
-
- 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);
-}
-
-/*
- * Routine to search the smbpasswd file for an entry matching the username.
- */
-struct smb_passwd *
-get_smbpwnam(char *name)
-{
- /* Static buffers we will return. */
- static struct smb_passwd pw_buf;
- static pstring user_name;
- static unsigned char smbpwd[16];
- static unsigned char smbntpwd[16];
- char linebuf[256];
- char readbuf[16 * 1024];
- unsigned char c;
- unsigned char *p;
- long uidval;
- long linebuf_len;
- FILE *fp;
- int lockfd;
- char *pfile = lp_smb_passwd_file();
-
- if (!*pfile) {
- DEBUG(0, ("No SMB password file set\n"));
- return (NULL);
- }
- DEBUG(10, ("get_smbpwnam: opening file %s\n", pfile));
-
- fp = fopen(pfile, "r");
-
- if (fp == NULL) {
- DEBUG(0, ("get_smbpwnam: unable to open file %s\n", pfile));
- return NULL;
- }
- /* Set a 16k buffer to do more efficient reads */
- setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
-
- if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
- DEBUG(0, ("get_smbpwnam: unable to lock file %s\n", pfile));
- fclose(fp);
- return NULL;
- }
- /* make sure it is only rw by the owner */
- chmod(pfile, 0600);
-
- /* We have a read lock on the file. */
- /*
- * Scan the file, a line at a time and check if the name matches.
- */
- while (!feof(fp)) {
- linebuf[0] = '\0';
-
- fgets(linebuf, 256, fp);
- if (ferror(fp)) {
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- /*
- * Check if the string is terminated with a newline - if not
- * then we must keep reading and discard until we get one.
- */
- linebuf_len = strlen(linebuf);
- if (linebuf[linebuf_len - 1] != '\n') {
- c = '\0';
- while (!ferror(fp) && !feof(fp)) {
- c = fgetc(fp);
- if (c == '\n')
- break;
- }
- } else
- linebuf[linebuf_len - 1] = '\0';
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf));
-#endif
- if ((linebuf[0] == 0) && feof(fp)) {
- DEBUG(4, ("get_smbpwnam: end of file reached\n"));
- break;
- }
- /*
- * The line we have should be of the form :-
- *
- * username:uid:[32hex bytes]:....other flags presently
- * ignored....
- *
- * or,
- *
- * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
- *
- * if Windows NT compatible passwords are also present.
- */
-
- if (linebuf[0] == '#' || linebuf[0] == '\0') {
- DEBUG(6, ("get_smbpwnam: skipping comment or blank line\n"));
- continue;
- }
- p = (unsigned char *) strchr(linebuf, ':');
- if (p == NULL) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no :)\n"));
- continue;
- }
- /*
- * As 256 is shorter than a pstring we don't need to check
- * length here - if this ever changes....
- */
- strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
- user_name[PTR_DIFF(p, linebuf)] = '\0';
- if (!strequal(user_name, name))
- continue;
-
- /* User name matches - get uid and password */
- p++; /* Go past ':' */
- if (!isdigit(*p)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (uid not number)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- uidval = atoi((char *) p);
- while (*p && isdigit(*p))
- p++;
- if (*p != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no : after uid)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- /*
- * Now get the password value - this should be 32 hex digits
- * which are the ascii representations of a 16 byte string.
- * Get two at a time and put them into the password.
- */
- p++;
- if (*p == '*' || *p == 'X') {
- /* Password deliberately invalid - end here. */
- DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", user_name));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (passwd too short)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return (False);
- }
- if (p[32] != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no terminating :)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
- pw_buf.smb_passwd = NULL;
- } else {
- if(!gethexpwd(p,smbpwd)) {
- DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- pw_buf.smb_passwd = smbpwd;
- }
- pw_buf.smb_name = user_name;
- pw_buf.smb_userid = uidval;
- pw_buf.smb_nt_passwd = NULL;
-
- /* Now check if the NT compatible password is
- available. */
- p += 33; /* Move to the first character of the line after
- the lanman password. */
- if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
- if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
- }
- }
-
- fclose(fp);
- pw_file_unlock(lockfd);
- DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n",
- user_name, uidval));
- return &pw_buf;
- }
-
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
-}
-#else
-void
-smbpass_dummy(void)
-{
-} /* To avoid compiler complaints */
-#endif