diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source3/passdb/account_pol.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/passdb/account_pol.c')
-rw-r--r-- | source3/passdb/account_pol.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/source3/passdb/account_pol.c b/source3/passdb/account_pol.c new file mode 100644 index 0000000..34c0d72 --- /dev/null +++ b/source3/passdb/account_pol.c @@ -0,0 +1,494 @@ +/* + * Unix SMB/CIFS implementation. + * account policy storage + * Copyright (C) Jean François Micouleau 1998-2001 + * Copyright (C) Andrew Bartlett 2002 + * Copyright (C) Guenther Deschner 2004-2005 + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "system/filesys.h" +#include "passdb.h" +#include "dbwrap/dbwrap.h" +#include "dbwrap/dbwrap_open.h" +#include "../libcli/security/security.h" +#include "lib/privileges.h" +#include "lib/gencache.h" +#include "lib/util/smb_strtox.h" + +static struct db_context *db; + +/* cache all entries for 60 seconds for to save ldap-queries (cache is updated + * after this period if admins do not use pdbedit or usermanager but manipulate + * ldap directly) - gd */ + +#define DATABASE_VERSION 3 +#define AP_TTL 60 + + +struct ap_table { + enum pdb_policy_type type; + const char *string; + uint32_t default_val; + const char *description; + const char *ldap_attr; +}; + +static const struct ap_table account_policy_names[] = { + {PDB_POLICY_MIN_PASSWORD_LEN, "min password length", MINPASSWDLENGTH, + "Minimal password length (default: 5)", + "sambaMinPwdLength" }, + + {PDB_POLICY_PASSWORD_HISTORY, "password history", 0, + "Length of Password History Entries (default: 0 => off)", + "sambaPwdHistoryLength" }, + + {PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, "user must logon to change password", 0, + "Force Users to logon for password change (default: 0 => off, 2 => on)", + "sambaLogonToChgPwd" }, + + {PDB_POLICY_MAX_PASSWORD_AGE, "maximum password age", (uint32_t) -1, + "Maximum password age, in seconds (default: -1 => never expire passwords)", + "sambaMaxPwdAge" }, + + {PDB_POLICY_MIN_PASSWORD_AGE,"minimum password age", 0, + "Minimal password age, in seconds (default: 0 => allow immediate password change)", + "sambaMinPwdAge" }, + + {PDB_POLICY_LOCK_ACCOUNT_DURATION, "lockout duration", 30, + "Lockout duration in minutes (default: 30, -1 => forever)", + "sambaLockoutDuration" }, + + {PDB_POLICY_RESET_COUNT_TIME, "reset count minutes", 30, + "Reset time after lockout in minutes (default: 30)", + "sambaLockoutObservationWindow" }, + + {PDB_POLICY_BAD_ATTEMPT_LOCKOUT, "bad lockout attempt", 0, + "Lockout users after bad logon attempts (default: 0 => off)", + "sambaLockoutThreshold" }, + + {PDB_POLICY_TIME_TO_LOGOUT, "disconnect time", (uint32_t) -1, + "Disconnect Users outside logon hours (default: -1 => off, 0 => on)", + "sambaForceLogoff" }, + + {PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, "refuse machine password change", 0, + "Allow Machine Password changes (default: 0 => off)", + "sambaRefuseMachinePwdChange" }, + + {0, NULL, 0, "", NULL} +}; + +void account_policy_names_list(TALLOC_CTX *mem_ctx, const char ***names, int *num_names) +{ + const char **nl; + int i, count = ARRAY_SIZE(account_policy_names); + + nl = talloc_array(mem_ctx, const char *, count); + if (!nl) { + *num_names = 0; + return; + } + for (i=0; i<count; i++) { + nl[i] = account_policy_names[i].string; + } + /* Do not return the last null entry */ + *num_names = count-1; + *names = nl; + return; +} + +/**************************************************************************** +Get the account policy name as a string from its #define'ed number +****************************************************************************/ + +const char *decode_account_policy_name(enum pdb_policy_type type) +{ + int i; + for (i=0; account_policy_names[i].string; i++) { + if (type == account_policy_names[i].type) { + return account_policy_names[i].string; + } + } + return NULL; +} + +/**************************************************************************** +Get the account policy LDAP attribute as a string from its #define'ed number +****************************************************************************/ + +const char *get_account_policy_attr(enum pdb_policy_type type) +{ + int i; + for (i=0; account_policy_names[i].type; i++) { + if (type == account_policy_names[i].type) { + return account_policy_names[i].ldap_attr; + } + } + return NULL; +} + +/**************************************************************************** +Get the account policy description as a string from its #define'ed number +****************************************************************************/ + +const char *account_policy_get_desc(enum pdb_policy_type type) +{ + int i; + for (i=0; account_policy_names[i].string; i++) { + if (type == account_policy_names[i].type) { + return account_policy_names[i].description; + } + } + return NULL; +} + +/**************************************************************************** +Get the account policy name as a string from its #define'ed number +****************************************************************************/ + +enum pdb_policy_type account_policy_name_to_typenum(const char *name) +{ + int i; + for (i=0; account_policy_names[i].string; i++) { + if (strcmp(name, account_policy_names[i].string) == 0) { + return account_policy_names[i].type; + } + } + return 0; +} + +/***************************************************************************** +Get default value for account policy +*****************************************************************************/ + +bool account_policy_get_default(enum pdb_policy_type type, uint32_t *val) +{ + int i; + for (i=0; account_policy_names[i].type; i++) { + if (account_policy_names[i].type == type) { + *val = account_policy_names[i].default_val; + return True; + } + } + DEBUG(0,("no default for account_policy index %d found. This should never happen\n", + type)); + return False; +} + +/***************************************************************************** + Set default for a type if it is empty +*****************************************************************************/ + +static bool account_policy_set_default_on_empty(enum pdb_policy_type type) +{ + + uint32_t value; + + if (!account_policy_get(type, &value) && + !account_policy_get_default(type, &value)) { + return False; + } + + return account_policy_set(type, value); +} + +/***************************************************************************** + Open the account policy tdb. +***`*************************************************************************/ + +bool init_account_policy(void) +{ + + const char *vstring = "INFO/version"; + uint32_t version = 0; + int i; + NTSTATUS status; + char *db_path; + + if (db != NULL) { + return True; + } + + db_path = state_path(talloc_tos(), "account_policy.tdb"); + if (db_path == NULL) { + return false; + } + + db = db_open(NULL, db_path, 0, TDB_DEFAULT, + O_RDWR, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); + + if (db == NULL) { /* the account policies files does not exist or open + * failed, try to create a new one */ + db = db_open(NULL, db_path, 0, + TDB_DEFAULT, O_RDWR|O_CREAT, 0600, + DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); + if (db == NULL) { + DEBUG(0,("Failed to open account policy database\n")); + TALLOC_FREE(db_path); + return False; + } + } + TALLOC_FREE(db_path); + + status = dbwrap_fetch_uint32_bystring(db, vstring, &version); + if (!NT_STATUS_IS_OK(status)) { + version = 0; + } + + if (version == DATABASE_VERSION) { + return true; + } + + /* handle a Samba upgrade */ + + if (dbwrap_transaction_start(db) != 0) { + DEBUG(0, ("transaction_start failed\n")); + TALLOC_FREE(db); + return false; + } + + status = dbwrap_fetch_uint32_bystring(db, vstring, &version); + if (!NT_STATUS_IS_OK(status)) { + version = 0; + } + + if (version == DATABASE_VERSION) { + /* + * Race condition + */ + if (dbwrap_transaction_cancel(db)) { + smb_panic("transaction_cancel failed"); + } + return true; + } + + if (version != DATABASE_VERSION) { + status = dbwrap_store_uint32_bystring(db, vstring, + DATABASE_VERSION); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dbwrap_store_uint32_t failed: %s\n", + nt_errstr(status))); + goto cancel; + } + + for (i=0; account_policy_names[i].type; i++) { + + if (!account_policy_set_default_on_empty(account_policy_names[i].type)) { + DEBUG(0,("failed to set default value in account policy tdb\n")); + goto cancel; + } + } + } + + /* These exist by default on NT4 in [HKLM\SECURITY\Policy\Accounts] */ + + privilege_create_account( &global_sid_World ); + privilege_create_account( &global_sid_Builtin_Account_Operators ); + privilege_create_account( &global_sid_Builtin_Server_Operators ); + privilege_create_account( &global_sid_Builtin_Print_Operators ); + privilege_create_account( &global_sid_Builtin_Backup_Operators ); + + /* BUILTIN\Administrators get everything -- *always* */ + + if ( lp_enable_privileges() ) { + if ( !grant_all_privileges( &global_sid_Builtin_Administrators ) ) { + DEBUG(1,("init_account_policy: Failed to grant privileges " + "to BUILTIN\\Administrators!\n")); + } + } + + if (dbwrap_transaction_commit(db) != 0) { + DEBUG(0, ("transaction_commit failed\n")); + TALLOC_FREE(db); + return false; + } + + return True; + + cancel: + if (dbwrap_transaction_cancel(db)) { + smb_panic("transaction_cancel failed"); + } + TALLOC_FREE(db); + + return false; +} + +/***************************************************************************** +Get an account policy (from tdb) +*****************************************************************************/ + +bool account_policy_get(enum pdb_policy_type type, uint32_t *value) +{ + const char *name; + uint32_t regval; + NTSTATUS status; + + if (!init_account_policy()) { + return False; + } + + if (value) { + *value = 0; + } + + name = decode_account_policy_name(type); + if (name == NULL) { + DEBUG(1, ("account_policy_get: Field %d is not a valid account policy type! Cannot get, returning 0.\n", type)); + return False; + } + + status = dbwrap_fetch_uint32_bystring(db, name, ®val); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("account_policy_get: tdb_fetch_uint32_t failed for type %d (%s), returning 0\n", type, name)); + return False; + } + + if (value) { + *value = regval; + } + + DEBUG(10,("account_policy_get: name: %s, val: %d\n", name, regval)); + return True; +} + + +/**************************************************************************** +Set an account policy (in tdb) +****************************************************************************/ + +bool account_policy_set(enum pdb_policy_type type, uint32_t value) +{ + const char *name; + NTSTATUS status; + + if (!init_account_policy()) { + return False; + } + + name = decode_account_policy_name(type); + if (name == NULL) { + DEBUG(1, ("Field %d is not a valid account policy type! Cannot set.\n", type)); + return False; + } + + status = dbwrap_trans_store_uint32_bystring(db, name, value); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("store_uint32_t failed for type %d (%s) on value " + "%u: %s\n", type, name, value, nt_errstr(status))); + return False; + } + + DEBUG(10,("account_policy_set: name: %s, value: %d\n", name, value)); + + return True; +} + +/**************************************************************************** +Set an account policy in the cache +****************************************************************************/ + +bool cache_account_policy_set(enum pdb_policy_type type, uint32_t value) +{ + const char *policy_name = NULL; + char *cache_key = NULL; + char *cache_value = NULL; + bool ret = False; + + policy_name = decode_account_policy_name(type); + if (policy_name == NULL) { + DEBUG(0,("cache_account_policy_set: no policy found\n")); + return False; + } + + if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) { + DEBUG(0, ("asprintf failed\n")); + goto done; + } + + if (asprintf(&cache_value, "%lu\n", (unsigned long)value) < 0) { + DEBUG(0, ("asprintf failed\n")); + goto done; + } + + DEBUG(10,("cache_account_policy_set: updating account pol cache\n")); + + ret = gencache_set(cache_key, cache_value, time(NULL)+AP_TTL); + + done: + SAFE_FREE(cache_key); + SAFE_FREE(cache_value); + return ret; +} + +/***************************************************************************** +Get an account policy from the cache +*****************************************************************************/ + +bool cache_account_policy_get(enum pdb_policy_type type, uint32_t *value) +{ + const char *policy_name = NULL; + char *cache_key = NULL; + char *cache_value = NULL; + bool ret = False; + + policy_name = decode_account_policy_name(type); + if (policy_name == NULL) { + DEBUG(0,("cache_account_policy_set: no policy found\n")); + return False; + } + + if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) { + DEBUG(0, ("asprintf failed\n")); + goto done; + } + + if (gencache_get(cache_key, talloc_tos(), &cache_value, NULL)) { + int error = 0; + uint32_t tmp; + + tmp = smb_strtoul(cache_value, + NULL, + 10, + &error, + SMB_STR_STANDARD); + if (error != 0) { + goto done; + } + *value = tmp; + ret = True; + } + + done: + SAFE_FREE(cache_key); + TALLOC_FREE(cache_value); + return ret; +} + +/**************************************************************************** +****************************************************************************/ + +struct db_context *get_account_pol_db( void ) +{ + + if ( db == NULL ) { + if ( !init_account_policy() ) { + return NULL; + } + } + + return db; +} |