diff options
author | Andrew Tridgell <tridge@samba.org> | 2009-06-01 10:39:30 +1000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2009-06-01 10:39:30 +1000 |
commit | ba95882155db4f8c10725f47f70ae482d5343f9a (patch) | |
tree | 52c65ddfbcd81f3dcbb3b91183ae043b9c51acd5 /source3/lib | |
parent | 67b83d2489788f1899c253fdab554d0998f9c044 (diff) | |
parent | 14c13620345dfd9f1e18761f103aa66138bf8907 (diff) | |
download | samba-ba95882155db4f8c10725f47f70ae482d5343f9a.tar.gz samba-ba95882155db4f8c10725f47f70ae482d5343f9a.tar.bz2 samba-ba95882155db4f8c10725f47f70ae482d5343f9a.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/ads_flags.c | 150 | ||||
-rw-r--r-- | source3/lib/smbldap.c | 133 | ||||
-rw-r--r-- | source3/lib/util.c | 33 | ||||
-rw-r--r-- | source3/lib/wb_reqtrans.c | 429 | ||||
-rw-r--r-- | source3/lib/wbclient.c | 674 |
5 files changed, 225 insertions, 1194 deletions
diff --git a/source3/lib/ads_flags.c b/source3/lib/ads_flags.c new file mode 100644 index 0000000000..a8fa062f2a --- /dev/null +++ b/source3/lib/ads_flags.c @@ -0,0 +1,150 @@ +/* + Unix SMB/CIFS implementation. + ads (active directory) utility library + + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Andrew Tridgell 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 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" + +/* +translated the ACB_CTRL Flags to UserFlags (userAccountControl) +*/ +uint32 ads_acb2uf(uint32 acb) +{ + uint32 uf = 0x00000000; + + if (acb & ACB_DISABLED) uf |= UF_ACCOUNTDISABLE; + if (acb & ACB_HOMDIRREQ) uf |= UF_HOMEDIR_REQUIRED; + if (acb & ACB_PWNOTREQ) uf |= UF_PASSWD_NOTREQD; + if (acb & ACB_TEMPDUP) uf |= UF_TEMP_DUPLICATE_ACCOUNT; + if (acb & ACB_NORMAL) uf |= UF_NORMAL_ACCOUNT; + if (acb & ACB_MNS) uf |= UF_MNS_LOGON_ACCOUNT; + if (acb & ACB_DOMTRUST) uf |= UF_INTERDOMAIN_TRUST_ACCOUNT; + if (acb & ACB_WSTRUST) uf |= UF_WORKSTATION_TRUST_ACCOUNT; + if (acb & ACB_SVRTRUST) uf |= UF_SERVER_TRUST_ACCOUNT; + if (acb & ACB_PWNOEXP) uf |= UF_DONT_EXPIRE_PASSWD; + if (acb & ACB_AUTOLOCK) uf |= UF_LOCKOUT; + if (acb & ACB_USE_DES_KEY_ONLY) uf |= UF_USE_DES_KEY_ONLY; + if (acb & ACB_SMARTCARD_REQUIRED) uf |= UF_SMARTCARD_REQUIRED; + if (acb & ACB_TRUSTED_FOR_DELEGATION) uf |= UF_TRUSTED_FOR_DELEGATION; + if (acb & ACB_DONT_REQUIRE_PREAUTH) uf |= UF_DONT_REQUIRE_PREAUTH; + if (acb & ACB_NO_AUTH_DATA_REQD) uf |= UF_NO_AUTH_DATA_REQUIRED; + if (acb & ACB_NOT_DELEGATED) uf |= UF_NOT_DELEGATED; + if (acb & ACB_ENC_TXT_PWD_ALLOWED) uf |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED; + + return uf; +} + +/* +translated the UserFlags (userAccountControl) to ACB_CTRL Flags +*/ +uint32 ads_uf2acb(uint32 uf) +{ + uint32 acb = 0x00000000; + + if (uf & UF_ACCOUNTDISABLE) acb |= ACB_DISABLED; + if (uf & UF_HOMEDIR_REQUIRED) acb |= ACB_HOMDIRREQ; + if (uf & UF_PASSWD_NOTREQD) acb |= ACB_PWNOTREQ; + if (uf & UF_MNS_LOGON_ACCOUNT) acb |= ACB_MNS; + if (uf & UF_DONT_EXPIRE_PASSWD) acb |= ACB_PWNOEXP; + if (uf & UF_LOCKOUT) acb |= ACB_AUTOLOCK; + if (uf & UF_USE_DES_KEY_ONLY) acb |= ACB_USE_DES_KEY_ONLY; + if (uf & UF_SMARTCARD_REQUIRED) acb |= ACB_SMARTCARD_REQUIRED; + if (uf & UF_TRUSTED_FOR_DELEGATION) acb |= ACB_TRUSTED_FOR_DELEGATION; + if (uf & UF_DONT_REQUIRE_PREAUTH) acb |= ACB_DONT_REQUIRE_PREAUTH; + if (uf & UF_NO_AUTH_DATA_REQUIRED) acb |= ACB_NO_AUTH_DATA_REQD; + if (uf & UF_NOT_DELEGATED) acb |= ACB_NOT_DELEGATED; + if (uf & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) acb |= ACB_ENC_TXT_PWD_ALLOWED; + + switch (uf & UF_ACCOUNT_TYPE_MASK) + { + case UF_TEMP_DUPLICATE_ACCOUNT: acb |= ACB_TEMPDUP;break; + case UF_NORMAL_ACCOUNT: acb |= ACB_NORMAL;break; + case UF_INTERDOMAIN_TRUST_ACCOUNT: acb |= ACB_DOMTRUST;break; + case UF_WORKSTATION_TRUST_ACCOUNT: acb |= ACB_WSTRUST;break; + case UF_SERVER_TRUST_ACCOUNT: acb |= ACB_SVRTRUST;break; + /*Fix Me: what should we do here? */ + default: acb |= ACB_NORMAL;break; + } + + return acb; +} + +/* +get the accountType from the UserFlags +*/ +uint32 ads_uf2atype(uint32 uf) +{ + uint32 atype = 0x00000000; + + if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST; + + return atype; +} + +/* +get the accountType from the groupType +*/ +uint32 ads_gtype2atype(uint32 gtype) +{ + uint32 atype = 0x00000000; + + switch(gtype) { + case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_GLOBAL_GROUP: + atype = ATYPE_SECURITY_GLOBAL_GROUP; + break; + + case GTYPE_DISTRIBUTION_GLOBAL_GROUP: + atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP; + break; + case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP: + atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP; + break; + case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP: + atype = ATYPE_DISTRIBUTION_LOCAL_GROUP; + break; + } + + return atype; +} + +/* turn a sAMAccountType into a SID_NAME_USE */ +enum lsa_SidType ads_atype_map(uint32 atype) +{ + switch (atype & 0xF0000000) { + case ATYPE_GLOBAL_GROUP: + return SID_NAME_DOM_GRP; + case ATYPE_SECURITY_LOCAL_GROUP: + return SID_NAME_ALIAS; + case ATYPE_ACCOUNT: + return SID_NAME_USER; + default: + DEBUG(1,("hmm, need to map account type 0x%x\n", atype)); + } + return SID_NAME_UNKNOWN; +} diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index b6921c329c..4833b96c5f 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -6,20 +6,20 @@ Copyright (C) Shahms King 2001 Copyright (C) Andrew Bartlett 2002-2003 Copyright (C) Stefan (metze) Metzmacher 2002-2003 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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" @@ -217,13 +217,13 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) { int i = 0; - + while ( table[i].attrib != LDAP_ATTR_LIST_END ) { if ( table[i].attrib == key ) return table[i].name; i++; } - + return NULL; } @@ -236,7 +236,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { { const char **names; int i = 0; - + while ( table[i].attrib != LDAP_ATTR_LIST_END ) i++; i++; @@ -253,7 +253,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { i++; } names[i] = NULL; - + return names; } @@ -266,25 +266,25 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { int max_len) { char **values; - + if ( !attribute ) return False; - + value[0] = '\0'; if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) { DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute)); - + return False; } - + if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, False) == (size_t)-1) { DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n", attribute, values[0])); ldap_value_free(values); return False; } - + ldap_value_free(values); #ifdef DEBUG_PASSWORDS DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value)); @@ -389,23 +389,42 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return result; } - bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib, - struct dom_sid *sid) + bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld, + LDAPMessage *msg, const char *attrib, + DATA_BLOB *blob) { struct berval **values; - bool ret = False; values = ldap_get_values_len(ld, msg, attrib); - if (!values) { return false; } - if (values[0] != NULL) { - ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid); + if (ldap_count_values_len(values) != 1) { + DEBUG(10, ("Expected one value for %s, got %d\n", attrib, + ldap_count_values_len(values))); + return false; } + *blob = data_blob_talloc(mem_ctx, values[0]->bv_val, + values[0]->bv_len); ldap_value_free_len(values); + + return (blob->data != NULL); +} + + bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib, + struct dom_sid *sid) +{ + DATA_BLOB blob; + bool ret; + + if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib, + &blob)) { + return false; + } + ret = sid_parse((char *)blob.data, blob.length, sid); + TALLOC_FREE(blob.data); return ret; } @@ -514,7 +533,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { for (; mods[i]->mod_values[j] != NULL; j++); } mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2); - + if (mods[i]->mod_values == NULL) { smb_panic("smbldap_set_mod: out of memory!"); /* notreached. */ @@ -524,8 +543,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { smb_panic("smbldap_set_mod: String conversion failure!"); /* notreached. */ } - - + mods[i]->mod_values[j] = SMB_STRDUP(utf8_value); TALLOC_FREE(utf8_value); SMB_ASSERT(mods[i]->mod_values[j] != NULL); @@ -561,9 +579,9 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { } /* all of our string attributes are case insensitive */ - + if (existed && newval && (StrCaseCmp(oldval, newval) == 0)) { - + /* Believe it or not, but LDAP will deny a delete and an add at the same time if the values are the same... */ @@ -582,7 +600,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { /* This will also allow modifying single valued attributes * in Novell NDS. In NDS you have to first remove attribute and then * you could add new value */ - + DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval)); smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval); } @@ -640,7 +658,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state) { struct smbldap_state *tmp_ldap_state; struct smbldap_state_lookup *t; - + if ((tmp_ldap_state = smbldap_find_state(ld))) { SMB_ASSERT(tmp_ldap_state == smbldap_state); return; @@ -648,7 +666,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state) t = SMB_XMALLOC_P(struct smbldap_state_lookup); ZERO_STRUCTP(t); - + DLIST_ADD_END(smbldap_state_lookup_list, t, struct smbldap_state_lookup *); t->ld = ld; t->smbldap_state = smbldap_state; @@ -663,11 +681,11 @@ int smb_ldap_start_tls(LDAP *ldap_struct, int version) #ifdef LDAP_OPT_X_TLS int rc; #endif - + if (lp_ldap_ssl() != LDAP_SSL_START_TLS) { return LDAP_SUCCESS; } - + #ifdef LDAP_OPT_X_TLS if (version != LDAP_VERSION3) { DEBUG(0, ("Need LDAPv3 for Start TLS\n")); @@ -697,9 +715,9 @@ int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri) int rc; DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri)); - + #ifdef HAVE_LDAP_INITIALIZE - + rc = ldap_initialize(ldap_struct, uri); if (rc) { DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc))); @@ -721,9 +739,9 @@ int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri) if ( strnequal( uri, "URL:", 4 ) ) { uri += 4; } - + sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port); - + if (port == 0) { if (strequal(protocol, "ldap")) { port = LDAP_PORT; @@ -733,12 +751,12 @@ int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri) DEBUG(0, ("unrecognised protocol (%s)!\n", protocol)); } } - + if ((*ldap_struct = ldap_init(host, port)) == NULL) { DEBUG(0, ("ldap_init failed !\n")); return LDAP_OPERATIONS_ERROR; } - + if (strequal(protocol, "ldaps")) { #ifdef LDAP_OPT_X_TLS int tls = LDAP_OPT_X_TLS_HARD; @@ -746,7 +764,7 @@ int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri) { DEBUG(0, ("Failed to setup a TLS session\n")); } - + DEBUG(3,("LDAPS option set...!\n")); #else DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n")); @@ -792,7 +810,7 @@ int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version) { int version; int rc; - + /* assume the worst */ *new_version = LDAP_VERSION2; @@ -812,7 +830,7 @@ int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version) if (rc) { return rc; } - + *new_version = LDAP_VERSION3; return LDAP_SUCCESS; } @@ -875,7 +893,7 @@ static int smbldap_open_connection (struct smbldap_state *ldap_state) if (rc) { return rc; } - + DEBUG(2, ("smbldap_open_connection: connection opened\n")); return rc; } @@ -890,11 +908,11 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, int *methodp, int freeit, void *arg) { struct smbldap_state *ldap_state = arg; - + /** @TODO Should we be doing something to check what servers we rebind to? Could we get a referral to a machine that we don't want to give our username and password to? */ - + if (freeit) { SAFE_FREE(*whop); if (*credp) { @@ -923,7 +941,7 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, } GetTimeOfDay(&ldap_state->last_rebind); - + return 0; } #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ @@ -998,7 +1016,6 @@ static int rebindproc (LDAP *ldap_struct, char **whop, char **credp, return rebindproc_with_state(ldap_struct, whop, credp, method, freeit, ldap_state); - } # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/ #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ @@ -1039,7 +1056,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite (OpenLDAP) doesnt' seem to support it */ - + DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n", ldap_state->uri, ldap_state->bind_dn)); @@ -1175,17 +1192,17 @@ static NTSTATUS smbldap_close(struct smbldap_state *ldap_state) { if (!ldap_state) return NT_STATUS_INVALID_PARAMETER; - + if (ldap_state->ldap_struct != NULL) { ldap_unbind(ldap_state->ldap_struct); ldap_state->ldap_struct = NULL; } smbldap_delete_state(ldap_state); - + DEBUG(5,("The connection to the LDAP server was closed\n")); /* maybe free the results here --metze */ - + return NT_STATUS_OK; } @@ -1279,7 +1296,7 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, size_t converted_size; SMB_ASSERT(ldap_state); - + DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], " "scope => [%d]\n", base, filter, scope)); @@ -1506,7 +1523,7 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at } } } - + TALLOC_FREE(utf8_dn); return rc; } @@ -1518,7 +1535,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs char *utf8_dn; time_t endtime = time(NULL)+lp_ldap_timeout(); size_t converted_size; - + SMB_ASSERT(ldap_state); DEBUG(5,("smbldap_add: dn => [%s]\n", dn )); @@ -1550,7 +1567,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs } } } - + TALLOC_FREE(utf8_dn); return rc; } @@ -1562,7 +1579,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) char *utf8_dn; time_t endtime = time(NULL)+lp_ldap_timeout(); size_t converted_size; - + SMB_ASSERT(ldap_state); DEBUG(5,("smbldap_delete: dn => [%s]\n", dn )); @@ -1594,7 +1611,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) } } } - + TALLOC_FREE(utf8_dn); return rc; } @@ -1607,7 +1624,7 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state, int rc = LDAP_SERVER_DOWN; int attempts = 0; time_t endtime = time(NULL)+lp_ldap_timeout(); - + if (!ldap_state) return (-1); @@ -1636,7 +1653,7 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state, } } } - + return rc; } @@ -1664,7 +1681,7 @@ static void smbldap_idle_fn(struct event_context *event_ctx, DEBUG(10,("ldap connection not connected...\n")); return; } - + if ((state->last_use+SMBLDAP_IDLE_TIME) > now.tv_sec) { DEBUG(10,("ldap connection not idle...\n")); @@ -1675,7 +1692,7 @@ static void smbldap_idle_fn(struct event_context *event_ctx, private_data); return; } - + DEBUG(7,("ldap connection idle...closing connection\n")); smbldap_close(state); } @@ -1687,7 +1704,7 @@ static void smbldap_idle_fn(struct event_context *event_ctx, void smbldap_free_struct(struct smbldap_state **ldap_state) { smbldap_close(*ldap_state); - + if ((*ldap_state)->bind_secret) { memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret)); } diff --git a/source3/lib/util.c b/source3/lib/util.c index 8e67edeae6..b85f29e136 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -495,39 +495,6 @@ void set_cmdline_auth_info_getpass(struct user_auth_info *auth_info) TALLOC_FREE(frame); } -/**************************************************************************** - Add a gid to an array of gids if it's not already there. -****************************************************************************/ - -bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid, - gid_t **gids, size_t *num_gids) -{ - int i; - - if ((*num_gids != 0) && (*gids == NULL)) { - /* - * A former call to this routine has failed to allocate memory - */ - return False; - } - - for (i=0; i<*num_gids; i++) { - if ((*gids)[i] == gid) { - return True; - } - } - - *gids = TALLOC_REALLOC_ARRAY(mem_ctx, *gids, gid_t, *num_gids+1); - if (*gids == NULL) { - *num_gids = 0; - return False; - } - - (*gids)[*num_gids] = gid; - *num_gids += 1; - return True; -} - /******************************************************************* Check if a file exists - call vfs_file_exist for samba files. ********************************************************************/ diff --git a/source3/lib/wb_reqtrans.c b/source3/lib/wb_reqtrans.c deleted file mode 100644 index 55883ba8c7..0000000000 --- a/source3/lib/wb_reqtrans.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Async transfer of winbindd_request and _response structs - - Copyright (C) Volker Lendecke 2008 - - 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 "wbc_async.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_WINBIND - -struct req_read_state { - struct winbindd_request *wb_req; - size_t max_extra_data; - ssize_t ret; -}; - -static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data); -static void wb_req_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - int fd, size_t max_extra_data) -{ - struct tevent_req *req, *subreq; - struct req_read_state *state; - - req = tevent_req_create(mem_ctx, &state, struct req_read_state); - if (req == NULL) { - return NULL; - } - state->max_extra_data = max_extra_data; - - subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_req_read_done, req); - return req; -} - -static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data) -{ - struct req_read_state *state = talloc_get_type_abort( - private_data, struct req_read_state); - struct winbindd_request *req = (struct winbindd_request *)buf; - - if (buflen == 4) { - if (req->length != sizeof(struct winbindd_request)) { - DEBUG(0, ("wb_req_read_len: Invalid request size " - "received: %d (expected %d)\n", - (int)req->length, - (int)sizeof(struct winbindd_request))); - return -1; - } - return sizeof(struct winbindd_request) - 4; - } - - if ((state->max_extra_data != 0) - && (req->extra_len > state->max_extra_data)) { - DEBUG(3, ("Got request with %d bytes extra data on " - "unprivileged socket\n", (int)req->extra_len)); - return -1; - } - - return req->extra_len; -} - -static void wb_req_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct req_read_state *state = tevent_req_data( - req, struct req_read_state); - int err; - uint8_t *buf; - - state->ret = read_packet_recv(subreq, state, &buf, &err); - TALLOC_FREE(subreq); - if (state->ret == -1) { - tevent_req_error(req, err); - return; - } - - state->wb_req = (struct winbindd_request *)buf; - - if (state->wb_req->extra_len != 0) { - state->wb_req->extra_data.data = - (char *)buf + sizeof(struct winbindd_request); - } else { - state->wb_req->extra_data.data = NULL; - } - tevent_req_done(req); -} - -ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_request **preq, int *err) -{ - struct req_read_state *state = tevent_req_data( - req, struct req_read_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *preq = talloc_move(mem_ctx, &state->wb_req); - return state->ret; -} - -struct req_write_state { - struct iovec iov[2]; - ssize_t ret; -}; - -static void wb_req_write_done(struct tevent_req *subreq); - -struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req) -{ - struct tevent_req *req, *subreq; - struct req_write_state *state; - int count = 1; - - req = tevent_req_create(mem_ctx, &state, struct req_write_state); - if (req == NULL) { - return NULL; - } - - state->iov[0].iov_base = (void *)wb_req; - state->iov[0].iov_len = sizeof(struct winbindd_request); - - if (wb_req->extra_len != 0) { - state->iov[1].iov_base = (void *)wb_req->extra_data.data; - state->iov[1].iov_len = wb_req->extra_len; - count = 2; - } - - subreq = writev_send(state, ev, queue, fd, true, state->iov, count); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_req_write_done, req); - return req; -} - -static void wb_req_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct req_write_state *state = tevent_req_data( - req, struct req_write_state); - int err; - - state->ret = writev_recv(subreq, &err); - TALLOC_FREE(subreq); - if (state->ret < 0) { - tevent_req_error(req, err); - return; - } - tevent_req_done(req); -} - -ssize_t wb_req_write_recv(struct tevent_req *req, int *err) -{ - struct req_write_state *state = tevent_req_data( - req, struct req_write_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - return state->ret; -} - -struct resp_read_state { - struct winbindd_response *wb_resp; - ssize_t ret; -}; - -static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data); -static void wb_resp_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, int fd) -{ - struct tevent_req *req, *subreq; - struct resp_read_state *state; - - req = tevent_req_create(mem_ctx, &state, struct resp_read_state); - if (req == NULL) { - return NULL; - } - - subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_resp_read_done, req); - return req; -} - -static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data) -{ - struct winbindd_response *resp = (struct winbindd_response *)buf; - - if (buflen == 4) { - if (resp->length < sizeof(struct winbindd_response)) { - DEBUG(0, ("wb_resp_read_len: Invalid response size " - "received: %d (expected at least%d)\n", - (int)resp->length, - (int)sizeof(struct winbindd_response))); - return -1; - } - } - return resp->length - buflen; -} - -static void wb_resp_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct resp_read_state *state = tevent_req_data( - req, struct resp_read_state); - uint8_t *buf; - int err; - - state->ret = read_packet_recv(subreq, state, &buf, &err); - TALLOC_FREE(subreq); - if (state->ret == -1) { - tevent_req_error(req, err); - return; - } - - state->wb_resp = (struct winbindd_response *)buf; - - if (state->wb_resp->length > sizeof(struct winbindd_response)) { - state->wb_resp->extra_data.data = - (char *)buf + sizeof(struct winbindd_response); - } else { - state->wb_resp->extra_data.data = NULL; - } - tevent_req_done(req); -} - -ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presp, int *err) -{ - struct resp_read_state *state = tevent_req_data( - req, struct resp_read_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *presp = talloc_move(mem_ctx, &state->wb_resp); - return state->ret; -} - -struct resp_write_state { - struct iovec iov[2]; - ssize_t ret; -}; - -static void wb_resp_write_done(struct tevent_req *subreq); - -struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_response *wb_resp) -{ - struct tevent_req *req, *subreq; - struct resp_write_state *state; - int count = 1; - - req = tevent_req_create(mem_ctx, &state, struct resp_write_state); - if (req == NULL) { - return NULL; - } - - state->iov[0].iov_base = (void *)wb_resp; - state->iov[0].iov_len = sizeof(struct winbindd_response); - - if (wb_resp->length > sizeof(struct winbindd_response)) { - state->iov[1].iov_base = (void *)wb_resp->extra_data.data; - state->iov[1].iov_len = - wb_resp->length - sizeof(struct winbindd_response); - count = 2; - } - - subreq = writev_send(state, ev, queue, fd, true, state->iov, count); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_resp_write_done, req); - return req; -} - -static void wb_resp_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct resp_write_state *state = tevent_req_data( - req, struct resp_write_state); - int err; - - state->ret = writev_recv(subreq, &err); - TALLOC_FREE(subreq); - if (state->ret < 0) { - tevent_req_error(req, err); - return; - } - tevent_req_done(req); -} - -ssize_t wb_resp_write_recv(struct tevent_req *req, int *err) -{ - struct resp_write_state *state = tevent_req_data( - req, struct resp_write_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - return state->ret; -} - -struct wb_simple_trans_state { - struct tevent_context *ev; - int fd; - struct winbindd_response *wb_resp; -}; - -static void wb_simple_trans_write_done(struct tevent_req *subreq); -static void wb_simple_trans_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req) -{ - struct tevent_req *req, *subreq; - struct wb_simple_trans_state *state; - - req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state); - if (req == NULL) { - return NULL; - } - - wb_req->length = sizeof(struct winbindd_request); - - state->ev = ev; - state->fd = fd; - - subreq = wb_req_write_send(state, ev, queue, fd, wb_req); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_simple_trans_write_done, req); - - return req; -} - -static void wb_simple_trans_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - ssize_t ret; - int err; - - ret = wb_req_write_recv(subreq, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, err); - return; - } - subreq = wb_resp_read_send(state, state->ev, state->fd); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_simple_trans_read_done, req); -} - -static void wb_simple_trans_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - ssize_t ret; - int err; - - ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, err); - return; - } - - tevent_req_done(req); -} - -int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse, int *err) -{ - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *presponse = talloc_move(mem_ctx, &state->wb_resp); - return 0; -} diff --git a/source3/lib/wbclient.c b/source3/lib/wbclient.c deleted file mode 100644 index 164cfc9691..0000000000 --- a/source3/lib/wbclient.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Infrastructure for async winbind requests - Copyright (C) Volker Lendecke 2008 - - 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 "wbc_async.h" - -wbcErr map_wbc_err_from_errno(int error) -{ - switch(error) { - case EPERM: - case EACCES: - return WBC_ERR_AUTH_ERROR; - case ENOMEM: - return WBC_ERR_NO_MEMORY; - case EIO: - default: - return WBC_ERR_UNKNOWN_FAILURE; - } -} - -bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err) -{ - enum tevent_req_state state; - uint64_t error; - if (!tevent_req_is_error(req, &state, &error)) { - *pwbc_err = WBC_ERR_SUCCESS; - return false; - } - - switch (state) { - case TEVENT_REQ_USER_ERROR: - *pwbc_err = error; - break; - case TEVENT_REQ_TIMED_OUT: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - case TEVENT_REQ_NO_MEMORY: - *pwbc_err = WBC_ERR_NO_MEMORY; - break; - default: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - } - return true; -} - -wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req) -{ - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - return WBC_ERR_SUCCESS; -} - -struct wb_context { - struct tevent_queue *queue; - int fd; - bool is_priv; -}; - -static int make_nonstd_fd(int fd) -{ - int i; - int sys_errno = 0; - int fds[3]; - int num_fds = 0; - - if (fd == -1) { - return -1; - } - while (fd < 3) { - fds[num_fds++] = fd; - fd = dup(fd); - if (fd == -1) { - sys_errno = errno; - break; - } - } - for (i=0; i<num_fds; i++) { - close(fds[i]); - } - if (fd == -1) { - errno = sys_errno; - } - return fd; -} - -/**************************************************************************** - Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, - else - if SYSV use O_NDELAY - if BSD use FNDELAY - Set close on exec also. -****************************************************************************/ - -static int make_safe_fd(int fd) -{ - int result, flags; - int new_fd = make_nonstd_fd(fd); - - if (new_fd == -1) { - goto fail; - } - - /* Socket should be nonblocking. */ - -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if ((flags = fcntl(new_fd, F_GETFL)) == -1) { - goto fail; - } - - flags |= FLAG_TO_SET; - if (fcntl(new_fd, F_SETFL, flags) == -1) { - goto fail; - } - -#undef FLAG_TO_SET - - /* Socket should be closed on exec() */ -#ifdef FD_CLOEXEC - result = flags = fcntl(new_fd, F_GETFD, 0); - if (flags >= 0) { - flags |= FD_CLOEXEC; - result = fcntl( new_fd, F_SETFD, flags ); - } - if (result < 0) { - goto fail; - } -#endif - return new_fd; - - fail: - if (new_fd != -1) { - int sys_errno = errno; - close(new_fd); - errno = sys_errno; - } - return -1; -} - -struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx) -{ - struct wb_context *result; - - result = talloc(mem_ctx, struct wb_context); - if (result == NULL) { - return NULL; - } - result->queue = tevent_queue_create(result, "wb_trans"); - if (result->queue == NULL) { - TALLOC_FREE(result); - return NULL; - } - result->fd = -1; - result->is_priv = false; - return result; -} - -struct wb_connect_state { - int dummy; -}; - -static void wbc_connect_connected(struct tevent_req *subreq); - -static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - const char *dir) -{ - struct tevent_req *result, *subreq; - struct wb_connect_state *state; - struct sockaddr_un sunaddr; - struct stat st; - char *path = NULL; - wbcErr wbc_err; - - result = tevent_req_create(mem_ctx, &state, struct wb_connect_state); - if (result == NULL) { - return NULL; - } - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - /* Check permissions on unix socket directory */ - - if (lstat(dir, &st) == -1) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - if (!S_ISDIR(st.st_mode) || - (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - /* Connect to socket */ - - path = talloc_asprintf(talloc_tos(), "%s/%s", dir, - WINBINDD_SOCKET_NAME); - if (path == NULL) { - goto nomem; - } - - sunaddr.sun_family = AF_UNIX; - strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); - TALLOC_FREE(path); - - /* If socket file doesn't exist, don't bother trying to connect - with retry. This is an attempt to make the system usable when - the winbindd daemon is not running. */ - - if ((lstat(sunaddr.sun_path, &st) == -1) - || !S_ISSOCK(st.st_mode) - || (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); - if (wb_ctx->fd == -1) { - wbc_err = map_wbc_err_from_errno(errno); - goto post_status; - } - - subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd, - (struct sockaddr *)(void *)&sunaddr, - sizeof(sunaddr)); - if (subreq == NULL) { - goto nomem; - } - tevent_req_set_callback(subreq, wbc_connect_connected, result); - return result; - - post_status: - tevent_req_error(result, wbc_err); - return tevent_req_post(result, ev); - nomem: - TALLOC_FREE(result); - return NULL; -} - -static void wbc_connect_connected(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - int res, err; - - res = async_connect_recv(subreq, &err); - TALLOC_FREE(subreq); - if (res == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - tevent_req_done(req); -} - -static wbcErr wb_connect_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -static const char *winbindd_socket_dir(void) -{ -#ifdef SOCKET_WRAPPER - const char *env_dir; - - env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); - if (env_dir) { - return env_dir; - } -#endif - - return WINBINDD_SOCKET_DIR; -} - -struct wb_open_pipe_state { - struct wb_context *wb_ctx; - struct tevent_context *ev; - bool need_priv; - struct winbindd_request wb_req; -}; - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_ping_done(struct tevent_req *subreq); -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq); - -static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - bool need_priv) -{ - struct tevent_req *result, *subreq; - struct wb_open_pipe_state *state; - - result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state); - if (result == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->need_priv = need_priv; - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir()); - if (subreq == NULL) { - goto fail; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done, - result); - return result; - - fail: - TALLOC_FREE(result); - return NULL; -} - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - state->wb_ctx->is_priv = true; - tevent_req_error(req, wbc_err); - return; - } - - ZERO_STRUCT(state->wb_req); - state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req); -} - -static void wb_open_pipe_ping_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - if (!state->need_priv) { - tevent_req_done(req); - return; - } - - state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req); -} - -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp = NULL; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - - subreq = wb_connect_send(state, state->ev, state->wb_ctx, - (char *)wb_resp->extra_data.data); - TALLOC_FREE(wb_resp); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req); -} - -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - tevent_req_error(req, wbc_err); - return; - } - state->wb_ctx->is_priv = true; - tevent_req_done(req); -} - -static wbcErr wb_open_pipe_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -struct wb_trans_state { - struct wb_trans_state *prev, *next; - struct wb_context *wb_ctx; - struct tevent_context *ev; - struct winbindd_request *wb_req; - struct winbindd_response *wb_resp; - bool need_priv; -}; - -static bool closed_fd(int fd) -{ - struct timeval tv; - fd_set r_fds; - int selret; - - if (fd == -1) { - return true; - } - - FD_ZERO(&r_fds); - FD_SET(fd, &r_fds); - ZERO_STRUCT(tv); - - selret = select(fd+1, &r_fds, NULL, NULL, &tv); - if (selret == -1) { - return true; - } - if (selret == 0) { - return false; - } - return (FD_ISSET(fd, &r_fds)); -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data); -static void wb_trans_connect_done(struct tevent_req *subreq); -static void wb_trans_done(struct tevent_req *subreq); -static void wb_trans_retry_wait_done(struct tevent_req *subreq); - -struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, bool need_priv, - struct winbindd_request *wb_req) -{ - struct tevent_req *req; - struct wb_trans_state *state; - - req = tevent_req_create(mem_ctx, &state, struct wb_trans_state); - if (req == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->wb_req = wb_req; - state->need_priv = need_priv; - - if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger, - NULL)) { - tevent_req_nomem(NULL, req); - return tevent_req_post(req, ev); - } - return req; -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - struct tevent_req *subreq; - - if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - if ((state->wb_ctx->fd == -1) - || (state->need_priv && !state->wb_ctx->is_priv)) { - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); - return; - } - - state->wb_req->pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static bool wb_trans_retry(struct tevent_req *req, - struct wb_trans_state *state, - wbcErr wbc_err) -{ - struct tevent_req *subreq; - - if (WBC_ERROR_IS_OK(wbc_err)) { - return false; - } - - if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) { - /* - * Winbind not around or we can't connect to the pipe. Fail - * immediately. - */ - tevent_req_error(req, wbc_err); - return true; - } - - /* - * The transfer as such failed, retry after one second - */ - - if (state->wb_ctx->fd != -1) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - subreq = tevent_wakeup_send(state, state->ev, - timeval_current_ofs(1, 0)); - if (tevent_req_nomem(subreq, req)) { - return true; - } - tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req); - return true; -} - -static void wb_trans_retry_wait_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - bool ret; - - ret = tevent_wakeup_recv(subreq); - TALLOC_FREE(subreq); - if (!ret) { - tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE); - return; - } - - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); -} - -static void wb_trans_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - wbc_err = wb_open_pipe_recv(subreq); - TALLOC_FREE(subreq); - - if (wb_trans_retry(req, state, wbc_err)) { - return; - } - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static void wb_trans_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err); - TALLOC_FREE(subreq); - if ((ret == -1) - && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) { - return; - } - - tevent_req_done(req); -} - -wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - *presponse = talloc_move(mem_ctx, &state->wb_resp); - return WBC_ERR_SUCCESS; -} |