summaryrefslogtreecommitdiffstats
path: root/source/passdb
diff options
context:
space:
mode:
Diffstat (limited to 'source/passdb')
-rw-r--r--source/passdb/.cvsignore2
-rw-r--r--source/passdb/ldap.c1017
-rw-r--r--source/passdb/machine_sid.c255
-rw-r--r--source/passdb/nispass.c1083
-rw-r--r--source/passdb/pampass.c892
-rw-r--r--source/passdb/pass_check.c776
-rw-r--r--source/passdb/passdb.c1813
-rw-r--r--source/passdb/passgrp.c217
-rw-r--r--source/passdb/pdb_ldap.c1045
-rw-r--r--source/passdb/pdb_nisplus.c1409
-rw-r--r--source/passdb/pdb_smbpasswd.c1545
-rw-r--r--source/passdb/pdb_tdb.c808
-rw-r--r--source/passdb/secrets.c247
-rw-r--r--source/passdb/smbpass.c304
-rw-r--r--source/passdb/smbpasschange.c25
-rw-r--r--source/passdb/smbpassgroup.c195
16 files changed, 11329 insertions, 304 deletions
diff --git a/source/passdb/.cvsignore b/source/passdb/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/passdb/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/passdb/ldap.c b/source/passdb/ldap.c
new file mode 100644
index 00000000000..e0ac013fc8f
--- /dev/null
+++ b/source/passdb/ldap.c
@@ -0,0 +1,1017 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 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.
+
+*/
+
+#ifdef WITH_LDAP
+
+#include "includes.h"
+
+#include <lber.h>
+#include <ldap.h>
+
+#define ADD_USER 1
+#define MODIFY_USER 2
+
+/*******************************************************************
+ open a connection to the ldap serve.
+******************************************************************/
+static BOOL ldap_open_connection(LDAP **ldap_struct)
+{
+ if ( (*ldap_struct = ldap_open(lp_ldap_server(),lp_ldap_port()) ) == NULL)
+ {
+ DEBUG( 0, ( "The LDAP server is not responding !\n" ) );
+ return( False );
+ }
+ DEBUG(2,("ldap_open_connection: connection opened\n"));
+ return (True);
+}
+
+
+/*******************************************************************
+ connect anonymously to the ldap server.
+ FIXME: later (jfm)
+******************************************************************/
+static BOOL ldap_connect_anonymous(LDAP *ldap_struct)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server !\n" ) );
+ return(False);
+ }
+ return (True);
+}
+
+
+/*******************************************************************
+ connect to the ldap server under system privileg.
+******************************************************************/
+static BOOL ldap_connect_system(LDAP *ldap_struct)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server!\n" ) );
+ return(False);
+ }
+ DEBUG(2,("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ connect to the ldap server under a particular user.
+******************************************************************/
+static BOOL ldap_connect_user(LDAP *ldap_struct, const char *user, const char *password)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server !\n" ) );
+ return(False);
+ }
+ DEBUG(2,("ldap_connect_user: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static BOOL ldap_search_one_user(LDAP *ldap_struct, char *filter, LDAPMessage **result)
+{
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+
+ DEBUG(2,("ldap_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, ( "Problem during the LDAP search\n" ) );
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static BOOL ldap_search_one_user_by_name(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());
+ pstring_sub(filter,"%u",user);
+
+ if ( !ldap_search_one_user(ldap_struct, filter, result) )
+ {
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static BOOL ldap_search_one_user_by_uid(LDAP *ldap_struct, int uid, LDAPMessage **result)
+{
+ pstring filter;
+
+ slprintf(filter, sizeof(pstring)-1, "uidAccount = %d", uid);
+
+ if ( !ldap_search_one_user(ldap_struct, filter, result) )
+ {
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ search an attribute and return the first value found.
+******************************************************************/
+static void get_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, char *attribute, char *value)
+{
+ char **valeurs;
+
+ if ( (valeurs = ldap_get_values(ldap_struct, entry, attribute)) ! = NULL)
+ {
+ pstrcpy(value, valeurs[0]);
+ ldap_value_free(valeurs);
+ DEBUG(3,("get_single_attribute: [%s] = [%s]\n", attribute, value));
+ }
+ else
+ {
+ value = NULL;
+ }
+}
+
+/*******************************************************************
+ check if the returned entry is a sambaAccount objectclass.
+******************************************************************/
+static BOOL ldap_check_user(LDAP *ldap_struct, LDAPMessage *entry)
+{
+ BOOL sambaAccount = False;
+ char **valeur;
+ int i;
+
+ DEBUG(2,("ldap_check_user: "));
+ valeur = ldap_get_values(ldap_struct, entry, "objectclass");
+ if (valeur! = NULL)
+ {
+ for (i = 0;valeur[i]! = NULL;i++)
+ {
+ if (!strcmp(valeur[i],"sambaAccount")) sambaAccount = True;
+ }
+ }
+ DEBUG(2,("%s\n",sambaAccount?"yes":"no"));
+ ldap_value_free(valeur);
+ return (sambaAccount);
+}
+
+/*******************************************************************
+ check if the returned entry is a sambaTrust objectclass.
+******************************************************************/
+static BOOL ldap_check_trust(LDAP *ldap_struct, LDAPMessage *entry)
+{
+ BOOL sambaTrust = False;
+ char **valeur;
+ int i;
+
+ DEBUG(2,("ldap_check_trust: "));
+ valeur = ldap_get_values(ldap_struct, entry, "objectclass");
+ if (valeur! = NULL)
+ {
+ for (i = 0;valeur[i]! = NULL;i++)
+ {
+ if (!strcmp(valeur[i],"sambaTrust")) sambaTrust = True;
+ }
+ }
+ DEBUG(2,("%s\n",sambaTrust?"yes":"no"));
+ ldap_value_free(valeur);
+ return (sambaTrust);
+}
+
+/*******************************************************************
+ retrieve the user's info and contruct a smb_passwd structure.
+******************************************************************/
+static void ldap_get_smb_passwd(LDAP *ldap_struct,LDAPMessage *entry,
+ struct smb_passwd *user)
+{
+ static pstring user_name;
+ static pstring user_pass;
+ static pstring temp;
+ static unsigned char smblmpwd[16];
+ static unsigned char smbntpwd[16];
+
+ pdb_init_smb(user);
+
+ memset((char *)smblmpwd, '\0', sizeof(smblmpwd));
+ memset((char *)smbntpwd, '\0', sizeof(smbntpwd));
+
+ get_single_attribute(ldap_struct, entry, "cn", user_name);
+ DEBUG(2,("ldap_get_smb_passwd: user: %s\n",user_name));
+
+#ifdef LDAP_PLAINTEXT_PASSWORD
+ get_single_attribute(ldap_struct, entry, "userPassword", temp);
+ nt_lm_owf_gen(temp, user->smb_nt_passwd, user->smb_passwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+#else
+ get_single_attribute(ldap_struct, entry, "unicodePwd", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+
+ get_single_attribute(ldap_struct, entry, "dBCSPwd", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+#endif
+
+ get_single_attribute(ldap_struct, entry, "userAccountControl", temp);
+ user->acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+
+ /* the smb (unix) ids are not stored: they are created */
+ user->smb_userid = pdb_user_rid_to_uid (atoi(temp));
+
+ if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
+ {
+ DEBUG(0,("Inconsistency in the LDAP database\n"));
+ }
+ if (user->acct_ctrl & ACB_NORMAL)
+ {
+ user->smb_name = user_name;
+ user->smb_passwd = smblmpwd;
+ user->smb_nt_passwd = smbntpwd;
+ }
+}
+
+/*******************************************************************
+ retrieve the user's info and contruct a sam_passwd structure.
+
+ calls ldap_get_smb_passwd function first, though, to save code duplication.
+
+******************************************************************/
+static void ldap_get_sam_passwd(LDAP *ldap_struct, LDAPMessage *entry,
+ struct sam_passwd *user)
+{
+ static pstring user_name;
+ static pstring fullname;
+ static pstring home_dir;
+ static pstring dir_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring workstations;
+ static pstring temp;
+ static struct smb_passwd pw_buf;
+
+ pdb_init_sam(user);
+
+ ldap_get_smb_passwd(ldap_struct, entry, &pw_buf);
+
+ user->pass_last_set_time = pw_buf.pass_last_set_time;
+
+ get_single_attribute(ldap_struct, entry, "logonTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logoffTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ user->smb_name = pw_buf.smb_name;
+
+ DEBUG(2,("ldap_get_sam_passwd: user: %s\n", user_name));
+
+ get_single_attribute(ldap_struct, entry, "userFullName", fullname);
+ user->full_name = fullname;
+
+ get_single_attribute(ldap_struct, entry, "homeDirectory", home_dir);
+ user->home_dir = home_dir;
+
+ get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
+ user->dir_drive = dir_drive;
+
+ get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
+ user->logon_script = logon_script;
+
+ get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
+ user->profile_path = profile_path;
+
+ get_single_attribute(ldap_struct, entry, "comment", acct_desc);
+ user->acct_desc = acct_desc;
+
+ get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
+ user->workstations = workstations;
+
+ user->unknown_str = NULL; /* don't know, yet! */
+ user->munged_dial = NULL; /* "munged" dial-back telephone number */
+
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user->user_rid = atoi(temp);
+
+ get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
+ user->group_rid = atoi(temp);
+
+ /* the smb (unix) ids are not stored: they are created */
+ user->smb_userid = pw_buf.smb_userid;
+ user->smb_grpid = group_rid_to_uid(user->group_rid);
+
+ user->acct_ctrl = pw_buf.acct_ctrl;
+
+ user->unknown_3 = 0xffffff; /* don't know */
+ user->logon_divs = 168; /* hours per week */
+ user->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->hours, 0xff, user->hours_len); /* available at all hours */
+ user->unknown_5 = 0x00000000; /* don't know */
+ user->unknown_6 = 0x000004ec; /* don't know */
+
+ if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
+ {
+ DEBUG(0,("Inconsistency in the LDAP database\n"));
+ }
+
+ if (!(user->acct_ctrl & ACB_NORMAL))
+ {
+ DEBUG(0,("User's acct_ctrl bits not set to ACT_NORMAL in LDAP database\n"));
+ return;
+ }
+}
+
+/************************************************************************
+ 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, **tmods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (mods == NULL)
+ {
+ tmods = (LDAPMod **)malloc( sizeof(LDAPMod *) );
+ if (tmods == NULL)
+ {
+ DEBUG(0,("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods = tmods;
+ 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)
+ {
+ tmods = (LDAPMod **)Realloc( mods, (i+2) * sizeof( LDAPMod * ) );
+ if (tmods == NULL)
+ {
+ DEBUG(0,("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods = tmods;
+ 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 )
+ {
+ char **tmval;
+
+ j = 0;
+ if ( mods[ i ]->mod_values ! = NULL )
+ {
+ for ( ; mods[ i ]->mod_values[ j ] ! = NULL; j++ );
+ }
+ tmval = (char **)Realloc(mods[ i ]->mod_values,
+ (j+2) * sizeof( char * ));
+ if ( tmval == NULL)
+ {
+ DEBUG(0, "make_a_mod: Memory allocation failure!\n");
+ return;
+ }
+ mods[ i ]->mod_values = tmval;
+ mods[ i ]->mod_values[ j ] = strdup(value);
+ mods[ i ]->mod_values[ j + 1 ] = NULL;
+ }
+ *modlist = mods;
+}
+
+/************************************************************************
+ Add or modify an entry. Only the smb struct values
+
+*************************************************************************/
+static BOOL modadd_ldappwd_entry(struct smb_passwd *newpwd, int flag)
+{
+
+ /* assume the struct is correct and filled
+ that's the job of passdb.c to check */
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+ char *smb_name;
+ int trust = False;
+ int ldap_state;
+ pstring filter;
+ pstring dn;
+ pstring lmhash;
+ pstring nthash;
+ pstring rid;
+ pstring lst;
+ pstring temp;
+
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMod **mods;
+
+ smb_name = newpwd->smb_name;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (smb_name[strlen(smb_name)-1] == '$' )
+ {
+ smb_name[strlen(smb_name)-1] = '\0';
+ trust = True;
+ }
+
+ slprintf(filter, sizeof(filter)-1,
+ "(&(cn = %s)(|(objectclass = sambaTrust)(objectclass = sambaAccount)))",
+ smb_name);
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &result);
+
+ switch (flag)
+ {
+ case ADD_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 0)
+ {
+ DEBUG(0,("User already in the base, with samba properties\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_ADD;
+ break;
+ }
+ case MODIFY_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(0,("No user to modify !\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_REPLACE;
+ break;
+ }
+ default:
+ {
+ DEBUG(0,("How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+ slprintf(dn, sizeof(dn)-1, "cn = %s, %s",smb_name, lp_ldap_suffix() );
+
+ if (newpwd->smb_passwd ! = NULL)
+ {
+ int i;
+ for( i = 0; i < 16; i++)
+ {
+ slprintf(&temp[2*i], sizeof(temp) - 1, "%02X", newpwd->smb_passwd[i]);
+ }
+
+ }
+ else
+ {
+ if (newpwd->acct_ctrl & ACB_PWNOTREQ)
+ {
+ slprintf(temp, sizeof(temp) - 1, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ }
+ else
+ {
+ slprintf(temp, sizeof(temp) - 1, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ }
+ slprintf(lmhash, sizeof(lmhash)-1, "%s", temp);
+
+ if (newpwd->smb_nt_passwd ! = NULL)
+ {
+ int i;
+ for( i = 0; i < 16; i++)
+ {
+ slprintf(&temp[2*i], sizeof(temp) - 1, "%02X", newpwd->smb_nt_passwd[i]);
+ }
+
+ }
+ else
+ {
+ if (newpwd->acct_ctrl & ACB_PWNOTREQ)
+ {
+ slprintf(temp, sizeof(temp) - 1, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ }
+ else
+ {
+ slprintf(temp, sizeof(temp) - 1, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ }
+ slprintf(nthash, sizeof(nthash)-1, "%s", temp);
+
+ slprintf(rid, sizeof(rid)-1, "%d", uid_to_user_rid(newpwd->smb_userid) );
+ slprintf(lst, sizeof(lst)-1, "%08X", newpwd->pass_last_set_time);
+
+ mods = NULL;
+
+ if (trust)
+ {
+ make_a_mod(&mods, ldap_state, "objectclass", "sambaTrust");
+ make_a_mod(&mods, ldap_state, "netbiosTrustName", smb_name);
+ make_a_mod(&mods, ldap_state, "trustPassword", nthash);
+ }
+ else
+ {
+ make_a_mod(&mods, ldap_state, "objectclass", "sambaAccount");
+ make_a_mod(&mods, ldap_state, "dBCSPwd", lmhash);
+ make_a_mod(&mods, ldap_state, "uid", smb_name);
+ make_a_mod(&mods, ldap_state, "unicodePwd", nthash);
+ }
+
+ make_a_mod(&mods, ldap_state, "cn", smb_name);
+
+ make_a_mod(&mods, ldap_state, "rid", rid);
+ make_a_mod(&mods, ldap_state, "pwdLastSet", lst);
+ make_a_mod(&mods, ldap_state, "userAccountControl",
+ smbpasswd_encode_acb_info(newpwd->acct_ctrl));
+
+ switch(flag)
+ {
+ case ADD_USER:
+ {
+ ldap_add_s(ldap_struct, dn, mods);
+ DEBUG(2,("modadd_ldappwd_entry: added: cn = %s in the LDAP database\n",smb_name));
+ break;
+ }
+ case MODIFY_USER:
+ {
+ ldap_modify_s(ldap_struct, dn, mods);
+ DEBUG(2,("modadd_ldappwd_entry: changed: cn = %s in the LDAP database_n",smb_name));
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("modadd_ldappwd_entry: How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+
+ ldap_mods_free(mods, 1);
+
+ ldap_unbind(ldap_struct);
+
+ return True;
+}
+
+/************************************************************************
+ Add or modify an entry. everything except the smb struct
+
+*************************************************************************/
+static BOOL modadd_ldap21pwd_entry(struct sam_passwd *newpwd, int flag)
+{
+
+ /* assume the struct is correct and filled
+ that's the job of passdb.c to check */
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+ char *smb_name;
+ int trust = False;
+ int ldap_state;
+ pstring filter;
+ pstring dn;
+ pstring lmhash;
+ pstring nthash;
+ pstring rid;
+ pstring lst;
+ pstring temp;
+
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMod **mods;
+
+ smb_name = newpwd->smb_name;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (smb_name[strlen(smb_name)-1] == '$' )
+ {
+ smb_name[strlen(smb_name)-1] = '\0';
+ trust = True;
+ }
+
+ slprintf(filter, sizeof(filter)-1,
+ "(&(cn = %s)(|(objectclass = sambaTrust)(objectclass = sambaAccount)))",
+ smb_name);
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &result);
+
+ switch (flag)
+ {
+ case ADD_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(2,("User already in the base, with samba properties\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_ADD;
+ break;
+ }
+
+ case MODIFY_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(2,("No user to modify !\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_REPLACE;
+ break;
+ }
+
+ default:
+ {
+ DEBUG(2,("How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+ slprintf(dn, sizeof(dn)-1, "cn = %s, %s",smb_name, lp_ldap_suffix() );
+
+ mods = NULL;
+
+ if (trust)
+ {
+ }
+ else
+ {
+ }
+
+ make_a_mod(&mods, ldap_state, "cn", smb_name);
+
+ make_a_mod(&mods, ldap_state, "rid", rid);
+ make_a_mod(&mods, ldap_state, "pwdLastSet", lst);
+ make_a_mod(&mods, ldap_state, "userAccountControl",
+ smbpasswd_encode_acct_ctrl(newpwd->acct_ctrl));
+
+ ldap_modify_s(ldap_struct, dn, mods);
+
+ ldap_mods_free(mods, 1);
+
+ ldap_unbind(ldap_struct);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to add an entry to the ldap passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_ldappwd_entry(struct smb_passwd *newpwd)
+{
+ return (modadd_ldappwd_entry(newpwd, ADD_USER) );
+}
+
+/************************************************************************
+ Routine to search the ldap passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startldappwent()/
+ getldappwent()/endldappwent() 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
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_ldappwd_entry(struct smb_passwd *pwd, BOOL override)
+{
+ return (modadd_ldappwd_entry(pwd, MODIFY_USER) );
+}
+
+/************************************************************************
+ Routine to add an entry to the ldap passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_ldap21pwd_entry(struct sam_passwd *newpwd)
+{
+ return( modadd_ldappwd_entry(newpwd, ADD_USER)?
+ modadd_ldap21pwd_entry(newpwd, ADD_USER):False);
+}
+
+/************************************************************************
+ Routine to search the ldap passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startldappwent()/
+ getldappwent()/endldappwent() 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
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_ldap21pwd_entry(struct sam_passwd *pwd, BOOL override)
+{
+ return( modadd_ldappwd_entry(pwd, MODIFY_USER)?
+ modadd_ldap21pwd_entry(pwd, MODIFY_USER):False);
+}
+
+struct ldap_enum_info
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+};
+
+static struct ldap_enum_info ldap_ent;
+
+/***************************************************************
+ Start to enumerate the ldap passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ do not call this function directly. use passdb.c instead.
+
+ ****************************************************************/
+static void *startldappwent(BOOL update)
+{
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+
+ pstring filter;
+
+ if (!ldap_open_connection(&ldap_ent.ldap_struct)) /* open a connection to the server */
+ {
+ return NULL;
+ }
+
+ if (!ldap_connect_system(ldap_ent.ldap_struct)) /* connect as system account */
+ {
+ return NULL;
+ }
+
+ /* when the class is known the search is much faster */
+ switch (0)
+ {
+ case 1:
+ {
+ pstrcpy(filter, "objectclass = sambaAccount");
+ break;
+ }
+ case 2:
+ {
+ pstrcpy(filter, "objectclass = sambaTrust");
+ break;
+ }
+ default:
+ {
+ pstrcpy(filter, "(|(objectclass = sambaTrust)(objectclass = sambaAccount))");
+ break;
+ }
+ }
+
+ rc = ldap_search_s(ldap_ent.ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &ldap_ent.result);
+
+ DEBUG(2,("%d entries in the base!\n", ldap_count_entries(ldap_ent.ldap_struct, ldap_ent.result) ));
+
+ ldap_ent.entry = ldap_first_entry(ldap_ent.ldap_struct, ldap_ent.result);
+
+ return &ldap_ent;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct smb_passwd *getldappwent(void *vp)
+{
+ static struct smb_passwd user;
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+
+ ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
+
+ if (ldap_vp->entry ! = NULL)
+ {
+ ldap_get_smb_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
+ return &user;
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct sam_passwd *getldap21pwent(void *vp)
+{
+ static struct sam_passwd user;
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+
+ ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
+
+ if (ldap_vp->entry ! = NULL)
+ {
+ ldap_get_sam_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
+ return &user;
+ }
+ return NULL;
+}
+
+/***************************************************************
+ End enumeration of the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+****************************************************************/
+static void endldappwent(void *vp)
+{
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+ ldap_msgfree(ldap_vp->result);
+ ldap_unbind(ldap_vp->ldap_struct);
+}
+
+/*************************************************************************
+ Return the current position in the ldap passwd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static SMB_BIG_UINT getldappwpos(void *vp)
+{
+ return (SMB_BIG_UINT)0;
+}
+
+/*************************************************************************
+ Set the current position in the ldap passwd list from SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL setldappwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return False;
+}
+
+/*
+ * Ldap derived functions.
+ */
+
+static struct smb_passwd *getldappwnam(char *name)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwnam(name));
+}
+
+static struct smb_passwd *getldappwuid(uid_t smb_userid)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwuid(smb_userid));
+}
+
+static struct smb_passwd *getldappwrid(uint32 user_rid)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwuid(pdb_user_rid_to_uid(user_rid)));
+}
+
+static struct smb_passwd *getldappwent(void *vp)
+{
+ return pdb_sam_to_smb(getldap21pwent(vp));
+}
+
+static BOOL add_ldappwd_entry(struct smb_passwd *newpwd)
+{
+ return add_ldap21pwd_entry(pdb_smb_to_sam(newpwd));
+}
+
+static BOOL mod_ldappwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ return mod_ldap21pwd_entry(pdb_smb_to_sam(pwd), override);
+}
+
+static BOOL del_ldappwd_entry(const char *name)
+{
+ return False; /* Dummy... */
+}
+
+static struct sam_passwd *getldap21pwuid(uid_t uid)
+{
+ return pdb_smb_to_sam(iterate_getsam21pwuid(pdb_uid_to_user_rid(uid)));
+}
+
+static struct passdb_ops ldap_ops =
+{
+ startldappwent,
+ endldappwent,
+ getldappwpos,
+ setldappwpos,
+ getldappwnam,
+ getldappwuid,
+ getldappwrid,
+ getldappwent,
+ add_ldappwd_entry,
+ mod_ldappwd_entry,
+ del_ldappwd_entry,
+ getldap21pwent,
+ iterate_getsam21pwnam, /* From passdb.c */
+ iterate_getsam21pwuid, /* From passdb.c */
+ iterate_getsam21pwrid, /* From passdb.c */
+ add_ldap21pwd_entry,
+ mod_ldap21pwd_entry
+};
+
+struct passdb_ops *ldap_initialize_password_db(void)
+{
+ return &ldap_ops;
+}
+
+#else
+ void dummy_function(void);
+ void dummy_function(void) { } /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/machine_sid.c b/source/passdb/machine_sid.c
new file mode 100644
index 00000000000..859f00b4c6e
--- /dev/null
+++ b/source/passdb/machine_sid.c
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ 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 the machine SID from a file.
+****************************************************************************/
+
+static BOOL read_sid_from_file(int fd, char *sid_file)
+{
+ fstring fline;
+
+ memset(fline, '\0', sizeof(fline));
+
+ if(read(fd, fline, sizeof(fline) -1 ) < 0) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Convert to the machine SID.
+ */
+
+ fline[sizeof(fline)-1] = '\0';
+ if(!string_to_sid( &global_sam_sid, fline)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Generate the global machine sid. Look for the MACHINE.SID file first, if
+ not found then look in smb.conf and use it to create the MACHINE.SID file.
+ Note this function will be replaced soon. JRA.
+****************************************************************************/
+
+BOOL pdb_generate_sam_sid(void)
+{
+ int fd;
+ pstring sid_file;
+ fstring sid_string;
+ SMB_STRUCT_STAT st;
+ BOOL overwrite_bad_sid = False;
+
+ generate_wellknown_sids();
+
+ pstrcpy(sid_file, lp_private_dir());
+
+ if (!directory_exist(sid_file, NULL)) {
+ if (mkdir(sid_file, 0700) != 0) {
+ DEBUG(0,("can't create private directory %s : %s\n",
+ sid_file, strerror(errno)));
+ return False;
+ }
+ }
+
+ pstrcat(sid_file, "/MACHINE.SID");
+
+ if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
+ DEBUG(0,("unable to open or create file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Check if the file contains data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * We have a valid SID - read it.
+ */
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ /*
+ * JRA. Reversed the sense of this test now that I have
+ * actually done this test *personally*. One more reason
+ * to never trust third party information you have not
+ * independently verified.... sigh. JRA.
+ */
+
+ if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
+ /*
+ * Fix and re-write...
+ */
+ overwrite_bad_sid = True;
+ global_sam_sid.sub_auths[0] = 21;
+ DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
+detected - re-writing to be decimal 21 instead.\n" ));
+ sid_to_string(sid_string, &global_sam_sid);
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
+ DEBUG(0,("unable to seek file file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ } else {
+ close(fd);
+ return True;
+ }
+ } else {
+ /*
+ * The file contains no data - we need to generate our
+ * own sid.
+ * Generate the new sid data & turn it into a string.
+ */
+ int i;
+ uchar raw_sid_data[12];
+ DOM_SID mysid;
+
+ memset((char *)&mysid, '\0', sizeof(DOM_SID));
+ mysid.sid_rev_num = 1;
+ mysid.id_auth[5] = 5;
+ mysid.num_auths = 0;
+ mysid.sub_auths[mysid.num_auths++] = 21;
+
+ generate_random_buffer( raw_sid_data, 12, True);
+ for( i = 0; i < 3; i++)
+ mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
+
+ sid_to_string(sid_string, &mysid);
+ }
+
+ fstrcat(sid_string, "\n");
+
+ /*
+ * Ensure our new SID is valid.
+ */
+
+ if(!string_to_sid( &global_sam_sid, sid_string)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ /*
+ * Do an exclusive blocking lock on the file.
+ */
+
+ if(!do_file_lock( fd, 60, F_WRLCK)) {
+ DEBUG(0,("unable to lock file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(!overwrite_bad_sid) {
+ /*
+ * At this point we have a blocking lock on the SID
+ * file - check if in the meantime someone else wrote
+ * SID data into the file. If so - they were here first,
+ * use their data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * Unlock as soon as possible to reduce
+ * contention on the exclusive lock.
+ */
+ do_file_lock( fd, 60, F_UNLCK);
+
+ /*
+ * We have a valid SID - read it.
+ */
+
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ close(fd);
+ return True;
+ }
+ }
+
+ /*
+ * The file is still empty and we have an exlusive lock on it,
+ * or we're fixing an earlier mistake.
+ * Write out out SID data into the file.
+ */
+
+ /*
+ * Use chmod here as some (strange) UNIX's don't
+ * have fchmod. JRA.
+ */
+
+ if(chmod(sid_file, 0644) < 0) {
+ DEBUG(0,("unable to set correct permissions on file %s. \
+Error was %s\n", sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
+ DEBUG(0,("unable to write file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ /*
+ * Unlock & exit.
+ */
+
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return True;
+}
+
+
diff --git a/source/passdb/nispass.c b/source/passdb/nispass.c
new file mode 100644
index 00000000000..2b1f6b54927
--- /dev/null
+++ b/source/passdb/nispass.c
@@ -0,0 +1,1083 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. 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.
+ *
+ * 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
+
+#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;
+
+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_PWDLCHG_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
+
+/***************************************************************
+ 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(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(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)
+ {
+ DEBUG(10,("get_single_attribute: entry length truncated\n"));
+ 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(struct sam_passwd *pw_buf, nis_object *obj)
+{
+ int uidval;
+ static pstring user_name;
+ static pstring full_name;
+ static pstring home_dir;
+ static pstring home_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring workstations;
+ static pstring temp;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+
+ char *p;
+
+ pdb_init_sam(pw_buf);
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ pstrcpy(user_name, ENTRY_VAL(obj, NPF_NAME));
+ pw_buf->smb_name = user_name;
+
+ uidval = atoi(ENTRY_VAL(obj, NPF_UID));
+ pw_buf->smb_userid = uidval;
+
+ /* Check the lanman password column. */
+ p = (char *)ENTRY_VAL(obj, NPF_LMPWD);
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("make_sam_from_nisp_object: 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 True;
+ }
+ if (!strncasecmp(p, "NO PASSWORD", 11)) {
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (strlen(p) != 32 || !pdb_gethexpwd(p, smbpwd))
+ {
+ DEBUG(0, ("make_sam_from_nisp_object: malformed LM pwd entry.\n"));
+ return False;
+ }
+ }
+
+ pw_buf->smb_passwd = smbpwd;
+
+ /* Check the NT password column. */
+ p = ENTRY_VAL(obj, NPF_NTPWD);
+ if (*p != '*' && *p != 'X') {
+ if (strlen(p) != 32 || !pdb_gethexpwd(p, smbntpwd))
+ {
+ DEBUG(0, ("make_smb_from_nisp_object: malformed NT pwd entry\n"));
+ return False;
+ }
+ pw_buf->smb_nt_passwd = smbntpwd;
+ }
+
+ p = (char *)ENTRY_VAL(obj, NPF_ACB);
+ if (*p == '[')
+ {
+ pw_buf->acct_ctrl = pdb_decode_acct_ctrl(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(*p == ']')
+ p++;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp(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(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;
+ }
+ }
+
+ get_single_attribute(obj, NPF_SMB_GRPID, temp, sizeof(pstring));
+ pw_buf->smb_grpid = atoi(temp);
+
+ get_single_attribute(obj, NPF_USER_RID, temp, sizeof(pstring));
+ pw_buf->user_rid = (strlen(temp) > 0) ?
+ strtol(temp, NULL, 16) : pdb_uid_to_user_rid (pw_buf->smb_userid);
+
+ if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$') {
+
+ get_single_attribute(obj, NPF_GROUP_RID, temp, sizeof(pstring));
+
+ if (strlen(temp) > 0)
+ pw_buf->group_rid = strtol(temp, NULL, 16);
+ else {
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pw_buf->smb_grpid, &map, MAPPING_WITHOUT_PRIV)) {
+ pw_buf->group_rid = map.rid;
+ }
+ else
+ pw_buf->group_rid = pdb_gid_to_group_rid(pw_buf->smb_grpid);
+ }
+
+ get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
+#if 1
+ /* It seems correct to use the global values - but in that case why
+ * do we want these NIS+ entries anyway ??
+ */
+ pstrcpy(logon_script , lp_logon_script ());
+ pstrcpy(profile_path , lp_logon_path ());
+ pstrcpy(home_drive , lp_logon_drive ());
+ pstrcpy(home_dir , lp_logon_home ());
+#else
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script, sizeof(pstring));
+ get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
+ get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
+ get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
+#endif
+ get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
+ get_single_attribute(obj, NPF_WORKSTATIONS, workstations, sizeof(pstring));
+
+ } else {
+
+ pw_buf->group_rid = DOMAIN_GROUP_RID_USERS; /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+
+ pstrcpy(full_name , "");
+ pstrcpy(logon_script , "");
+ pstrcpy(profile_path , "");
+ pstrcpy(home_drive , "");
+ pstrcpy(home_dir , "");
+ pstrcpy(acct_desc , "");
+ pstrcpy(workstations , "");
+ }
+
+ pw_buf->full_name = full_name;
+ pw_buf->home_dir = home_dir;
+ pw_buf->dir_drive = home_drive;
+ pw_buf->logon_script = logon_script;
+ pw_buf->profile_path = profile_path;
+ pw_buf->acct_desc = acct_desc;
+ pw_buf->workstations = workstations;
+
+ pw_buf->unknown_str = NULL; /* don't know, yet! */
+ pw_buf->munged_dial = NULL; /* "munged" dial-back telephone number */
+
+ pw_buf->unknown_3 = 0xffffff; /* don't know */
+ pw_buf->logon_divs = 168; /* hours per week */
+ pw_buf->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(pw_buf->hours, 0xff, pw_buf->hours_len); /* available at all hours */
+ pw_buf->unknown_5 = 0x00000000; /* don't know */
+ pw_buf->unknown_6 = 0x000004ec; /* don't know */
+
+ return True;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisresult(struct sam_passwd *pw_buf, nis_result *result)
+{
+ if (pw_buf == NULL || result == NULL) return False;
+
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(0, ("make_sam_from_nisresult: NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("make_sam_from_nisresult: user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("make_sam_from_nisresult: 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]);
+ }
+
+/***************************************************************
+ calls nis_list, returns results.
+ ****************************************************************/
+static nis_result *nisp_get_nis_list(char *nis_name)
+{
+ nis_result *result;
+ result = nis_list(nis_name, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("nisp_get_nis_list: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+ return result;
+}
+
+
+
+struct nisp_enum_info
+{
+ nis_result *result;
+ int enum_entry;
+};
+
+/***************************************************************
+ Start to enumerate the nisplus passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ do not call this function directly. use passdb.c instead.
+
+ ****************************************************************/
+static void *startnisppwent(BOOL update)
+{
+ static struct nisp_enum_info res;
+ res.result = nisp_get_nis_list(lp_smb_passwd_file());
+ res.enum_entry = 0;
+ return res.result != NULL ? &res : NULL;
+}
+
+/***************************************************************
+ End enumeration of the nisplus passwd list.
+****************************************************************/
+static void endnisppwent(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ nis_freeresult(res->result);
+ DEBUG(7,("endnisppwent: freed enumeration list\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwent(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ static struct sam_passwd pw_buf;
+ int which;
+ BOOL ret;
+
+ if (res == NULL || (int)(res->enum_entry) < 0 ||
+ (int)(res->enum_entry) > (NIS_RES_NUMOBJ(res->result) - 1)) {
+ ret = False;
+ } else {
+ which = (int)(res->enum_entry);
+ ret = make_sam_from_nisp_object(&pw_buf,
+ &NIS_RES_OBJECT(res->result)[which]);
+ if (ret && which < (NIS_RES_NUMOBJ(res->result) - 1))
+ (int)(res->enum_entry)++;
+ }
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*************************************************************************
+ Return the current position in the nisplus passwd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static SMB_BIG_UINT getnisppwpos(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ return (SMB_BIG_UINT)(res->enum_entry);
+}
+
+/*************************************************************************
+ Set the current position in the nisplus passwd list from SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL setnisppwpos(void *vp, SMB_BIG_UINT tok)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ if (tok < (NIS_RES_NUMOBJ(res->result) - 1)) {
+ res->enum_entry = tok;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+/*************************************************************************
+ 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;
+ }
+}
+
+/************************************************************************
+ Routine to add an entry to the nisplus passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
+{
+ char *pfile;
+ char *nisname;
+ nis_result *nis_user;
+ nis_result *result = NULL,
+ *tblresult = NULL,
+ *addresult = NULL;
+ nis_object new_obj, *obj;
+
+ fstring uid;
+ fstring user_rid;
+ fstring smb_grpid;
+ fstring group_rid;
+ fstring acb;
+
+ fstring smb_passwd;
+ fstring smb_nt_passwd;
+
+ fstring logon_t;
+ fstring logoff_t;
+ fstring kickoff_t;
+ fstring pwdlset_t;
+ fstring pwdlchg_t;
+ fstring pwdmchg_t;
+
+ memset((char *)logon_t , '\0', sizeof(logon_t ));
+ memset((char *)logoff_t , '\0', sizeof(logoff_t ));
+ memset((char *)kickoff_t, '\0', sizeof(kickoff_t));
+ memset((char *)pwdlset_t, '\0', sizeof(pwdlset_t));
+ memset((char *)pwdlchg_t, '\0', sizeof(pwdlchg_t));
+ memset((char *)pwdmchg_t, '\0', sizeof(pwdmchg_t));
+
+ pfile = lp_smb_passwd_file();
+
+ nisname = make_nisname_from_name(newpwd->smb_name, pfile);
+ result = nisp_get_nis_list(nisname);
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(3, ( "add_nis21ppwd_entry: 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, ("add_nisp21pwd_entry: User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+#if 0
+ /* User not found. */
+ if (!add_user)
+ {
+ DEBUG(3, ("add_nisp21pwd_entry: User not found in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+#endif
+
+ tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ nis_freeresult(result);
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "add_nisp21pwd_entry: nis_lookup failure: %s\n",
+ nis_sperrno(tblresult->status)));
+ return False;
+ }
+
+ new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
+ new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
+ new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
+ new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
+ 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.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
+ new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_maxcol;
+ new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val = calloc(new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len, sizeof(entry_col));
+
+ if (new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val == NULL)
+ {
+ DEBUG(0, ("add_nisp21pwd_entry: memory allocation failure\n"));
+ nis_freeresult(result);
+ nis_freeresult(tblresult);
+ return False;
+ }
+
+ pdb_sethexpwd(smb_passwd , newpwd->smb_passwd , newpwd->acct_ctrl);
+ pdb_sethexpwd(smb_nt_passwd, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+
+ newpwd->pass_last_set_time = (time_t)time(NULL);
+ newpwd->logon_time = (time_t)-1;
+ newpwd->logoff_time = (time_t)-1;
+ newpwd->kickoff_time = (time_t)-1;
+ newpwd->pass_can_change_time = (time_t)-1;
+ newpwd->pass_must_change_time = (time_t)-1;
+
+ slprintf(logon_t, 13, "LNT-%08X", (uint32)newpwd->logon_time);
+ slprintf(logoff_t, 13, "LOT-%08X", (uint32)newpwd->logoff_time);
+ slprintf(kickoff_t, 13, "KOT-%08X", (uint32)newpwd->kickoff_time);
+ slprintf(pwdlset_t, 13, "LCT-%08X", (uint32)newpwd->pass_last_set_time);
+ slprintf(pwdlchg_t, 13, "CCT-%08X", (uint32)newpwd->pass_can_change_time);
+ slprintf(pwdmchg_t, 13, "MCT-%08X", (uint32)newpwd->pass_must_change_time);
+
+ slprintf(uid, sizeof(uid)-1, "%u", newpwd->smb_userid);
+ slprintf(user_rid, sizeof(user_rid)-1, "0x%x", newpwd->user_rid);
+ slprintf(smb_grpid, sizeof(smb_grpid)-1, "%u", newpwd->smb_grpid);
+ slprintf(group_rid, sizeof(group_rid)-1, "0x%x", newpwd->group_rid);
+
+ safe_strcpy(acb, smbpasswd_encode_acct_ctrl(newpwd->acct_ctrl),
+ sizeof(acb)-1);
+
+ set_single_attribute(&new_obj, NPF_NAME , newpwd->smb_name , strlen(newpwd->smb_name) , 0);
+ set_single_attribute(&new_obj, NPF_UID , uid , strlen(uid) , 0);
+ set_single_attribute(&new_obj, NPF_USER_RID , user_rid , strlen(user_rid) , 0);
+ set_single_attribute(&new_obj, NPF_SMB_GRPID , smb_grpid , strlen(smb_grpid) , 0);
+ set_single_attribute(&new_obj, NPF_GROUP_RID , group_rid , strlen(group_rid) , 0);
+ set_single_attribute(&new_obj, NPF_ACB , acb , strlen(acb) , 0);
+ set_single_attribute(&new_obj, NPF_LMPWD , smb_passwd , strlen(smb_passwd) , EN_CRYPT);
+ set_single_attribute(&new_obj, NPF_NTPWD , smb_nt_passwd , strlen(smb_nt_passwd) , EN_CRYPT);
+ set_single_attribute(&new_obj, NPF_LOGON_T , logon_t , strlen(logon_t) , 0);
+ set_single_attribute(&new_obj, NPF_LOGOFF_T , logoff_t , strlen(logoff_t) , 0);
+ set_single_attribute(&new_obj, NPF_KICK_T , kickoff_t , strlen(kickoff_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDLSET_T , pwdlset_t , strlen(pwdlset_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDLCHG_T , pwdlchg_t , strlen(pwdlchg_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDMCHG_T , pwdmchg_t , strlen(pwdmchg_t) , 0);
+#if 0
+ set_single_attribute(&new_obj, NPF_FULL_NAME , newpwd->full_name , strlen(newpwd->full_name) , 0);
+ set_single_attribute(&new_obj, NPF_HOME_DIR , newpwd->home_dir , strlen(newpwd->home_dir) , 0);
+ set_single_attribute(&new_obj, NPF_DIR_DRIVE , newpwd->dir_drive , strlen(newpwd->dir_drive) , 0);
+ set_single_attribute(&new_obj, NPF_LOGON_SCRIPT , newpwd->logon_script , strlen(newpwd->logon_script) , 0);
+ set_single_attribute(&new_obj, NPF_PROFILE_PATH , newpwd->profile_path , strlen(newpwd->profile_path) , 0);
+ set_single_attribute(&new_obj, NPF_ACCT_DESC , newpwd->acct_desc , strlen(newpwd->acct_desc) , 0);
+ set_single_attribute(&new_obj, NPF_WORKSTATIONS , newpwd->workstations , strlen(newpwd->workstations) , 0);
+ set_single_attribute(&new_obj, NPF_HOURS , newpwd->hours , newpwd->hours_len , 0);
+#endif
+
+ obj = &new_obj;
+
+ addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+
+ if (addresult->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "add_nisp21pwd_entry: NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(tblresult);
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(tblresult);
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startnisppwent()/
+ getnisppwent()/endnisppwent() 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
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
+{
+ char *oldnislmpwd, *oldnisntpwd, *oldnisacb, *oldnislct, *user_name;
+ char lmpwd[33], ntpwd[33], lct[13];
+ nis_result *result, *addresult;
+ nis_object *obj;
+ fstring acb;
+ pstring nisname;
+ BOOL got_pass_last_set_time, ret;
+ int i;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("mod_getnisp21pwd_entry: no SMB password file set\n"));
+ return False;
+ }
+
+ DEBUG(10, ("mod_getnisp21pwd_entry: search by name: %s\n", pwd->smb_name));
+ DEBUG(10, ("mod_getnisp21pwd_entry: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", pwd->smb_name, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("mod_getnisp21pwd_entry: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("mod_getnisp21pwd_entry: user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ DEBUG(6,("mod_getnisp21pwd_entry: entry exists\n"));
+
+ obj = NIS_RES_OBJECT(result);
+
+ user_name = ENTRY_VAL(obj, NPF_NAME);
+ oldnislmpwd = ENTRY_VAL(obj, NPF_LMPWD);
+ oldnisntpwd = ENTRY_VAL(obj, NPF_NTPWD);
+ oldnisacb = ENTRY_VAL(obj, NPF_ACB);
+ oldnislct = ENTRY_VAL(obj, NPF_PWDLSET_T);
+
+
+ if (!override && (*oldnislmpwd == '*' || *oldnislmpwd == 'X' ||
+ *oldnisntpwd == '*' || *oldnisntpwd == 'X')) {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("mod_nisp21pwd_entry: entry invalidated for user %s\n", user_name));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (strlen(oldnislmpwd) != 32 || strlen(oldnisntpwd) != 32) {
+ DEBUG(0, ("mod_nisp21pwd_entry: malformed password entry (incorrect length)\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+
+ /*
+ * If both NT and lanman passwords are provided - reset password
+ * not required flag.
+ */
+
+ if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
+ /* Require password in the future (should ACB_DISABLED also be reset?) */
+ pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
+ }
+
+ if (*oldnisacb == '[') {
+
+ i = 0;
+ acb[i++] = oldnisacb[i];
+ while(i < (sizeof(fstring) - 2) && (oldnisacb[i] != ']'))
+ acb[i] = oldnisacb[i++];
+
+ acb[i++] = ']';
+ acb[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(acb, smbpasswd_encode_acct_ctrl(pwd->acct_ctrl));
+ } else {
+ /*
+ * If using the old format and the ACB_DISABLED or
+ * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
+ * here as we have no space to encode the change.
+ */
+ if(pwd->acct_ctrl & (ACB_DISABLED|ACB_PWNOTREQ)) {
+ pwd->smb_passwd = NULL;
+ pwd->smb_nt_passwd = NULL;
+ }
+ }
+
+ /* Now do the LCT stuff. */
+ if (StrnCaseCmp(oldnislct, "LCT-", 4) == 0) {
+
+ for(i = 0; i < 8; i++) {
+ if(oldnislct[i+4] == '\0' || !isxdigit(oldnislct[i+4]))
+ 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 */
+ } /* StrnCaseCmp() */
+
+ } /* 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(&lmpwd[i*2], 32, "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(lmpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(lmpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ /* Add on the NT md4 hash */
+ if (pwd->smb_nt_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ntpwd[i*2], 32, "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(ntpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(ntpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ pwd->pass_last_set_time = time(NULL);
+
+ if(got_pass_last_set_time) {
+ slprintf(lct, 13, "LCT-%08X", (uint32)pwd->pass_last_set_time);
+ }
+
+ set_single_attribute(obj, NPF_LMPWD, lmpwd, strlen(lmpwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_NTPWD, ntpwd, strlen(ntpwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
+ set_single_attribute(obj, NPF_PWDLSET_T, lct, strlen(lct), 0);
+
+ addresult =
+ nis_add_entry(lp_smb_passwd_file(), obj,
+ ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ if(addresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("mod_nisp21pwd_entry: NIS+ table update failed: %s %s\n", nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ DEBUG(6,("mod_nisp21pwd_entry: password changed\n"));
+
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwnam(char *name)
+{
+ /* Static buffers we will return. */
+ static struct sam_passwd pw_buf;
+ nis_result *result;
+ pstring nisname;
+ BOOL ret;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return NULL;
+ }
+
+ DEBUG(10, ("getnisp21pwnam: search by name: %s\n", name));
+ DEBUG(10, ("getnisp21pwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", name, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("getnisp21pwnam: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+
+ ret = make_sam_from_nisresult(&pw_buf, result);
+ nis_freeresult(result);
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwrid(uint32 rid)
+{
+ /* Static buffers we will return. */
+ static struct sam_passwd pw_buf;
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("getnisp21pwrid: no SMB password file set\n"));
+ return NULL;
+ }
+
+ DEBUG(10, ("getnisp21pwrid: search by rid: %x\n", rid));
+ DEBUG(10, ("getnisp21pwrid: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ nisname = make_nisname_from_user_rid(rid, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("getnisp21pwrid: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+
+ ret = make_sam_from_nisresult(&pw_buf, result);
+ nis_freeresult(result);
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*
+ * Derived functions for NIS+.
+ */
+
+static struct smb_passwd *getnisppwent(void *vp)
+{
+ return pdb_sam_to_smb(getnisp21pwent(vp));
+}
+
+static BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
+{
+ return add_nisp21pwd_entry(pdb_smb_to_sam(newpwd));
+}
+
+static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override);
+}
+
+static BOOL del_nisppwd_entry(const char *name)
+{
+ return False; /* Dummy. */
+}
+
+static struct smb_passwd *getnisppwnam(char *name)
+{
+ return pdb_sam_to_smb(getnisp21pwnam(name));
+}
+
+static struct sam_passwd *getnisp21pwuid(uid_t smb_userid)
+{
+ return getnisp21pwrid(pdb_uid_to_user_rid(smb_userid));
+}
+
+static struct smb_passwd *getnisppwrid(uint32 user_rid)
+{
+ return pdb_sam_to_smb(getnisp21pwuid(pdb_user_rid_to_uid(user_rid)));
+}
+
+static struct smb_passwd *getnisppwuid(uid_t smb_userid)
+{
+ return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
+}
+
+static struct passdb_ops nispasswd_ops = {
+ startnisppwent,
+ endnisppwent,
+ getnisppwpos,
+ setnisppwpos,
+ getnisppwnam,
+ getnisppwuid,
+ getnisppwrid,
+ getnisppwent,
+ add_nisppwd_entry,
+ mod_nisppwd_entry,
+ del_nisppwd_entry,
+ getnisp21pwent,
+ getnisp21pwnam,
+ getnisp21pwuid,
+ getnisp21pwrid,
+ add_nisp21pwd_entry,
+ mod_nisp21pwd_entry
+};
+
+struct passdb_ops *nisplus_initialize_password_db(void)
+{
+ return &nispasswd_ops;
+}
+
+#else
+ void nisplus_dummy_function(void);
+ void nisplus_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_NISPLUS */
+
+/* useful code i can't bring myself to delete */
+#if 0
+static void useful_code(void) {
+ /* checks user in unix password database. don't want to do that, here. */
+ nisname = make_nisname_from_name(newpwd->smb_name, "passwd.org_dir");
+
+ nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
+ {
+ DEBUG(3, ("useful_code: Unable to get NIS+ passwd entry for user: %s.\n",
+ nis_sperrno(nis_user->status)));
+ return False;
+ }
+
+ user_obj = NIS_RES_OBJECT(nis_user);
+ make_nisname_from_name(ENTRY_VAL(user_obj,0), pfile);
+}
+#endif
diff --git a/source/passdb/pampass.c b/source/passdb/pampass.c
new file mode 100644
index 00000000000..018eae3a07e
--- /dev/null
+++ b/source/passdb/pampass.c
@@ -0,0 +1,892 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+ PAM Password checking
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) John H Terpsta 1999-2001
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 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.
+*/
+
+/*
+ * This module provides PAM based functions for validation of
+ * username/password pairs, account managment, session and access control.
+ * Note: SMB password checking is done in smbpass.c
+ */
+
+#include "includes.h"
+
+#ifdef WITH_PAM
+
+/*******************************************************************
+ * Handle PAM authentication
+ * - Access, Authentication, Session, Password
+ * Note: See PAM Documentation and refer to local system PAM implementation
+ * which determines what actions/limitations/allowances become affected.
+ *********************************************************************/
+
+#include <security/pam_appl.h>
+
+/*
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
+ */
+
+struct smb_pam_userdata {
+ const char *PAM_username;
+ const char *PAM_password;
+ const char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
+
+/*
+ * Macros to help make life easy
+ */
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
+static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
+{
+
+ if( pam_error != PAM_SUCCESS) {
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
+
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ char *msg, int dbglvl,
+ NTSTATUS *nt_status)
+{
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (NT_STATUS_IS_OK(*nt_status)) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
+/*
+ * PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ memset(reply, '\0', sizeof(struct pam_response) * num_msg);
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static void special_char_sub(char *buf)
+{
+ all_string_sub(buf, "\\n", "", 0);
+ all_string_sub(buf, "\\r", "", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass)
+{
+ pstring_sub(buf, "%u", username);
+ all_string_sub(buf, "%o", oldpass, sizeof(fstring));
+ all_string_sub(buf, "%n", newpass, sizeof(fstring));
+}
+
+
+struct chat_struct {
+ struct chat_struct *next, *prev;
+ fstring prompt;
+ fstring reply;
+};
+
+/**************************************************************
+ Create a linked list containing chat data.
+***************************************************************/
+
+static struct chat_struct *make_pw_chat(char *p)
+{
+ fstring prompt;
+ fstring reply;
+ struct chat_struct *list = NULL;
+ struct chat_struct *t;
+ struct chat_struct *tmp;
+
+ while (1) {
+ t = (struct chat_struct *)malloc(sizeof(*t));
+ if (!t) {
+ DEBUG(0,("make_pw_chat: malloc failed!\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(list, t, tmp);
+
+ if (!next_token(&p, prompt, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(prompt,"."))
+ fstrcpy(prompt,"*");
+
+ special_char_sub(prompt);
+ fstrcpy(t->prompt, prompt);
+ strlower(t->prompt);
+ trim_string(t->prompt, " ", " ");
+
+ if (!next_token(&p, reply, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(reply,"."))
+ fstrcpy(reply,"");
+
+ special_char_sub(reply);
+ fstrcpy(t->reply, reply);
+ strlower(t->reply);
+ trim_string(t->reply, " ", " ");
+
+ }
+ return list;
+}
+
+static void free_pw_chat(struct chat_struct *list)
+{
+ while (list) {
+ struct chat_struct *old_head = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
+}
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring current_prompt;
+ fstring current_reply;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+ struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());
+ struct chat_struct *t;
+ BOOL found;
+ *resp = NULL;
+
+ DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ if (pw_chat == NULL)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) {
+ DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ for (replies = 0; replies < num_msg; replies++) {
+ found = False;
+ DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));
+#endif
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));
+#endif
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ free_pw_chat(pw_chat);
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ SAFE_FREE(pconv->appdata_ptr);
+
+ SAFE_FREE(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,
+ const char *passwd, const char *newpass)
+{
+ struct pam_conv *pconv = (struct pam_conv *)malloc(sizeof(struct pam_conv));
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)malloc(sizeof(struct smb_pam_userdata));
+
+ if (pconv == NULL || udp == NULL) {
+ SAFE_FREE(pconv);
+ SAFE_FREE(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
+
+/*
+ * PAM Closing out cleanup handler
+ */
+
+static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
+{
+ int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
+
+ if( pamh != NULL ) {
+ pam_error = pam_end(pamh, 0);
+ if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
+ return True;
+ }
+ }
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
+ return False;
+}
+
+/*
+ * Start PAM authentication for specified account
+ */
+
+static BOOL smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv)
+{
+ int pam_error;
+ const char *our_rhost;
+
+ *pamh = (pam_handle_t *)NULL;
+
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
+
+ pam_error = pam_start("samba", user, pconv, pamh);
+ if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+
+ if (rhost == NULL) {
+ our_rhost = client_name();
+ if (strequal(rhost,"UNKNOWN"))
+ our_rhost = client_addr();
+ } else {
+ our_rhost = rhost;
+ }
+
+#ifdef PAM_RHOST
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", our_rhost));
+ pam_error = pam_set_item(*pamh, PAM_RHOST, our_rhost);
+ if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+#ifdef PAM_TTY
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
+ pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
+ if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
+ return True;
+}
+
+/*
+ * PAM Authentication Handler
+ */
+static NTSTATUS smb_pam_auth(pam_handle_t *pamh, char *user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+
+ /*
+ * To enable debugging set in /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ */
+
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
+ switch( pam_error ){
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+ nt_status = NT_STATUS_WRONG_PASSWORD;
+ break;
+ case PAM_CRED_INSUFFICIENT:
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
+ break;
+ case PAM_AUTHINFO_UNAVAIL:
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_MAXTRIES:
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
+ break;
+ case PAM_ABORT:
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Account Handler
+ */
+static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
+ switch( pam_error ) {
+ case PAM_AUTHTOK_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_ACCT_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ nt_status = NT_STATUS_ACCOUNT_EXPIRED;
+ break;
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_NO_TOKEN;
+
+ /*
+ * This will allow samba to aquire a kerberos token. And, when
+ * exporting an AFS cell, be able to /write/ to this cell.
+ */
+
+ DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
+ pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
+ switch( pam_error ) {
+ case PAM_CRED_UNAVAIL:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ case PAM_CRED_EXPIRED:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_CRED_ERR:
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Internal Session Handler
+ */
+static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
+{
+ int pam_error;
+
+#ifdef PAM_TTY
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
+ pam_error = pam_set_item(pamh, PAM_TTY, tty);
+ if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+ return False;
+#endif
+
+ if (flag) {
+ pam_error = pam_open_session(pamh, PAM_SILENT);
+ if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+ return False;
+ } else {
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
+ if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+ return False;
+ }
+ return (True);
+}
+
+/*
+ * Internal PAM Password Changer.
+ */
+
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+
+ /* This doesn't seem to be defined on Solaris. JRA */
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+#endif
+
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Account handler
+ */
+
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_OK;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user)))
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+NTSTATUS smb_pam_passcheck(char * user, char * password)
+{
+ pam_handle_t *pamh = NULL;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
+
+ /*
+ * Note we can't ignore PAM here as this is the only
+ * way of doing auths on plaintext passwords when
+ * compiled --with-pam.
+ */
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_setcred(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+BOOL smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+#else
+
+/* If PAM not used, no PAM restrictions on accounts. */
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ return NT_STATUS_OK;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ return True;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_close_session(char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
+#endif /* WITH_PAM */
diff --git a/source/passdb/pass_check.c b/source/passdb/pass_check.c
new file mode 100644
index 00000000000..77839e4bb0c
--- /dev/null
+++ b/source/passdb/pass_check.c
@@ -0,0 +1,776 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password checking
+ Copyright (C) Andrew Tridgell 1992-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.
+*/
+
+/* this module is for checking a username/password against a system
+ password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+/* these are kept here to keep the string_combinations function simple */
+static fstring this_user;
+#if !defined(WITH_PAM)
+static fstring this_salt;
+static fstring this_crypted;
+#endif
+
+#ifdef WITH_AFS
+
+#include <afs/stds.h>
+#include <afs/kautils.h>
+
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static BOOL afs_auth(char *user, char *password)
+{
+ long password_expires = 0;
+ char *reason;
+
+ /* For versions of AFS prior to 3.3, this routine has few arguments, */
+ /* but since I can't find the old documentation... :-) */
+ setpag();
+ if (ka_UserAuthenticateGeneral
+ (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
+ (char *)0, /* cell */
+ password, 0, /* lifetime, default */
+ &password_expires, /*days 'til it expires */
+ 0, /* spare 2 */
+ &reason) == 0)
+ {
+ return (True);
+ }
+ DEBUG(1,
+ ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
+ return (False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+#include <dce/dce_error.h>
+#include <dce/sec_login.h>
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+ - Server credentials may expire
+ - Client credential cache files have wrong owner
+ - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static BOOL dfs_auth(char *user, char *password)
+{
+ error_status_t err;
+ int err2;
+ int prterr;
+ signed32 expire_time, current_time;
+ boolean32 password_reset;
+ struct passwd *pw;
+ sec_passwd_rec_t passwd_rec;
+ sec_login_auth_src_t auth_src = sec_login_auth_src_network;
+ unsigned char dce_errstr[dce_c_error_string_len];
+ gid_t egid;
+
+ if (dcelogin_atmost_once)
+ return (False);
+
+#ifdef HAVE_CRYPT
+ /*
+ * We only go for a DCE login context if the given password
+ * matches that stored in the local password file..
+ * Assumes local passwd file is kept in sync w/ DCE RGY!
+ */
+
+ if (strcmp((char *)crypt(password, this_salt), this_crypted))
+ {
+ return (False);
+ }
+#endif
+
+ sec_login_get_current_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ time(&current_time);
+
+ if (expire_time < (current_time + 60))
+ {
+ struct passwd *pw;
+ sec_passwd_rec_t *key;
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_refresh_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't refresh identity. %s\n",
+ dce_errstr));
+
+ return (False);
+ }
+
+ sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
+ (unsigned char *)pw->pw_name,
+ sec_c_key_version_none,
+ (void **)&key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get key for %s. %s\n",
+ pw->pw_name, dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_valid_and_cert_ident(my_dce_sec_context, key,
+ &password_reset, &auth_src,
+ &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE can't validate and certify identity for %s. %s\n",
+ pw->pw_name, dce_errstr));
+ }
+
+ sec_key_mgmt_free_key(key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't free key.\n", dce_errstr));
+ }
+ }
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ return (False);
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ /*
+ * NB. I'd like to change these to call something like change_to_user()
+ * instead but currently we don't have a connection
+ * context to become the correct user. This is already
+ * fairly platform specific code however, so I think
+ * this should be ok. I have added code to go
+ * back to being root on error though. JRA.
+ */
+
+ egid = getegid();
+
+ set_effective_gid(pw->pw_gid);
+ set_effective_uid(pw->pw_uid);
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ passwd_rec.version_number = sec_passwd_c_version_none;
+ passwd_rec.pepper = NULL;
+ passwd_rec.key.key_type = sec_passwd_plain;
+ passwd_rec.key.tagged_union.plain = (idl_char *) password;
+
+ sec_login_validate_identity(my_dce_sec_context,
+ &passwd_rec, &password_reset,
+ &auth_src, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE Identity Validation failed for principal %s: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
+ goto err;
+ }
+
+ if (auth_src != sec_login_auth_src_network)
+ {
+ DEBUG(0, ("DCE context has no network credentials.\n"));
+ }
+
+ sec_login_set_context(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE login failed for principal %s, cant set context: %s\n",
+ user, dce_errstr));
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
+ user, sys_getpid()));
+
+ DEBUG(3, ("DCE principal: %s\n"
+ " uid: %d\n"
+ " gid: %d\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid));
+ DEBUG(3, (" info: %s\n"
+ " dir: %s\n"
+ " shell: %s\n",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell));
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+ goto err;
+ }
+
+ set_effective_uid(0);
+ set_effective_gid(0);
+
+ DEBUG(0,
+ ("DCE context expires: %s", asctime(localtime(&expire_time))));
+
+ dcelogin_atmost_once = 1;
+ return (True);
+
+ err:
+
+ /* Go back to root, JRA. */
+ set_effective_uid(0);
+ set_effective_gid(egid);
+ return (False);
+}
+
+void dfs_unlogin(void)
+{
+ error_status_t err;
+ int err2;
+ unsigned char dce_errstr[dce_c_error_string_len];
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE purge login context failed for server instance %d: %s\n",
+ sys_getpid(), dce_errstr));
+ }
+}
+#endif
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+static int linux_bigcrypt(char *password, char *salt1, char *crypted)
+{
+#define LINUX_PASSWORD_SEG_CHARS 8
+ char salt[3];
+ int i;
+
+ StrnCpy(salt, salt1, 2);
+ crypted += 2;
+
+ for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
+ char *p = crypt(password, salt) + 2;
+ if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
+ return (0);
+ password += LINUX_PASSWORD_SEG_CHARS;
+ crypted += strlen(p);
+ }
+
+ return (1);
+}
+#endif
+
+#ifdef OSF1_ENH_SEC
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+static char *osf1_bigcrypt(char *password, char *salt1)
+{
+ static char result[AUTH_MAX_PASSWD_LENGTH] = "";
+ char *p1;
+ char *p2 = password;
+ char salt[3];
+ int i;
+ int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
+ if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
+ parts++;
+
+ StrnCpy(salt, salt1, 2);
+ StrnCpy(result, salt1, 2);
+ result[2] = '\0';
+
+ for (i = 0; i < parts; i++) {
+ p1 = crypt(p2, salt);
+ strncat(result, p1 + 2,
+ AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
+ StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
+ p2 += AUTH_CLEARTEXT_SEG_CHARS;
+ }
+
+ return (result);
+}
+#endif
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (char *),
+ int N)
+{
+ int len = strlen(s);
+ int i;
+ NTSTATUS nt_status;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len, PASSWORD_LENGTH);
+#endif
+
+ if (N <= 0 || offset >= len)
+ return (fn(s));
+
+ for (i = offset; i < (len - (N - 1)); i++) {
+ char c = s[i];
+ if (!islower(c))
+ continue;
+ s[i] = toupper(c);
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
+ return (nt_status);
+ }
+ s[i] = c;
+ }
+ return (NT_STATUS_WRONG_PASSWORD);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (char *), int N)
+{
+ int n;
+ NTSTATUS nt_status;
+ for (n = 1; n <= N; n++)
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
+ return nt_status;
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static NTSTATUS password_check(char *password)
+{
+#ifdef WITH_PAM
+ return smb_pam_passcheck(this_user, password);
+#else
+
+ BOOL ret;
+
+#ifdef WITH_AFS
+ if (afs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_AFS */
+
+#ifdef WITH_DFS
+ if (dfs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_DFS */
+
+#ifdef OSF1_ENH_SEC
+
+ ret = (strcmp(osf1_bigcrypt(password, this_salt),
+ this_crypted) == 0);
+ if (!ret) {
+ DEBUG(2,
+ ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ }
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* OSF1_ENH_SEC */
+
+#ifdef ULTRIX_AUTH
+ ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* ULTRIX_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+ ret = (linux_bigcrypt(password, this_salt, this_crypted));
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* LINUX_BIGCRYPT */
+
+#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
+
+ /*
+ * Some systems have bigcrypt in the C library but might not
+ * actually use it for the password hashes (HPUX 10.20) is
+ * a noteable example. So we try bigcrypt first, followed
+ * by crypt.
+ */
+
+ if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
+ return NT_STATUS_OK;
+ else
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+
+#ifdef HAVE_BIGCRYPT
+ ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_BIGCRYPT */
+
+#ifndef HAVE_CRYPT
+ DEBUG(1, ("Warning - no crypt available\n"));
+ return NT_STATUS_LOGON_FAILURE;
+#else /* HAVE_CRYPT */
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_CRYPT */
+#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+#endif /* WITH_PAM || KRB4_AUTH || KRB5_AUTH */
+}
+
+
+
+/****************************************************************************
+CHECK if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file
+return NT_STATUS_OK on correct match, appropriate error otherwise
+****************************************************************************/
+
+NTSTATUS pass_check(struct passwd *pass, char *user, char *password,
+ int pwlen, BOOL (*fn) (char *, char *), BOOL run_cracker)
+{
+ pstring pass2;
+ int level = lp_passwordlevel();
+
+ NTSTATUS nt_status;
+ if (password)
+ password[pwlen] = 0;
+
+#if DEBUG_PASSWORD
+ DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
+#endif
+
+ if (!password)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (((!*password) || (!pwlen)) && !lp_null_passwords())
+ return NT_STATUS_LOGON_FAILURE;
+
+#if defined(WITH_PAM)
+
+ /*
+ * If we're using PAM we want to short-circuit all the
+ * checks below and dive straight into the PAM code.
+ */
+
+ fstrcpy(this_user, user);
+
+ DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
+
+#else /* Not using PAM or Kerebos */
+
+ DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
+
+ if (!pass) {
+ DEBUG(3, ("Couldn't find user %s\n", user));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+#ifdef HAVE_GETSPNAM
+ {
+ struct spwd *spass;
+
+ /* many shadow systems require you to be root to get
+ the password, in most cases this should already be
+ the case when this function is called, except
+ perhaps for IPC password changing requests */
+
+ spass = getspnam(pass->pw_name);
+ if (spass && spass->sp_pwdp)
+ pstrcpy(pass->pw_passwd, spass->sp_pwdp);
+ }
+#elif defined(IA_UINFO)
+ {
+ /* Need to get password with SVR4.2's ia_ functions
+ instead of get{sp,pw}ent functions. Required by
+ UnixWare 2.x, tested on version
+ 2.1. (tangent@cyberport.com) */
+ uinfo_t uinfo;
+ if (ia_openinfo(pass->pw_name, &uinfo) != -1)
+ ia_get_logpwd(uinfo, &(pass->pw_passwd));
+ }
+#endif
+
+#ifdef HAVE_GETPRPWNAM
+ {
+ struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
+ if (pr_pw && pr_pw->ufld.fd_encrypt)
+ pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
+ }
+#endif
+
+#ifdef OSF1_ENH_SEC
+ {
+ struct pr_passwd *mypasswd;
+ DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
+ user));
+ mypasswd = getprpwnam(user);
+ if (mypasswd) {
+ fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
+ fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
+ } else {
+ DEBUG(5,
+ ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
+ user));
+ }
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ {
+ AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+ if (ap) {
+ fstrcpy(pass->pw_passwd, ap->a_password);
+ endauthent();
+ }
+ }
+#endif
+
+ /* extract relevant info */
+ fstrcpy(this_salt, pass->pw_passwd);
+
+#if defined(HAVE_TRUNCATED_SALT)
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ this_salt[2] = 0;
+#endif
+
+ fstrcpy(this_crypted, pass->pw_passwd);
+
+ if (!*this_crypted) {
+ if (!lp_null_passwords()) {
+ DEBUG(2, ("Disallowing %s with null password\n",
+ this_user));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ if (!*password) {
+ DEBUG(3,
+ ("Allowing access to %s with null password\n",
+ this_user));
+ return NT_STATUS_OK;
+ }
+ }
+
+#endif /* defined(WITH_PAM) */
+
+ /* try it as it came to us */
+ nt_status = password_check(password);
+ if NT_STATUS_IS_OK(nt_status) {
+ if (fn) {
+ fn(user, password);
+ }
+ return (nt_status);
+ } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+ return (nt_status);
+ }
+
+ if (!run_cracker) {
+ return (nt_status);
+ }
+
+ /* if the password was given to us with mixed case then we don't
+ * need to proceed as we know it hasn't been case modified by the
+ * client */
+ if (strhasupper(password) && strhaslower(password)) {
+ return nt_status;
+ }
+
+ /* make a copy of it */
+ StrnCpy(pass2, password, sizeof(pstring) - 1);
+
+ /* try all lowercase if it's currently all uppercase */
+ if (strhasupper(password)) {
+ strlower(password);
+ if NT_STATUS_IS_OK(nt_status = password_check(password)) {
+ if (fn)
+ fn(user, password);
+ return (nt_status);
+ }
+ }
+
+ /* give up? */
+ if (level < 1) {
+ /* restore it */
+ fstrcpy(password, pass2);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower(password);
+
+
+ if NT_STATUS_IS_OK(nt_status = string_combinations(password, password_check, level)) {
+ if (fn)
+ fn(user, password);
+ return nt_status;
+ }
+
+ /* restore it */
+ fstrcpy(password, pass2);
+
+ return NT_STATUS_WRONG_PASSWORD;
+}
diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c
new file mode 100644
index 00000000000..fa4946b0930
--- /dev/null
+++ b/source/passdb/passdb.c
@@ -0,0 +1,1813 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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
+
+ 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;
+
+struct passdb_ops *pdb_ops;
+
+#if 0 /* JERRY */
+static void* pdb_handle = NULL;
+#endif
+
+/***************************************************************
+ Initialize the password db operations.
+***************************************************************/
+
+BOOL initialize_password_db(BOOL reload)
+{
+ /*
+ * This function is unfinished right now, so just
+ * ignore the details and always return True. It
+ * is here only as a placeholder --jerry
+ */
+ return True;
+
+}
+
+
+/************************************************************
+ Fill the SAM_ACCOUNT with default values.
+ ***********************************************************/
+
+static BOOL pdb_fill_default_sam(SAM_ACCOUNT *user)
+{
+ if (user == NULL) {
+ DEBUG(0,("pdb_fill_default_sam: SAM_ACCOUNT was NULL\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(user);
+
+ /* Don't change these timestamp settings without a good reason.
+ They are important for NT member server compatibility. */
+
+ user->logon_time = (time_t)0;
+ user->pass_last_set_time = (time_t)0;
+ user->pass_can_change_time = (time_t)0;
+ user->logoff_time =
+ user->kickoff_time =
+ user->pass_must_change_time = get_time_t_max();
+ user->unknown_3 = 0x00ffffff; /* don't know */
+ user->logon_divs = 168; /* hours per week */
+ user->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->hours, 0xff, user->hours_len); /* available at all hours */
+ user->unknown_5 = 0x00000000; /* don't know */
+ user->unknown_6 = 0x000004ec; /* don't know */
+ return True;
+}
+
+
+/*************************************************************
+ Alloc memory and initialises a struct sam_passwd.
+ ************************************************************/
+
+BOOL pdb_init_sam(SAM_ACCOUNT **user)
+{
+ if (*user != NULL) {
+ DEBUG(0,("pdb_init_sam: SAM_ACCOUNT was non NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_init_sam\n");
+#endif
+ return False;
+ }
+
+ *user=(SAM_ACCOUNT *)malloc(sizeof(SAM_ACCOUNT));
+
+ if (*user==NULL) {
+ DEBUG(0,("pdb_init_sam: error while allocating memory\n"));
+ return False;
+ }
+
+ pdb_fill_default_sam(*user);
+
+ return True;
+}
+
+
+/*************************************************************
+ Initialises a struct sam_passwd with sane values.
+ ************************************************************/
+
+BOOL pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd)
+{
+ pstring str;
+ GROUP_MAP map;
+ uint32 rid;
+
+ if (!pwd) {
+ new_sam_acct = NULL;
+ return False;
+ }
+
+ if (!pdb_init_sam(new_sam_acct)) {
+ new_sam_acct = NULL;
+ return False;
+ }
+
+ 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);
+
+ pdb_set_user_rid(*new_sam_acct, pdb_uid_to_user_rid(pwd->pw_uid));
+
+ /* 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ return True;
+}
+
+
+/************************************************************
+ Free the NT/LM hashes only.
+ ***********************************************************/
+
+static BOOL pdb_free_sam_contents(SAM_ACCOUNT *user)
+{
+ if (user == NULL) {
+ DEBUG(0,("pdb_free_sam_contents: SAM_ACCOUNT was NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_free_sam_contents\n");
+#endif
+ return False;
+ }
+
+ /* As we start mallocing more strings this is where
+ we should free them. */
+
+ SAFE_FREE(user->nt_pw);
+ SAFE_FREE(user->lm_pw);
+
+ SAFE_FREE(user->uid);
+ SAFE_FREE(user->gid);
+
+ return True;
+}
+
+
+/************************************************************
+ Reset the SAM_ACCOUNT and free the NT/LM hashes.
+ - note: they are not zero'ed out however.
+ ***********************************************************/
+
+BOOL 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 False;
+ }
+
+ if (!pdb_free_sam_contents(user)) {
+ return False;
+ }
+
+ if (!pdb_fill_default_sam(user)) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/************************************************************
+ Free the SAM_ACCOUNT and the NT/LM hashes.
+ ***********************************************************/
+
+BOOL 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 False;
+ }
+
+ if (!pdb_free_sam_contents(*user)) {
+ return False;
+ }
+
+ SAFE_FREE(*user);
+
+ return True;
+}
+
+
+/**********************************************************
+ 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);
+}
+
+/*******************************************************************
+ 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 = 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;
+}
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+
+/*******************************************************************
+ 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 UNIX uid to an NT User RID.
+ ********************************************************************/
+
+uint32 pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ 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;
+
+ 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) {
+ pstring admin_users;
+ char *p = admin_users;
+ *psid_name_use = SID_NAME_USER;
+ if(!next_token(&p, name, NULL, sizeof(fstring)))
+ fstrcpy(name, "Administrator");
+ } else if (rid == DOMAIN_USER_RID_GUEST) {
+ pstring guest_users;
+ char *p = guest_users;
+ *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;
+
+ uid = pdb_user_rid_to_uid(rid);
+ pass = sys_getpwuid(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 ));
+ }
+
+ } 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_domain, 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;
+ fstring domain;
+
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ /*
+ * domain and user may be quoted const strings, and map_username and
+ * friends can modify them. Make a modifiable copy. JRA.
+ */
+
+ fstrcpy(domain, c_domain);
+ 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((pass = Get_Pwnam(user))) {
+ sid_append_rid( &local_sid, pdb_uid_to_user_rid(pass->pw_uid));
+ *psid_name_use = SID_NAME_USER;
+ } else {
+ /*
+ * Maybe it was a group ?
+ */
+ struct group *grp;
+ GROUP_MAP map;
+
+ /* 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;
+
+ sid_copy(psid, &global_sam_sid);
+ sid_append_rid(psid, pdb_uid_to_user_rid(uid));
+
+ 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;
+
+ *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;
+
+ *puid = pdb_user_rid_to_uid(rid);
+
+ /*
+ * Ensure this uid really does exist.
+ */
+ if(!(pass = sys_getpwuid(*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 ));
+
+ *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, pgid);
+ *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;
+}
+
+static void select_name(pstring string, const UNISTR2 *from)
+{
+ if (from->buffer != 0)
+ unistr2_to_ascii(string, from, sizeof(pstring));
+}
+
+/*************************************************************
+ 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;
+
+ to->logon_time = nt_time_to_unix(&from->logon_time);
+ to->logoff_time = nt_time_to_unix(&from->logoff_time);
+ to->kickoff_time = nt_time_to_unix(&from->kickoff_time);
+ to->pass_last_set_time = nt_time_to_unix(&from->pass_last_set_time);
+ to->pass_can_change_time = nt_time_to_unix(&from->pass_can_change_time);
+ to->pass_must_change_time = nt_time_to_unix(&from->pass_must_change_time);
+
+ select_name(to->username , &from->uni_user_name );
+ select_name(to->full_name , &from->uni_full_name );
+ select_name(to->home_dir , &from->uni_home_dir );
+ select_name(to->dir_drive , &from->uni_dir_drive );
+ select_name(to->logon_script, &from->uni_logon_script);
+ select_name(to->profile_path, &from->uni_profile_path);
+ select_name(to->acct_desc , &from->uni_acct_desc );
+ select_name(to->workstations, &from->uni_workstations);
+ select_name(to->unknown_str , &from->uni_unknown_str );
+ select_name(to->munged_dial , &from->uni_munged_dial );
+
+ if (from->user_rid)
+ to->user_rid = from->user_rid;
+ if (from->group_rid)
+ to->group_rid = from->group_rid;
+
+ to->acct_ctrl = from->acb_info;
+ to->unknown_3 = from->unknown_3;
+
+ to->logon_divs = from->logon_divs;
+ to->hours_len = from->logon_hrs.len;
+ memcpy(to->hours, from->logon_hrs.hours, MAX_HOURS_LEN);
+
+ to->unknown_5 = from->unknown_5;
+ to->unknown_6 = 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;
+
+ to->logon_time = nt_time_to_unix(&from->logon_time);
+ to->logoff_time = nt_time_to_unix(&from->logoff_time);
+ to->kickoff_time = nt_time_to_unix(&from->kickoff_time);
+ to->pass_last_set_time = nt_time_to_unix(&from->pass_last_set_time);
+ to->pass_can_change_time = nt_time_to_unix(&from->pass_can_change_time);
+ to->pass_must_change_time = nt_time_to_unix(&from->pass_must_change_time);
+
+ select_name(to->username , &from->uni_user_name );
+ select_name(to->full_name , &from->uni_full_name );
+ select_name(to->home_dir , &from->uni_home_dir );
+ select_name(to->dir_drive , &from->uni_dir_drive );
+ select_name(to->logon_script, &from->uni_logon_script);
+ select_name(to->profile_path, &from->uni_profile_path);
+ select_name(to->acct_desc , &from->uni_acct_desc );
+ select_name(to->workstations, &from->uni_workstations);
+ select_name(to->unknown_str , &from->uni_unknown_str );
+ select_name(to->munged_dial , &from->uni_munged_dial );
+
+ to->user_rid = from->user_rid;
+ to->group_rid = from->group_rid;
+
+ /* FIXME!! Do we need to copy the passwords here as well?
+ I don't know. Need to figure this out --jerry */
+
+ to->acct_ctrl = from->acb_info;
+ to->unknown_3 = from->unknown_3;
+
+ to->logon_divs = from->logon_divs;
+ to->hours_len = from->logon_hrs.len;
+ memcpy(to->hours, from->logon_hrs.hours, MAX_HOURS_LEN);
+
+ to->unknown_5 = from->unknown_5;
+ to->unknown_6 = 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) {
+ /*
+ * Check for a local account - if we're adding only.
+ */
+
+ if(!(pwd = sys_getpwnam(user_name))) {
+ slprintf(err_str, err_str_len - 1, "User %s does not \
+exist in system password file (usually /etc/passwd). Cannot add \
+account without a valid local system user.\n", user_name);
+ return False;
+ }
+ } else {
+ slprintf(err_str, err_str_len-1,"Failed to find entry for user %s.\n", user_name);
+ return False;
+ }
+
+ if (!pdb_init_sam_pw(&sam_pass, pwd)) {
+ slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
+ return False;
+ }
+
+ /* set account flags. Note that the default is non-expiring accounts */
+ /*if (!pdb_set_acct_ctrl(sam_pass,((local_flags & LOCAL_TRUST_ACCOUNT) ? ACB_WSTRUST : ACB_NORMAL|ACB_PWNOEXP) )) {*/
+ if (!pdb_set_acct_ctrl(sam_pass,((local_flags & LOCAL_TRUST_ACCOUNT) ? ACB_WSTRUST : ACB_NORMAL) )) {
+ slprintf(err_str, err_str_len-1, "Failed to set 'trust 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(user_name)) {
+ 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, True)) {
+ 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;
+}
+
+/*********************************************************************
+ Collection of get...() functions for SAM_ACCOUNT_INFO.
+ ********************************************************************/
+
+uint16 pdb_get_acct_ctrl (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->acct_ctrl);
+ else
+ return (ACB_DISABLED);
+}
+
+time_t pdb_get_logon_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_time);
+ else
+ return (0);
+}
+
+time_t pdb_get_logoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_kickoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->kickoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_last_set_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_last_set_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_can_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_can_change_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_must_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_must_change_time);
+ else
+ return (-1);
+}
+
+uint16 pdb_get_logon_divs (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_divs);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_hours_len (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->hours_len);
+ else
+ return (-1);
+}
+
+const uint8* pdb_get_hours (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->hours);
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_nt_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->nt_pw);
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->lm_pw);
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_user_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->user_rid);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_group_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->group_rid);
+ else
+ return (-1);
+}
+
+uid_t *pdb_get_uid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->uid);
+ else
+ return (NULL);
+}
+
+gid_t *pdb_get_gid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->gid);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_domain (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->domain);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_nt_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->nt_username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_fullname (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->full_name);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_homedir (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->home_dir);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_dirdrive (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->dir_drive);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_logon_script (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_script);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_profile_path (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->profile_path);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_acct_desc (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->acct_desc);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_workstations (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->workstations);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_munged_dial (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->munged_dial);
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_unknown3 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->unknown_3);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown5 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->unknown_5);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown6 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->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->acct_ctrl = flags;
+ return True;
+ }
+
+ return False;
+}
+
+BOOL pdb_set_logon_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logon_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_logoff_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logoff_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_kickoff_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->kickoff_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_can_change_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_can_change_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_must_change_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_must_change_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_last_set_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_last_set_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_hours_len (SAM_ACCOUNT *sampass, uint32 len)
+{
+ if (!sampass)
+ return False;
+
+ sampass->hours_len = len;
+ return True;
+}
+
+BOOL pdb_set_logons_divs (SAM_ACCOUNT *sampass, uint16 hours)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logon_divs = hours;
+ return True;
+}
+
+/*********************************************************************
+ Set the user's UNIX uid, as a pointer to malloc'ed memory.
+ ********************************************************************/
+
+BOOL pdb_set_uid (SAM_ACCOUNT *sampass, const uid_t *uid)
+{
+ if (!sampass)
+ return False;
+
+ if (!uid) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->uid);
+ return True;
+ }
+
+ if (sampass->uid!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: uid non NULL overwritting ?\n"));
+ else
+ sampass->uid=(uid_t *)malloc(sizeof(uid_t));
+
+ if (sampass->uid==NULL)
+ return False;
+
+ *sampass->uid = *uid;
+
+ return True;
+
+}
+
+/*********************************************************************
+ Set the user's UNIX gid, as a pointer to malloc'ed memory.
+ ********************************************************************/
+
+BOOL pdb_set_gid (SAM_ACCOUNT *sampass, const gid_t *gid)
+{
+ if (!sampass)
+ return False;
+
+ if (!gid) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->gid);
+ return True;
+ }
+
+ if (sampass->gid!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: gid non NULL overwritting ?\n"));
+ else
+ sampass->gid=(gid_t *)malloc(sizeof(gid_t));
+
+ if (sampass->gid==NULL)
+ return False;
+
+ *sampass->gid = *gid;
+
+ return True;
+
+}
+
+BOOL pdb_set_user_rid (SAM_ACCOUNT *sampass, uint32 rid)
+{
+ if (!sampass)
+ return False;
+
+ sampass->user_rid = rid;
+ return True;
+}
+
+BOOL pdb_set_group_rid (SAM_ACCOUNT *sampass, uint32 grid)
+{
+ if (!sampass)
+ return False;
+
+ sampass->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;
+ *sampass->username = '\0';
+ if (!username)
+ return False;
+
+ StrnCpy (sampass->username, username, strlen(username));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+BOOL pdb_set_domain(SAM_ACCOUNT *sampass, const char *domain)
+{
+ if (!sampass)
+ return False;
+ *sampass->domain = '\0';
+ if (!domain)
+ return False;
+
+ StrnCpy (sampass->domain, domain, strlen(domain));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT name.
+ ********************************************************************/
+
+BOOL pdb_set_nt_username(SAM_ACCOUNT *sampass, const char *nt_username)
+{
+ if (!sampass)
+ return False;
+ *sampass->nt_username = '\0';
+ if (!nt_username)
+ return False;
+
+ StrnCpy (sampass->nt_username, nt_username, strlen(nt_username));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's full name.
+ ********************************************************************/
+
+BOOL pdb_set_fullname(SAM_ACCOUNT *sampass, const char *fullname)
+{
+ if (!sampass)
+ return False;
+ *sampass->full_name = '\0';
+ if (!fullname)
+ return False;
+
+ StrnCpy (sampass->full_name, fullname, strlen(fullname));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's logon script.
+ ********************************************************************/
+
+BOOL pdb_set_logon_script(SAM_ACCOUNT *sampass, const char *logon_script)
+{
+ if (!sampass)
+ return False;
+ *sampass->logon_script = '\0';
+ if (!logon_script)
+ return False;
+
+ StrnCpy (sampass->logon_script, logon_script, strlen(logon_script));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's profile path.
+ ********************************************************************/
+
+BOOL pdb_set_profile_path (SAM_ACCOUNT *sampass, const char *profile_path)
+{
+ if (!sampass)
+ return False;
+ *sampass->profile_path = '\0';
+ if (!profile_path)
+ return False;
+
+ StrnCpy (sampass->profile_path, profile_path, strlen(profile_path));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's directory drive.
+ ********************************************************************/
+
+BOOL pdb_set_dir_drive (SAM_ACCOUNT *sampass, const char *dir_drive)
+{
+ if (!sampass)
+ return False;
+ *sampass->dir_drive = '\0';
+ if (!dir_drive)
+ return False;
+
+ StrnCpy (sampass->dir_drive, dir_drive, strlen(dir_drive));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's home directory.
+ ********************************************************************/
+
+BOOL pdb_set_homedir (SAM_ACCOUNT *sampass, const char *homedir)
+{
+ if (!sampass)
+ return False;
+ *sampass->home_dir = '\0';
+ if (!homedir)
+ return False;
+
+ StrnCpy (sampass->home_dir, homedir, strlen(homedir));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's account description.
+ ********************************************************************/
+
+BOOL pdb_set_acct_desc (SAM_ACCOUNT *sampass, const char *acct_desc)
+{
+ if (!sampass)
+ return False;
+ *sampass->acct_desc = '\0';
+ if (!acct_desc)
+ return False;
+
+ StrnCpy (sampass->acct_desc, acct_desc, strlen(acct_desc));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's workstation allowed list.
+ ********************************************************************/
+
+BOOL pdb_set_workstations (SAM_ACCOUNT *sampass, const char *workstations)
+{
+ if (!sampass)
+ return False;
+ *sampass->workstations = '\0';
+ if (!workstations)
+ return False;
+
+ StrnCpy (sampass->workstations, workstations, strlen(workstations));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's dial string.
+ ********************************************************************/
+
+BOOL pdb_set_munged_dial (SAM_ACCOUNT *sampass, const char *munged_dial)
+{
+ if (!sampass)
+ return False;
+ *sampass->munged_dial = '\0';
+ if (!munged_dial)
+ return False;
+
+ StrnCpy (sampass->munged_dial, munged_dial, strlen(munged_dial));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT hash.
+ ********************************************************************/
+
+BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ if (!pwd) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->nt_pw);
+ return True;
+ }
+
+ if (sampass->nt_pw!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: NT hash non NULL overwritting ?\n"));
+ else
+ sampass->nt_pw=(unsigned char *)malloc(sizeof(unsigned char)*16);
+
+ if (sampass->nt_pw==NULL)
+ return False;
+
+ memcpy (sampass->nt_pw, pwd, 16);
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's LM hash.
+ ********************************************************************/
+
+BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ if (!pwd) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->lm_pw);
+ return True;
+ }
+
+ if (sampass->lm_pw!=NULL)
+ DEBUG(4,("pdb_set_lanman_passwd: LM hash non NULL overwritting ?\n"));
+ else
+ sampass->lm_pw=(unsigned char *)malloc(sizeof(unsigned char)*16);
+
+ if (sampass->lm_pw==NULL)
+ return False;
+
+ memcpy (sampass->lm_pw, pwd, 16);
+
+ return True;
+}
+
+BOOL pdb_set_unknown_3 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_3 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_5 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_5 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_6 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_6 = unkn;
+ return True;
+}
+
+BOOL pdb_set_hours (SAM_ACCOUNT *sampass, const uint8 *hours)
+{
+ if (!sampass)
+ return False;
+
+ if (!hours) {
+ memset ((char *)sampass->hours, 0, MAX_HOURS_LEN);
+ return True;
+ }
+
+ memcpy (sampass->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)
+{
+ time_t expire;
+
+ if (!sampass)
+ return False;
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL)))
+ return False;
+
+ account_policy_get(AP_MAX_PASSWORD_AGE, (int *)&expire);
+
+ if (expire==-1) {
+ if (!pdb_set_pass_must_change_time (sampass, 0))
+ return False;
+ } else {
+ if (!pdb_set_pass_must_change_time (sampass,
+ pdb_get_pass_last_set_time(sampass)
+ + expire))
+ 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/source/passdb/passgrp.c b/source/passdb/passgrp.c
new file mode 100644
index 00000000000..55a71e94a27
--- /dev/null
+++ b/source/passdb/passgrp.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c
new file mode 100644
index 00000000000..f426f926b19
--- /dev/null
+++ b/source/passdb/pdb_ldap.c
@@ -0,0 +1,1045 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.9.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Shahms King 2001
+ Copyright (C) Jean François Micouleau 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"
+
+#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 ldap_enum_info
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+};
+
+static struct ldap_enum_info global_ldap_ent;
+
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static BOOL
+ldap_open_connection (LDAP ** ldap_struct)
+{
+ int port;
+ int version, rc;
+ int tls = LDAP_OPT_X_TLS_HARD;
+
+ if (lp_ldap_ssl() == LDAP_SSL_ON && lp_ldap_port() == 389) {
+ port = 636;
+ }
+ else {
+ port = lp_ldap_port();
+ }
+
+ if ((*ldap_struct = ldap_init(lp_ldap_server(), port)) == NULL) {
+ DEBUG(0, ("The LDAP server is not responding !\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);
+ }
+ }
+
+ switch (lp_ldap_ssl())
+ {
+ case 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"));
+ break;
+ case LDAP_SSL_ON:
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+ break;
+ case LDAP_SSL_OFF:
+ default:
+ }
+
+ DEBUG(2, ("ldap_open_connection: connection opened\n"));
+ return (True);
+}
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static BOOL ldap_connect_system(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_ldap_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 */
+ 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 ldap_search_one_user (LDAP * ldap_struct, const char *filter, LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+
+ DEBUG(2, ("ldap_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,("ldap_search_one_user: Problem during the LDAP search: %s\n",
+ ldap_err2string (rc)));
+ DEBUG(3,("ldap_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(),
+ filter));
+ }
+ return (rc);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldap_search_one_user_by_name (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 ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static int ldap_search_one_user_by_uid(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 */
+ user = sys_getpwuid(uid);
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
+
+ return ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by rid.
+******************************************************************/
+static int ldap_search_one_user_by_rid (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 = ldap_search_one_user(ldap_struct, filter, result);
+
+ if (rc != LDAP_SUCCESS)
+ rc = ldap_search_one_user_by_uid(ldap_struct,
+ pdb_user_rid_to_uid(rid), result);
+
+ return rc;
+}
+
+/*******************************************************************
+search an attribute and return the first value found.
+******************************************************************/
+static void get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ char *attribute, char *value)
+{
+ char **valeurs;
+
+ if ((valeurs = ldap_get_values (ldap_struct, entry, attribute)) != NULL) {
+ pstrcpy(value, valeurs[0]);
+ ldap_value_free(valeurs);
+ DEBUG (2, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
+ }
+ else {
+ value = NULL;
+ DEBUG (2, ("get_single_attribute: [%s] = [NULL]\n", attribute));
+ }
+}
+
+/************************************************************************
+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 (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;
+ static pstring username;
+ static pstring domain;
+ static pstring nt_username;
+ static pstring fullname;
+ static pstring homedir;
+ static pstring dir_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring munged_dial;
+ static pstring workstations;
+ struct passwd *sys_user;
+ uint32 user_rid, group_rid;
+ static uint8 smblmpwd[16];
+ static uint8 smbntpwd[16];
+ uint16 acct_ctrl, logon_divs;
+ uint32 hours_len;
+ uint8 *hours;
+ pstring temp;
+
+ get_single_attribute(ldap_struct, entry, "uid", username);
+ DEBUG(2, ("Entry found for user: %s\n", username));
+
+ pstrcpy(nt_username, username);
+
+ get_single_attribute(ldap_struct, entry, "sambaDomain", domain);
+ if (!domain)
+ pstrcpy(domain, lp_workgroup());
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ pass_last_set_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logonTime", temp);
+ logon_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logoffTime", temp);
+ logoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
+ kickoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
+ pass_can_change_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
+ pass_must_change_time = (time_t) strtol(temp, NULL, 16);
+
+ /* 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 gecos then displayName then cn rather than 'userFullName'
+ */
+
+ get_single_attribute(ldap_struct, entry, "gecos", fullname);
+
+ if (!fullname) {
+ get_single_attribute(ldap_struct, entry, "displayName", fullname);
+ get_single_attribute(ldap_struct, entry, "cn", fullname);
+ }
+
+ get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
+ DEBUG(5,("homeDrive is set to %s\n",dir_drive));
+ if (!*dir_drive) {
+ pstrcpy(dir_drive, lp_logon_drive());
+ DEBUG(5,("homeDrive fell back to %s\n",dir_drive));
+ }
+
+ get_single_attribute(ldap_struct, entry, "smbHome", homedir);
+ DEBUG(5,("smbHome is set to %s\n",homedir));
+ if (!*homedir) {
+ pstrcpy(homedir, lp_logon_home());
+ DEBUG(5,("smbHome fell back to %s\n",homedir));
+ }
+
+ get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
+ DEBUG(5,("scriptPath is set to %s\n",logon_script));
+ if (!*logon_script) {
+ pstrcpy(logon_script, lp_logon_script());
+ DEBUG(5,("scriptPath fell back to %s\n",logon_script));
+ }
+
+ get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
+ DEBUG(5,("profilePath is set to %s\n",profile_path));
+ if (!*profile_path) {
+ pstrcpy(profile_path, lp_logon_path());
+ DEBUG(5,("profilePath fell back to %s\n",profile_path));
+ }
+
+ get_single_attribute(ldap_struct, entry, "description", acct_desc);
+ get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user_rid = (uint32)strtol(temp, NULL, 10);
+ get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
+ group_rid = (uint32)strtol(temp, NULL, 10);
+
+
+ /* These values MAY be in LDAP, but they can also be retrieved through
+ * sys_getpw*() which is how we're doing it (if you use nss_ldap, then
+ * these values will be stored in LDAP as well, but if not, we want the
+ * local values to override the LDAP for this anyway
+ * homeDirectory attribute
+ */
+ sys_user = sys_getpwnam(username);
+ if (sys_user == NULL)
+ return False;
+
+
+ /* FIXME: hours stuff should be cleaner */
+ logon_divs = 168;
+ hours_len = 21;
+ hours = malloc(sizeof(hours) * hours_len);
+ memset(hours, 0xff, hours_len);
+
+ get_single_attribute (ldap_struct, entry, "lmPassword", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "ntPassword", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "acctFlags", temp);
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0)
+ acct_ctrl |= ACB_NORMAL;
+
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_logons_divs(sampass, logon_divs);
+
+ pdb_set_uid(sampass, &sys_user->pw_uid);
+ pdb_set_gid(sampass, &sys_user->pw_gid);
+ 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_fullname(sampass, fullname);
+
+ pdb_set_logon_script(sampass, logon_script);
+ pdb_set_profile_path(sampass, profile_path);
+ pdb_set_dir_drive(sampass, dir_drive);
+ pdb_set_homedir(sampass, homedir);
+ pdb_set_acct_desc(sampass, acct_desc);
+ pdb_set_workstations(sampass, workstations);
+ pdb_set_munged_dial(sampass, munged_dial);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd))
+ return False;
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd))
+ return False;
+
+ /* 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 (LDAPMod *** mods, int ldap_state, const SAM_ACCOUNT * sampass)
+{
+ pstring temp;
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+
+
+ make_a_mod(mods, ldap_state, "uid", pdb_get_username(sampass));
+ DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ /* not sure about using this for the nt_username */
+ make_a_mod(mods, ldap_state, "sambaDomain", pdb_get_domain(sampass));
+
+ slprintf(temp, sizeof(temp) - 1, "%i", pdb_get_uid(sampass));
+ make_a_mod(mods, ldap_state, "uidNumber", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdLastSet", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
+ make_a_mod(mods, ldap_state, "logonTime", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
+ make_a_mod(mods, ldap_state, "logoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
+ make_a_mod(mods, ldap_state, "kickoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdCanChange", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdMustChange", 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_state, "displayName", pdb_get_fullname(sampass));
+ make_a_mod(mods, ldap_state, "cn", pdb_get_fullname(sampass));
+
+ make_a_mod(mods, ldap_state, "smbHome", pdb_get_homedir(sampass));
+ make_a_mod(mods, ldap_state, "homeDrive", pdb_get_dirdrive(sampass));
+ make_a_mod(mods, ldap_state, "scriptPath", pdb_get_logon_script(sampass));
+ make_a_mod(mods, ldap_state, "profilePath", pdb_get_profile_path(sampass));
+ make_a_mod(mods, ldap_state, "description", pdb_get_acct_desc(sampass));
+ make_a_mod(mods, ldap_state, "userWorkstations", pdb_get_workstations(sampass));
+
+ if ( !sampass->user_rid)
+ sampass->user_rid = pdb_uid_to_user_rid(pdb_get_uid(sampass));
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->user_rid);
+ make_a_mod(mods, ldap_state, "rid", temp);
+
+ if ( !sampass->group_rid) {
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pdb_get_gid(sampass), &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &sampass->group_rid);
+ }
+ else
+ sampass->group_rid = pdb_gid_to_group_rid(pdb_get_gid(sampass));
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->group_rid);
+ make_a_mod(mods, ldap_state, "primaryGroupID", 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_state, "lmPassword", temp);
+ pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_state, "ntPassword", temp);
+ make_a_mod (mods, ldap_state, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ return True;
+}
+
+/**********************************************************************
+Connect to LDAP server for password enumeration
+*********************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ int rc;
+ pstring filter;
+
+ if (!ldap_open_connection(&global_ldap_ent.ldap_struct))
+ {
+ return False;
+ }
+ if (!ldap_connect_system(global_ldap_ent.ldap_struct))
+ {
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ return False;
+ }
+
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", "*", sizeof(pstring));
+
+ rc = ldap_search_s(global_ldap_ent.ldap_struct, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0,
+ &global_ldap_ent.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(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ return False;
+ }
+
+ DEBUG(2, ("pdb_setsampwent: %d entries in the base!\n",
+ ldap_count_entries(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result)));
+
+ global_ldap_ent.entry = ldap_first_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result);
+
+ return True;
+}
+
+/**********************************************************************
+End enumeration of the LDAP password list
+*********************************************************************/
+void pdb_endsampwent(void)
+{
+ if (global_ldap_ent.ldap_struct && global_ldap_ent.result)
+ {
+ ldap_msgfree(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ }
+}
+
+/**********************************************************************
+Get the next entry in the LDAP password database
+*********************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT * user)
+{
+ if (!global_ldap_ent.entry)
+ return False;
+
+ global_ldap_ent.entry = ldap_next_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+
+ if (global_ldap_ent.entry != NULL)
+ {
+ return init_sam_from_ldap(user, global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+ }
+ return False;
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by username
+*********************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_name(ldap_struct, sname, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("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)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ 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
+*********************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_rid(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)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ 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 uid
+*********************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_uid(ldap_struct, uid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this uid [%i] count=%d\n", uid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ 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
+*********************************************************************/
+BOOL pdb_delete_sam_account(const char *sname)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *entry;
+ LDAPMessage *result;
+
+ if (!ldap_open_connection (&ldap_struct))
+ return False;
+
+ DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
+
+ if (!ldap_connect_system (ldap_struct)) {
+ ldap_unbind (ldap_struct);
+ DEBUG(0, ("Failed to delete user %s from LDAP.\n", sname));
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name (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
+*********************************************************************/
+BOOL pdb_update_sam_account(const SAM_ACCOUNT * newpwd, BOOL override)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ LDAPMod **mods;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ return False;
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name(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;
+ }
+
+ init_ldap_from_sam(&mods, LDAP_MOD_REPLACE, newpwd);
+
+ 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
+*********************************************************************/
+BOOL pdb_add_sam_account(const SAM_ACCOUNT * newpwd)
+{
+ int rc;
+ pstring filter;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ pstring dn;
+ LDAPMod **mods;
+ int ldap_op = LDAP_MOD_ADD;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (pdb_get_username(newpwd) != NULL) {
+ slprintf (dn, sizeof (dn) - 1, "uid=%s,%s",
+ pdb_get_username(newpwd), lp_ldap_suffix ());
+ }
+ else
+ {
+ return False;
+ }
+
+
+ rc = ldap_search_one_user_by_name (ldap_struct, pdb_get_username(newpwd), &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", pdb_get_username(newpwd));
+ rc = ldap_search_one_user(ldap_struct, filter, &result);
+ if (ldap_count_entries(ldap_struct, 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
+ {
+ DEBUG (3, ("More than one user with that uid exists: bailing out!\n"));
+ return False;
+ }
+
+ ldap_msgfree(result);
+
+ init_ldap_from_sam(&mods, ldap_op, newpwd);
+ 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 user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), 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;
+}
+
+#else
+void dummy_function(void);
+void
+dummy_function (void)
+{
+} /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/pdb_nisplus.c b/source/passdb/pdb_nisplus.c
new file mode 100644
index 00000000000..2820fa14142
--- /dev/null
+++ b/source/passdb/pdb_nisplus.c
@@ -0,0 +1,1409 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. 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
+
+/***************************************************************
+ 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);
+ 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));
+ }
+ }
+
+ pdb_set_logoff_time(pw_buf, get_time_t_max());
+ 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));
+ }
+ }
+
+ pdb_set_kickoff_time(pw_buf, get_time_t_max());
+ 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));
+ }
+ }
+
+ 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);
+ 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));
+ }
+ }
+
+ pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* 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));
+ }
+ }
+
+ /* 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));
+ unix_to_dos(full_name, True);
+ 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));
+ unix_to_dos(acct_desc, True);
+ 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);
+
+ 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);
+
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
+ sizeof(pstring));
+ if( !(logon_script && *logon_script) )
+ pstrcpy(logon_script, lp_logon_script());
+ pdb_set_logon_script(pw_buf, logon_script);
+
+ 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);
+ } 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);
+ pdb_set_lanman_passwd(pw_buf, NULL);
+
+ 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;
+ }
+ pdb_set_lanman_passwd(pw_buf, smbpwd);
+ }
+
+ /* Check the NT password column. */
+ ptr = ENTRY_VAL(obj, NPF_NTPWD);
+ pdb_set_nt_passwd(pw_buf, NULL);
+
+ 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;
+ }
+ pdb_set_nt_passwd(pw_buf, smbntpwd);
+ }
+
+ pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
+ pdb_set_logons_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);
+ dos_to_unix(full_name, True);
+ safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
+ dos_to_unix(acct_desc, True);
+
+ 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, uint_t 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 search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ 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_uid(uid, pfiletmp);
+
+ DEBUG(10, ("search by uid: %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(const char *sname)
+{
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ nis_result *result, *delresult;
+ nis_object *obj;
+ 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);
+
+ /* 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(const 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)
+ {
+ DEBUG(3, ("nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+
+ if (!sys_getpwnam(pdb_get_username(newpwd))) {
+ /* no such user in system! */
+ return False;
+ }
+ /*
+ * 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(const SAM_ACCOUNT * newpwd, BOOL override)
+{
+ 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/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c
new file mode 100644
index 00000000000..9cfad2540c4
--- /dev/null
+++ b/source/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1545 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-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_SMBPASSWD_SAM
+
+
+/*
+ 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
+{
+ uid_t 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 */
+};
+
+
+extern struct passdb_ops pdb_ops;
+
+/* used for maintain locks on the smbpasswd file */
+static int pw_file_lock_depth;
+static void *global_vp;
+
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+/***************************************************************
+ 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 void *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 (void *)fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+static void endsmbfilepwent(void *vp, int *lock_depth)
+{
+ FILE *fp = (FILE *)vp;
+
+ 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(void *vp)
+{
+ /* 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];
+ FILE *fp = (FILE *)vp;
+ 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(const struct smb_passwd *newpwd)
+{
+ char *pfile = lp_smb_passwd_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;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &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(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, &pw_file_lock_depth);
+ return False;
+ }
+ }
+
+ /* Ok - entry doesn't exist. We can add it */
+
+ /* 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, &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, &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, &pw_file_lock_depth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &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(const struct smb_passwd* pwd, BOOL override)
+{
+ /* Static buffers we will return. */
+ static pstring 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;
+ char *pfile = lp_smb_passwd_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, &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, &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, &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, &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, &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 (!override && (*p == '*' || *p == 'X')) {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&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,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (!override && (*p == '*' || *p == 'X')) {
+ pw_file_unlock(lockfd,&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,&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,&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,&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,&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,&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,&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,&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,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static BOOL del_smbfilepwd_entry(const char *name)
+{
+ char *pfile = lp_smb_passwd_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, &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, &pw_file_lock_depth);
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(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, &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, &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, &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, &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;
+ gid_t *gid;
+
+ if (sampass == NULL)
+ return False;
+ uid = pdb_get_uid(sampass);
+ gid = pdb_get_gid(sampass);
+
+ if (!uid || !gid) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user without a UNIX uid or gid. \n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(smb_pw);
+
+ smb_pw->smb_userid=*uid;
+ smb_pw->smb_name=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 (*uid != pdb_user_rid_to_uid(pdb_get_user_rid(sampass))) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
+ return False;
+ }
+
+#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(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;
+ }
+
+ /* 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 = sys_getpwnam(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));
+
+ {
+ uint32 rid;
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pwfile->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ }
+ else
+ rid=pdb_gid_to_group_rid(pwfile->pw_gid);
+
+ pdb_set_group_rid(sam_pass, rid);
+ }
+
+ 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);
+ pdb_set_domain (sam_pass, lp_workgroup());
+
+ pdb_set_dir_drive (sam_pass, lp_logon_drive());
+
+ /* 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);
+
+ /* 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ /*pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS); */
+ }
+
+ return True;
+}
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+BOOL pdb_setsampwent (BOOL update)
+{
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+
+ /* did we fail? Should we try to create it? */
+ if (!global_vp && 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(lp_smb_passwd_file(), "w");
+ if (fp)
+ {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ }
+
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+ }
+
+ return (global_vp != NULL);
+}
+
+void pdb_endsampwent (void)
+{
+ endsmbfilepwent(global_vp, &pw_file_lock_depth);
+}
+
+/*****************************************************************
+ ****************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ struct smb_passwd *pw_buf=NULL;
+ BOOL done = False;
+ DEBUG(5,("pdb_getsampwent\n"));
+
+ if (user==NULL) {
+ DEBUG(5,("pdb_getsampwent: user is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwent\n");
+#endif
+ return False;
+ }
+
+ while (!done)
+ {
+ /* do we have an entry? */
+ pw_buf = getsmbfilepwent(global_vp);
+ 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(user, pw_buf))
+ done = True;
+ }
+
+ DEBUG(5,("pdb_getsampwent: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
+ ***************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+ char *domain = NULL;
+ char *user = NULL;
+ fstring name;
+
+ DEBUG(10, ("pdb_getsampwnam: 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(lp_smb_passwd_file(), PWF_READ, &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(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwnam: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(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", (int)uid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwuid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
+{
+ 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(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwrid: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 (sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_add_sam_account(const SAM_ACCOUNT *sampass)
+{
+ 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(&smb_pw)) {
+ return False;
+ }
+
+ return True;
+}
+
+BOOL pdb_update_sam_account(const SAM_ACCOUNT *sampass, BOOL override)
+{
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ build_smb_pass(&smb_pw, sampass);
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(&smb_pw, override))
+ return False;
+
+ return True;
+}
+
+BOOL pdb_delete_sam_account (const char* username)
+{
+ return del_smbfilepwd_entry(username);
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void smbpass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WTH_SMBPASSWD_SAM*/
+
diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c
new file mode 100644
index 00000000000..1f1d1ab455b
--- /dev/null
+++ b/source/passdb/pdb_tdb.c
@@ -0,0 +1,808 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. 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
+ *
+ * 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_"
+
+extern int DEBUGLEVEL;
+
+struct tdb_enum_info {
+ TDB_CONTEXT *passwd_tdb;
+ TDB_DATA key;
+};
+
+static struct tdb_enum_info global_tdb_ent;
+/*static SAM_ACCOUNT global_sam_pass;*/
+
+/**********************************************************************
+ Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
+ *********************************************************************/
+
+static BOOL init_sam_from_buffer (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 /* uid, gid,*/ 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;
+
+ /* 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;
+ }
+
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_username (sampass, username_len?username:NULL);
+ pdb_set_domain (sampass, domain_len?domain:NULL);
+ pdb_set_nt_username (sampass, nt_username_len?nt_username:NULL);
+ pdb_set_fullname (sampass, fullname_len?fullname:NULL);
+ pdb_set_homedir (sampass, homedir_len?homedir:NULL);
+ pdb_set_dir_drive (sampass, dir_drive_len?dir_drive:NULL);
+ pdb_set_logon_script (sampass, logon_script_len?logon_script:NULL);
+ pdb_set_profile_path (sampass, profile_path_len?profile_path:NULL);
+ pdb_set_acct_desc (sampass, acct_desc_len?acct_desc:NULL);
+ pdb_set_workstations (sampass, workstations_len?workstations:NULL);
+ pdb_set_munged_dial (sampass, munged_dial_len?munged_dial:NULL);
+ pdb_set_lanman_passwd(sampass, lmpwlen?lm_pw_ptr:NULL);
+ pdb_set_nt_passwd (sampass, ntpwlen?nt_pw_ptr:NULL);
+
+ /*pdb_set_uid(sampass, uid);
+ pdb_set_gid(sampass, gid);*/
+ 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_logons_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 (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;
+ 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)
+ 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);
+
+
+ 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;
+ dir_drive = pdb_get_dirdrive(sampass);
+ if (dir_drive)
+ dir_drive_len = strlen(dir_drive) +1;
+ else
+ dir_drive_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;
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname)
+ fullname_len = strlen(fullname) +1;
+ else
+ fullname_len = 0;
+ homedir = pdb_get_homedir(sampass);
+ if (homedir)
+ homedir_len = strlen(homedir) +1;
+ else
+ homedir_len = 0;
+ logon_script = pdb_get_logon_script(sampass);
+ if (logon_script)
+ logon_script_len = strlen(logon_script) +1;
+ else
+ logon_script_len = 0;
+ profile_path = pdb_get_profile_path(sampass);
+ if (profile_path)
+ profile_path_len = strlen(profile_path) +1;
+ else
+ profile_path_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;
+
+ 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;
+
+ /* 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,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ 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,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ 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) {
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+/***************************************************************
+ Open the TDB passwd database for SAM account enumeration.
+****************************************************************/
+
+BOOL pdb_setsampwent(BOOL update)
+{
+ pstring tdbfile;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* Open tdb passwd */
+ if (!(global_tdb_ent.passwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)))
+ {
+ DEBUG(0, ("Unable to open/create TDB passwd\n"));
+ return False;
+ }
+
+ global_tdb_ent.key = tdb_firstkey(global_tdb_ent.passwd_tdb);
+
+ return True;
+}
+
+/***************************************************************
+ End enumeration of the TDB passwd list.
+****************************************************************/
+
+void pdb_endsampwent(void)
+{
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ DEBUG(7, ("endtdbpwent: closed password file.\n"));
+}
+
+/*****************************************************************
+ Get one SAM_ACCOUNT from the TDB (next in line)
+*****************************************************************/
+
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ TDB_DATA data;
+ struct passwd *pw;
+ uid_t uid;
+ gid_t gid;
+ char *prefix = USERPREFIX;
+ int prefixlen = strlen (prefix);
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_get_sampwent: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* skip all RID entries */
+ while ((global_tdb_ent.key.dsize != 0) && (strncmp (global_tdb_ent.key.dptr, prefix, prefixlen)))
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ /* do we have an valid interation pointer? */
+ if(global_tdb_ent.passwd_tdb == NULL) {
+ DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
+ return False;
+ }
+
+ data = tdb_fetch (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (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);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user))) == NULL) {
+ DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
+ pdb_get_username(user)));
+ return False;
+ }
+
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, &uid);
+ pdb_set_gid (user, &gid);
+
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ return True;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+BOOL pdb_getsampwnam (SAM_ACCOUNT *user, const char *sname)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ struct passwd *pw;
+ pstring tdbfile;
+ fstring name;
+ uid_t uid;
+ gid_t gid;
+
+
+ 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));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_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(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd!\n"));
+ 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)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (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);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user)))) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, &uid);
+ pdb_set_gid (user, &gid);
+ }
+
+ /* cleanup */
+ tdb_close (pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Search by uid
+ **************************************************************************/
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT* user, uid_t uid)
+{
+ struct passwd *pw;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwuid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ pw = sys_getpwuid(uid);
+ if (pw == NULL) {
+ DEBUG(0,("pdb_getsampwuid: getpwuid(%d) return NULL. User does not exist!\n", uid));
+ return False;
+ }
+ fstrcpy (name, pw->pw_name);
+
+ return pdb_getsampwnam (user, name);
+
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+BOOL pdb_getsampwrid (SAM_ACCOUNT *user, uint32 rid)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* 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(tdbfile, 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 fetching database.\n"));
+ 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 pdb_getsampwnam (user, name);
+}
+
+/***************************************************************************
+ Delete a SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_delete_sam_account(const char *sname)
+{
+ SAM_ACCOUNT *sam_pass = NULL;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA key, data;
+ fstring keystr;
+ pstring tdbfile;
+ uint32 rid;
+ fstring name;
+
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* open the TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 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;
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_delete_sam_account (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!pdb_init_sam (&sam_pass)) {
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ if (!init_sam_from_buffer (sam_pass, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ tdb_close (pwd_tdb);
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ pdb_free_sam (&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(const SAM_ACCOUNT* newpwd, BOOL override, int flag)
+{
+ TDB_CONTEXT *pwd_tdb = NULL;
+ TDB_DATA key, data;
+ uint8 *buf = NULL;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+ BOOL ret = True;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* if we don't have a RID, then FAIL */
+ if (!pdb_get_user_rid(newpwd))
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a RID\n",pdb_get_username(newpwd)));
+ if (!pdb_get_group_rid(newpwd))
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd)));
+
+ /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
+ if ((data.dsize=init_buffer_from_sam (&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));
+
+ /* setup the USER index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* invalidate the existing TDB iterator if it is open */
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ /* open the account TDB passwd*/
+ pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+ if (!pwd_tdb)
+ {
+ DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd!\n"));
+ return False;
+ }
+
+ /* add the account */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify passwd TDB!"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ 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, pdb_get_user_rid(newpwd));
+ 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)));
+ ret = False;
+ goto done;
+ }
+
+done:
+ /* cleanup */
+ tdb_close (pwd_tdb);
+ SAFE_FREE(buf);
+
+ return (ret);
+}
+
+/***************************************************************************
+ Modifies an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_update_sam_account (const SAM_ACCOUNT *newpwd, BOOL override)
+{
+ return (tdb_update_sam(newpwd, override, TDB_MODIFY));
+}
+
+/***************************************************************************
+ Adds an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_add_sam_account (const SAM_ACCOUNT *newpwd)
+{
+ return (tdb_update_sam(newpwd, True, TDB_INSERT));
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void samtdb_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_TDB_SAM */
diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c
new file mode 100644
index 00000000000..198f557bd62
--- /dev/null
+++ b/source/passdb/secrets.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ 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);
+ 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);
+ 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 a domain trust password
+************************************************************************/
+char *trust_keystr(char *domain)
+{
+ static fstring keystr;
+
+ slprintf(keystr,sizeof(keystr)-1,"%s/%s",
+ SECRETS_MACHINE_ACCT_PASS, domain);
+
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get the 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 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 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)
+{
+ return secrets_store(SECRETS_MACHINE_PASSWORD, pass, strlen(pass)+1);
+}
+
+
+/************************************************************************
+ 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)
+{
+ return (char *)secrets_fetch(SECRETS_MACHINE_PASSWORD, NULL);
+}
+
+
+
+/************************************************************************
+ Routine to delete the trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_delete(char *domain)
+{
+ return secrets_delete(trust_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_int_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);
+}
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
deleted file mode 100644
index 2dec15ffb43..00000000000
--- a/source/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
diff --git a/source/passdb/smbpasschange.c b/source/passdb/smbpasschange.c
new file mode 100644
index 00000000000..f4af6e8745f
--- /dev/null
+++ b/source/passdb/smbpasschange.c
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ change a password in a local smbpasswd file
+ Copyright (C) Andrew Tridgell 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"
+
+
+
diff --git a/source/passdb/smbpassgroup.c b/source/passdb/smbpassgroup.c
new file mode 100644
index 00000000000..808abde6617
--- /dev/null
+++ b/source/passdb/smbpassgroup.c
@@ -0,0 +1,195 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 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"
+
+#ifdef USE_SMBPASS_DB
+
+static int grp_file_lock_depth = 0;
+
+/***************************************************************
+ Start to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+static void *startsmbfilegrpent(BOOL update)
+{
+ static char s_readbuf[1024];
+ return startfilepwent(lp_smb_passgrp_file(), s_readbuf, sizeof(s_readbuf),
+ &grp_file_lock_depth, update);
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+
+static void endsmbfilegrpent(void *vp)
+{
+ endfilepwent(vp, &grp_file_lock_depth);
+}
+
+/*************************************************************************
+ Return the current position in the smbpasswd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+
+static SMB_BIG_UINT getsmbfilegrppos(void *vp)
+{
+ return getfilepwpos(vp);
+}
+
+/*************************************************************************
+ Set the current position in the smbpasswd list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+
+static BOOL setsmbfilegrppos(void *vp, SMB_BIG_UINT tok)
+{
+ return setfilepwpos(vp, tok);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+static struct smb_passwd *getsmbfilegrpent(void *vp,
+ uint32 **grp_rids, int *num_grps,
+ uint32 **als_rids, int *num_alss)
+{
+ /* Static buffers we will return. */
+ static struct smb_passwd pw_buf;
+ static pstring user_name;
+ struct passwd *pwfile;
+ pstring linebuf;
+ unsigned char *p;
+ int uidval;
+ size_t linebuf_len;
+
+ if (vp == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pwdb_init_smb(&pw_buf);
+
+ /*
+ * Scan the file, a line at a time.
+ */
+ while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0)
+ {
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:domainrid1,domainrid2..:aliasrid1,aliasrid2..:
+ */
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ p = strncpyn(user_name, linebuf, sizeof(user_name), ':');
+
+ /* Go past ':' */
+ p++;
+
+ /* Get smb uid. */
+
+ p = Atoic((char *) p, &uidval, ":");
+
+ 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 (grp_rids != NULL && num_grps != NULL)
+ {
+ int i;
+ p = get_numlist(p, grp_rids, num_grps);
+ if (p == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: invalid line\n"));
+ return NULL;
+ }
+ for (i = 0; i < (*num_grps); i++)
+ {
+ (*grp_rids)[i] = pwdb_gid_to_group_rid((*grp_rids)[i]);
+ }
+ }
+
+ /* Skip the ':' */
+ p++;
+
+ if (als_rids != NULL && num_alss != NULL)
+ {
+ int i;
+ p = get_numlist(p, als_rids, num_alss);
+ if (p == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: invalid line\n"));
+ return NULL;
+ }
+ for (i = 0; i < (*num_alss); i++)
+ {
+ (*als_rids)[i] = pwdb_gid_to_alias_rid((*als_rids)[i]);
+ }
+ }
+
+ pwfile = Get_Pwnam(pw_buf.smb_name);
+ if (pwfile == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: smbpasswd database is corrupt!\n"));
+ DEBUG(0,("getsmbfilegrpent: username %s not in unix passwd database!\n", pw_buf.smb_name));
+ return NULL;
+ }
+
+ return &pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilegrpent: end of file reached.\n"));
+ return NULL;
+}
+
+static struct passgrp_ops file_ops =
+{
+ startsmbfilegrpent,
+ endsmbfilegrpent,
+ getsmbfilegrppos,
+ setsmbfilegrppos,
+ iterate_getsmbgrpnam, /* In passgrp.c */
+ iterate_getsmbgrpuid, /* In passgrp.c */
+ iterate_getsmbgrprid, /* In passgrp.c */
+ getsmbfilegrpent,
+};
+
+struct passgrp_ops *file_initialise_password_grp(void)
+{
+ return &file_ops;
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void smbpass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* USE_SMBPASS_DB */