summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2007-12-26 17:58:55 +0100
committerVolker Lendecke <vl@samba.org>2007-12-26 18:57:15 +0100
commite70c97ef85b309d6e005c07e16a003725d21ffc8 (patch)
tree5242d8ac652b48c0e0b49638837860ba9f6cc16c /source3
parentc90f731ef21d682f808cf3da0f24510a2eaea4ff (diff)
downloadsamba-e70c97ef85b309d6e005c07e16a003725d21ffc8.tar.gz
samba-e70c97ef85b309d6e005c07e16a003725d21ffc8.tar.bz2
samba-e70c97ef85b309d6e005c07e16a003725d21ffc8.zip
Remove the sampwent interface
(This used to be commit 9e80b969fb40766de2c9b1a05d16bf4d4c6e46f7)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/passdb.h9
-rw-r--r--source3/passdb/pdb_interface.c123
-rw-r--r--source3/passdb/pdb_ldap.c102
-rw-r--r--source3/passdb/pdb_smbpasswd.c76
-rw-r--r--source3/passdb/pdb_tdb.c146
-rw-r--r--source3/torture/pdbtest.c18
6 files changed, 3 insertions, 471 deletions
diff --git a/source3/include/passdb.h b/source3/include/passdb.h
index bb8a336b8c..b72ec6b0ba 100644
--- a/source3/include/passdb.h
+++ b/source3/include/passdb.h
@@ -242,20 +242,15 @@ struct pdb_search {
* changed to version 14 to move lookup_rids and lookup_names to return
* enum lsa_SidType rather than uint32.
* Changed to 16 for access to the trusted domain passwords (obnox).
+ * Changed to 17, the sampwent interface is gone.
*/
-#define PASSDB_INTERFACE_VERSION 16
+#define PASSDB_INTERFACE_VERSION 17
struct pdb_methods
{
const char *name; /* What name got this module */
- NTSTATUS (*setsampwent)(struct pdb_methods *, bool update, uint32 acb_mask);
-
- void (*endsampwent)(struct pdb_methods *);
-
- NTSTATUS (*getsampwent)(struct pdb_methods *, struct samu *user);
-
NTSTATUS (*getsampwnam)(struct pdb_methods *, struct samu *sam_acct, const char *username);
NTSTATUS (*getsampwsid)(struct pdb_methods *, struct samu *sam_acct, const DOM_SID *sid);
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
index 198960550b..2102b579ec 100644
--- a/source3/passdb/pdb_interface.c
+++ b/source3/passdb/pdb_interface.c
@@ -208,33 +208,6 @@ static struct pdb_methods *pdb_get_methods(void)
return pdb_get_methods_reload(False);
}
-/******************************************************************
- Backward compatibility functions for the original passdb interface
-*******************************************************************/
-
-bool pdb_setsampwent(bool update, uint16 acb_mask)
-{
- struct pdb_methods *pdb = pdb_get_methods();
- return NT_STATUS_IS_OK(pdb->setsampwent(pdb, update, acb_mask));
-}
-
-void pdb_endsampwent(void)
-{
- struct pdb_methods *pdb = pdb_get_methods();
- pdb->endsampwent(pdb);
-}
-
-bool pdb_getsampwent(struct samu *user)
-{
- struct pdb_methods *pdb = pdb_get_methods();
-
- if ( !NT_STATUS_IS_OK(pdb->getsampwent(pdb, user) ) ) {
- return False;
- }
-
- return True;
-}
-
bool pdb_getsampwnam(struct samu *sam_acct, const char *username)
{
struct pdb_methods *pdb = pdb_get_methods();
@@ -1181,21 +1154,6 @@ static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods,
return NT_STATUS_NOT_IMPLEMENTED;
}
-static NTSTATUS pdb_default_setsampwent(struct pdb_methods *methods, bool update, uint32 acb_mask)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
-static NTSTATUS pdb_default_getsampwent(struct pdb_methods *methods, struct samu *user)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
-static void pdb_default_endsampwent(struct pdb_methods *methods)
-{
- return; /* NT_STATUS_NOT_IMPLEMENTED; */
-}
-
static NTSTATUS pdb_default_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value)
{
return account_policy_get(policy_index, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
@@ -1738,7 +1696,7 @@ static NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods,
}
#endif
-static struct pdb_search *pdb_search_init(enum pdb_search_type type)
+struct pdb_search *pdb_search_init(enum pdb_search_type type)
{
TALLOC_CTX *mem_ctx;
struct pdb_search *result;
@@ -1795,81 +1753,6 @@ static void fill_displayentry(TALLOC_CTX *mem_ctx, uint32 rid,
entry->description = "";
}
-static bool user_search_in_progress = False;
-struct user_search {
- uint16 acct_flags;
-};
-
-static bool next_entry_users(struct pdb_search *s,
- struct samr_displayentry *entry)
-{
- struct user_search *state = (struct user_search *)s->private_data;
- struct samu *user = NULL;
-
- next:
- if ( !(user = samu_new( NULL )) ) {
- DEBUG(0, ("next_entry_users: samu_new() failed!\n"));
- return False;
- }
-
- if (!pdb_getsampwent(user)) {
- TALLOC_FREE(user);
- return False;
- }
-
- if ((state->acct_flags != 0) &&
- ((pdb_get_acct_ctrl(user) & state->acct_flags) == 0)) {
- TALLOC_FREE(user);
- goto next;
- }
-
- fill_displayentry(s->mem_ctx, pdb_get_user_rid(user),
- pdb_get_acct_ctrl(user), pdb_get_username(user),
- pdb_get_fullname(user), pdb_get_acct_desc(user),
- entry);
-
- TALLOC_FREE(user);
- return True;
-}
-
-static void search_end_users(struct pdb_search *search)
-{
- pdb_endsampwent();
- user_search_in_progress = False;
-}
-
-static bool pdb_default_search_users(struct pdb_methods *methods,
- struct pdb_search *search,
- uint32 acct_flags)
-{
- struct user_search *state;
-
- if (user_search_in_progress) {
- DEBUG(1, ("user search in progress\n"));
- return False;
- }
-
- if (!pdb_setsampwent(False, acct_flags)) {
- DEBUG(5, ("Could not start search\n"));
- return False;
- }
-
- user_search_in_progress = True;
-
- state = TALLOC_P(search->mem_ctx, struct user_search);
- if (state == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return False;
- }
-
- state->acct_flags = acct_flags;
-
- search->private_data = state;
- search->next_entry = next_entry_users;
- search->search_end = search_end_users;
- return True;
-}
-
struct group_search {
GROUP_MAP *groups;
size_t num_groups, current_group;
@@ -2136,9 +2019,6 @@ NTSTATUS make_pdb_method( struct pdb_methods **methods )
return NT_STATUS_NO_MEMORY;
}
- (*methods)->setsampwent = pdb_default_setsampwent;
- (*methods)->endsampwent = pdb_default_endsampwent;
- (*methods)->getsampwent = pdb_default_getsampwent;
(*methods)->getsampwnam = pdb_default_getsampwnam;
(*methods)->getsampwsid = pdb_default_getsampwsid;
(*methods)->create_user = pdb_default_create_user;
@@ -2180,7 +2060,6 @@ NTSTATUS make_pdb_method( struct pdb_methods **methods )
(*methods)->gid_to_sid = pdb_default_gid_to_sid;
(*methods)->sid_to_id = pdb_default_sid_to_id;
- (*methods)->search_users = pdb_default_search_users;
(*methods)->search_groups = pdb_default_search_groups;
(*methods)->search_aliases = pdb_default_search_aliases;
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
index bc912ada29..b638219466 100644
--- a/source3/passdb/pdb_ldap.c
+++ b/source3/passdb/pdb_ldap.c
@@ -1454,79 +1454,6 @@ static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
}
/**********************************************************************
- Connect to LDAP server for password enumeration.
-*********************************************************************/
-
-static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, bool update, uint32 acb_mask)
-{
- struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
- int rc;
- char *filter = NULL;
- const char *suffix;
- const char **attr_list;
- bool machine_mask = False, user_mask = False;
- NTSTATUS status = NT_STATUS_OK;
- TALLOC_CTX *ctx = talloc_init("ldapsam_setsampwent");
-
- if (!ctx) {
- return NT_STATUS_NO_MEMORY;
- }
- filter = talloc_asprintf(ctx, "(&%s%s)", "(uid=%u)",
- get_objclass_filter(ldap_state->schema_ver));
- if (!filter) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- filter = talloc_all_string_sub(ctx, filter, "%u", "*");
- if (!filter) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- machine_mask = ((acb_mask != 0) && (acb_mask & (ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)));
- user_mask = ((acb_mask != 0) && (acb_mask & ACB_NORMAL));
-
- if (machine_mask) {
- suffix = lp_ldap_machine_suffix();
- } else if (user_mask) {
- suffix = lp_ldap_user_suffix();
- } else {
- suffix = lp_ldap_suffix();
- }
-
- DEBUG(10,("ldapsam_setsampwent: LDAP Query for acb_mask 0x%x will use suffix %s\n",
- acb_mask, suffix));
-
- attr_list = get_userattr_list(NULL, ldap_state->schema_ver);
- rc = smbldap_search(ldap_state->smbldap_state, suffix, LDAP_SCOPE_SUBTREE, filter,
- attr_list, 0, &ldap_state->result);
- TALLOC_FREE( attr_list );
-
- if (rc != LDAP_SUCCESS) {
- DEBUG(0, ("ldapsam_setsampwent: LDAP search failed: %s\n", ldap_err2string(rc)));
- DEBUG(3, ("ldapsam_setsampwent: Query was: %s, %s\n", suffix, filter));
- ldap_msgfree(ldap_state->result);
- ldap_state->result = NULL;
- status = NT_STATUS_UNSUCCESSFUL;
- goto out;
- }
-
- DEBUG(2, ("ldapsam_setsampwent: %d entries in the base %s\n",
- ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
- ldap_state->result), suffix));
-
- ldap_state->entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
- ldap_state->result);
- ldap_state->index = 0;
-
- out:
-
- TALLOC_FREE(ctx);
- return status;
-}
-
-/**********************************************************************
End enumeration of the LDAP password list.
*********************************************************************/
@@ -1539,32 +1466,6 @@ static void ldapsam_endsampwent(struct pdb_methods *my_methods)
}
}
-/**********************************************************************
-Get the next entry in the LDAP password database.
-*********************************************************************/
-
-static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods,
- struct samu *user)
-{
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- struct ldapsam_privates *ldap_state =
- (struct ldapsam_privates *)my_methods->private_data;
- bool bret = False;
-
- while (!bret) {
- if (!ldap_state->entry)
- return ret;
-
- ldap_state->index++;
- bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry);
-
- ldap_state->entry = ldap_next_entry(priv2ld(ldap_state),
- ldap_state->entry);
- }
-
- return NT_STATUS_OK;
-}
-
static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list,
const char *new_attr)
{
@@ -6172,9 +6073,6 @@ static NTSTATUS pdb_init_ldapsam_common(struct pdb_methods **pdb_method, const c
(*pdb_method)->name = "ldapsam";
- (*pdb_method)->setsampwent = ldapsam_setsampwent;
- (*pdb_method)->endsampwent = ldapsam_endsampwent;
- (*pdb_method)->getsampwent = ldapsam_getsampwent;
(*pdb_method)->getsampwnam = ldapsam_getsampwnam;
(*pdb_method)->getsampwsid = ldapsam_getsampwsid;
(*pdb_method)->add_sam_account = ldapsam_add_sam_account;
diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c
index 21cd988cff..6cf54fbdf6 100644
--- a/source3/passdb/pdb_smbpasswd.c
+++ b/source3/passdb/pdb_smbpasswd.c
@@ -1264,79 +1264,6 @@ static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state,
Functions to be implemented by the new passdb API
****************************************************************/
-static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, bool update, uint32 acb_mask)
-{
- struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
-
- smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
- update ? PWF_UPDATE : PWF_READ,
- &(smbpasswd_state->pw_file_lock_depth));
-
- /* did we fail? Should we try to create it? */
- if (!smbpasswd_state->pw_file && update && errno == ENOENT) {
- FILE *fp;
- /* slprintf(msg_str,msg_str_len-1,
- "smbpasswd file did not exist - attempting to create it.\n"); */
- DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
- fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w");
- if (fp) {
- fprintf(fp, "# Samba SMB password file\n");
- fclose(fp);
- }
-
- smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
- update ? PWF_UPDATE : PWF_READ,
- &(smbpasswd_state->pw_file_lock_depth));
- }
-
- if (smbpasswd_state->pw_file != NULL)
- return NT_STATUS_OK;
- else
- return NT_STATUS_UNSUCCESSFUL;
-}
-
-static void smbpasswd_endsampwent (struct pdb_methods *my_methods)
-{
- struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
- endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth));
-}
-
-/*****************************************************************
- ****************************************************************/
-
-static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, struct samu *user)
-{
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
- struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
- struct smb_passwd *pw_buf=NULL;
- bool done = False;
-
- DEBUG(5,("pdb_getsampwent\n"));
-
- if ( !user ) {
- DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n"));
- return nt_status;
- }
-
- while (!done) {
- /* do we have an entry? */
- pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file);
- if (pw_buf == NULL)
- return nt_status;
-
- /* build the struct samu entry from the smb_passwd struct.
- We loop in case the user in the pdb does not exist in
- the local system password file */
- if (build_sam_account(smbpasswd_state, user, pw_buf))
- done = True;
- }
-
- DEBUG(5,("getsampwent (smbpasswd): done\n"));
-
- /* success */
- return NT_STATUS_OK;
-}
-
/****************************************************************
Search smbpasswd file by iterating over the entries. Do not
call getpwnam() for unix account information until we have found
@@ -1730,9 +1657,6 @@ static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char
(*pdb_method)->name = "smbpasswd";
- (*pdb_method)->setsampwent = smbpasswd_setsampwent;
- (*pdb_method)->endsampwent = smbpasswd_endsampwent;
- (*pdb_method)->getsampwent = smbpasswd_getsampwent;
(*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
(*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
(*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
index 1c2278ba7d..1277b9c395 100644
--- a/source3/passdb/pdb_tdb.c
+++ b/source3/passdb/pdb_tdb.c
@@ -44,13 +44,6 @@ static int tdbsam_debug_level = DBGC_ALL;
#define RIDPREFIX "RID_"
#define PRIVPREFIX "PRIV_"
-struct pwent_list {
- struct pwent_list *prev, *next;
- TDB_DATA key;
-};
-static struct pwent_list *tdbsam_pwent_list;
-static bool pwent_initialized;
-
/* GLOBAL TDB SAM CONTEXT */
static TDB_CONTEXT *tdbsam;
@@ -891,134 +884,6 @@ void tdbsam_close( void )
return;
}
-/****************************************************************************
- creates a list of user keys
-****************************************************************************/
-
-static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
-{
- const char *prefix = USERPREFIX;
- int prefixlen = strlen (prefix);
- struct pwent_list *ptr;
-
- if ( strncmp((const char *)key.dptr, prefix, prefixlen) == 0 ) {
- if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
- DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
-
- /* just return 0 and let the traversal continue */
- return 0;
- }
- ZERO_STRUCTP(ptr);
-
- /* save a copy of the key */
-
- ptr->key.dptr = (uint8 *)memdup( key.dptr, key.dsize );
- if (!ptr->key.dptr) {
- DEBUG(0,("tdbsam_traverse_setpwent: memdup failed\n"));
- /* just return 0 and let the traversal continue */
- SAFE_FREE(ptr);
- return 0;
- }
-
- ptr->key.dsize = key.dsize;
-
- DLIST_ADD( tdbsam_pwent_list, ptr );
-
- }
-
- return 0;
-}
-
-/***************************************************************
- Open the TDB passwd database for SAM account enumeration.
- Save a list of user keys for iteration.
-****************************************************************/
-
-static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, bool update, uint32 acb_mask)
-{
- if ( !tdbsam_open( tdbsam_filename ) ) {
- DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
- pwent_initialized = True;
-
- return NT_STATUS_OK;
-}
-
-
-/***************************************************************
- End enumeration of the TDB passwd list.
-****************************************************************/
-
-static void tdbsam_endsampwent(struct pdb_methods *my_methods)
-{
- struct pwent_list *ptr, *ptr_next;
-
- /* close the tdb only if we have a valid pwent state */
-
- if ( pwent_initialized ) {
- DEBUG(7, ("endtdbpwent: closed sam database.\n"));
- tdbsam_close();
- }
-
- /* clear out any remaining entries in the list */
-
- for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
- ptr_next = ptr->next;
- DLIST_REMOVE( tdbsam_pwent_list, ptr );
- SAFE_FREE( ptr->key.dptr);
- SAFE_FREE( ptr );
- }
-
- pwent_initialized = False;
-}
-
-/*****************************************************************
- Get one struct samu from the TDB (next in line)
-*****************************************************************/
-
-static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
-{
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
- TDB_DATA data;
- struct pwent_list *pkey;
-
- if ( !user ) {
- DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
- return nt_status;
- }
-
- if ( !tdbsam_pwent_list ) {
- DEBUG(4,("tdbsam_getsampwent: end of list\n"));
- return nt_status;
- }
-
- /* pull the next entry */
-
- pkey = tdbsam_pwent_list;
- DLIST_REMOVE( tdbsam_pwent_list, pkey );
-
- data = tdb_fetch(tdbsam, pkey->key);
-
- SAFE_FREE( pkey->key.dptr);
- SAFE_FREE( pkey);
-
- if ( !data.dptr ) {
- DEBUG(5,("pdb_getsampwent: database entry not found. Was the user deleted?\n"));
- return nt_status;
- }
-
- if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
- DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
- }
-
- SAFE_FREE( data.dptr );
-
- return NT_STATUS_OK;
-}
-
/******************************************************************
Lookup a name in the SAM TDB
******************************************************************/
@@ -1306,10 +1171,6 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
{
bool result = True;
- /* invalidate the existing TDB iterator if it is open */
-
- tdbsam_endsampwent( my_methods );
-
#if 0
if ( !pdb_get_group_rid(newpwd) ) {
DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
@@ -1396,10 +1257,6 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
return NT_STATUS_ACCESS_DENIED;
}
- /* invalidate the existing TDB iterator if it is open */
-
- tdbsam_endsampwent( my_methods );
-
if ( !(new_acct = samu_new( NULL )) ) {
return NT_STATUS_NO_MEMORY;
}
@@ -1742,9 +1599,6 @@ static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *loc
(*pdb_method)->name = "tdbsam";
- (*pdb_method)->setsampwent = tdbsam_setsampwent;
- (*pdb_method)->endsampwent = tdbsam_endsampwent;
- (*pdb_method)->getsampwent = tdbsam_getsampwent;
(*pdb_method)->getsampwnam = tdbsam_getsampwnam;
(*pdb_method)->getsampwsid = tdbsam_getsampwsid;
(*pdb_method)->add_sam_account = tdbsam_add_sam_account;
diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c
index 77666bb664..ab7edde85d 100644
--- a/source3/torture/pdbtest.c
+++ b/source3/torture/pdbtest.c
@@ -364,24 +364,6 @@ int main(int argc, char **argv)
get_friendly_nt_error_msg(rv));
}
- pdb->setsampwent(pdb, False, 0);
- while (NT_STATUS_IS_OK(pdb->getsampwent(pdb, out))) {
- if (pdb_get_username(out) == NULL) {
- fprintf(stderr, "Got bad username through getsampwent()\n");
- error = True;
- break;
- }
- if (NT_STATUS_IS_ERR(pdb->getsampwnam(pdb, in, pdb_get_username(out)))) {
- fprintf(stderr, "Error getting samu through getsampwnam() of an account we got through getsampwent!\n");
- error = True;
- continue;
- }
- if (!samu_correct(out, in)) {
- printf("Record gotten through getsampwnam() differs from same record through getsampwent()\n");
- }
- }
- pdb->endsampwent(pdb);
-
TALLOC_FREE(ctx);
if (error) {