sdap_async_connection.c revision 801fcc63a9ec83d76d8d027758f9a0357b34890f
/*
SSSD
Async LDAP Helper routines
Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
Copyright (C) 2010, rhafer@suse.de, Novell Inc.
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 "util/sss_krb5.h"
#include "providers/ldap/sdap_async_private.h"
#define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D
/* ==Connect-to-LDAP-Server=============================================== */
struct sdap_connect_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
int result;
};
struct tevent_context *ev,
struct sdap_options *opts,
const char *uri,
bool use_start_tls)
{
struct tevent_req *req;
struct sdap_connect_state *state;
int ver;
int lret;
int optret;
int msgid;
bool ldap_referrals;
return NULL;
}
return NULL;
}
/* Initialize LDAP handler */
if (lret != LDAP_SUCCESS) {
goto fail;
}
/* Force ldap version to 3 */
ver = LDAP_VERSION3;
if (lret != LDAP_OPT_SUCCESS) {
goto fail;
}
/* TODO: maybe this can be remove when we go async, currently we need it
* to handle EINTR during poll(). */
if (ret != LDAP_OPT_SUCCESS) {
}
/* Set Network Timeout */
if (lret != LDAP_OPT_SUCCESS) {
goto fail;
}
/* Set Default Timeout */
if (lret != LDAP_OPT_SUCCESS) {
goto fail;
}
/* Set Referral chasing */
if (lret != LDAP_OPT_SUCCESS) {
goto fail;
}
goto fail;
}
/* if we do not use start_tls the connection is not really connected yet
* just fake an async procedure and leave connection to the bind call */
if (!use_start_tls) {
return req;
}
if (lret != LDAP_SUCCESS) {
(void*)&errmsg);
if (optret == LDAP_SUCCESS) {
errmsg));
}
else {
ldap_err2string(lret)));
}
goto fail;
}
/* FIXME: get timeouts from configuration, for now 5 secs. */
if (ret) {
goto fail;
}
return req;
fail:
if (ret) {
} else {
if (lret == LDAP_SERVER_DOWN) {
} else {
}
}
return req;
}
{
struct sdap_connect_state);
char *errmsg;
char *tlserr;
int ret;
int optret;
if (error) {
return;
}
if (ret != LDAP_SUCCESS) {
return;
}
return;
}
/* FIXME: take care that ldap_install_tls might block */
if (ret != LDAP_SUCCESS) {
(void*)&tlserr);
if (optret == LDAP_SUCCESS) {
tlserr));
}
else {
ldap_err2string(ret)));
}
return;
}
}
struct sdap_handle **sh)
{
struct sdap_connect_state);
if (!*sh) {
return ENOMEM;
}
return EOK;
}
/* ==Simple-Bind========================================================== */
struct simple_bind_state {
struct tevent_context *ev;
struct sdap_handle *sh;
const char *user_dn;
struct sdap_ppolicy_data *ppolicy;
int result;
};
struct tevent_context *ev,
struct sdap_handle *sh,
const char *user_dn,
{
struct tevent_req *req;
struct simple_bind_state *state;
int msgid;
int ldap_err;
return NULL;
}
0, NULL, 0, &request_controls[0]);
if (ret != LDAP_SUCCESS) {
goto fail;
}
if (ret != LDAP_OPT_SUCCESS) {
} else {
}
goto fail;
}
}
/* FIXME: get timeouts from configuration, for now 5 secs. */
if (ret) {
goto fail;
}
return req;
fail:
if (ret == LDAP_SERVER_DOWN) {
} else {
}
return req;
}
{
struct simple_bind_state);
char *errmsg;
int ret;
int c;
if (error) {
return;
}
&response_controls, 0);
if (ret != LDAP_SUCCESS) {
goto done;
}
if (response_controls == NULL) {
} else {
for (c = 0; response_controls[c] != NULL; c++) {
response_controls[c]->ldctl_oid));
LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
&pp_error);
if (ret != LDAP_SUCCESS) {
goto done;
}
goto done;
}
if (pp_error == PP_changeAfterReset) {
"User must set a new password.\n"));
} else if (pp_grace > 0) {
"[%d] grace logins remaining.\n", pp_grace));
} else if (pp_expire > 0) {
pp_expire));
}
pp_error == PP_passwordExpired) {
DEBUG(4,
("Password expired user must set a new password.\n"));
}
}
}
}
ret = LDAP_SUCCESS;
done:
if (ret == LDAP_SUCCESS) {
} else {
}
}
int *ldaperr,
struct sdap_ppolicy_data **ppolicy)
{
struct simple_bind_state);
*ldaperr = LDAP_OTHER;
return EOK;
}
/* ==SASL-Bind============================================================ */
struct sasl_bind_state {
struct tevent_context *ev;
struct sdap_handle *sh;
const char *sasl_mech;
const char *sasl_user;
int result;
};
struct tevent_context *ev,
struct sdap_handle *sh,
const char *sasl_mech,
const char *sasl_user,
{
struct tevent_req *req;
struct sasl_bind_state *state;
/* FIXME: Warning, this is a sync call!
* No async variant exist in openldap libraries yet */
(*sdap_sasl_interact), state);
if (ret != LDAP_SUCCESS) {
goto fail;
}
}
return req;
fail:
if (ret == LDAP_SERVER_DOWN) {
} else {
}
return req;
}
{
struct sasl_bind_state);
if (!ld) return LDAP_PARAM_ERROR;
case SASL_CB_GETREALM:
case SASL_CB_USER:
case SASL_CB_PASS:
} else {
}
break;
case SASL_CB_AUTHNAME:
} else {
}
break;
case SASL_CB_NOECHOPROMPT:
case SASL_CB_ECHOPROMPT:
goto fail;
}
in++;
}
return LDAP_SUCCESS;
fail:
return LDAP_UNAVAILABLE;
}
{
struct sasl_bind_state);
enum tevent_req_state tstate;
if (tstate != TEVENT_REQ_IN_PROGRESS) {
*ldaperr = LDAP_OTHER;
return err;
}
}
return EOK;
}
/* ==Perform-Kinit-given-keytab-and-principal============================= */
struct sdap_kinit_state {
int result;
};
struct tevent_context *ev,
struct sdap_handle *sh,
int timeout,
const char *keytab,
const char *principal,
const char *realm,
int lifetime)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct sdap_kinit_state *state;
int ret;
lifetime));
return NULL;
}
if (keytab) {
if (ret == -1) {
return NULL;
}
}
timeout);
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct sdap_kinit_state);
int ret;
int result;
return;
}
if (ret == -1) {
}
return;
}
}
enum sdap_result *result,
{
struct sdap_kinit_state);
enum tevent_req_state tstate;
if (tstate != TEVENT_REQ_IN_PROGRESS) {
*result = SDAP_ERROR;
return err;
}
}
return EOK;
}
/* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state {
const char *user_dn;
struct sdap_ppolicy_data *ppolicy;
int result;
bool is_sasl;
};
/* TODO: handle sasl_cred */
struct tevent_context *ev,
struct sdap_handle *sh,
const char *sasl_mech,
const char *sasl_user,
const char *user_dn,
const char *authtok_type,
struct dp_opt_blob authtok)
{
struct sdap_auth_state *state;
return NULL;
}
if (sasl_mech) {
if (!subreq) {
}
} else {
if (!subreq) {
}
}
return req;
}
{
struct tevent_req);
struct sdap_auth_state);
int ret;
} else {
}
return;
}
}
enum sdap_result *result,
struct sdap_ppolicy_data **ppolicy)
{
struct sdap_auth_state);
*result = SDAP_ERROR;
}
case LDAP_SUCCESS:
break;
case LDAP_INVALID_CREDENTIALS:
break;
break;
default:
break;
}
return EOK;
}
/* ==Client connect============================================ */
struct sdap_cli_connect_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_service *service;
bool use_rootdse;
struct sysdb_attrs *rootdse;
struct sdap_handle *sh;
};
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_service *service,
struct sysdb_attrs **rootdse)
{
struct sdap_cli_connect_state *state;
struct tevent_req *req;
int ret;
if (rootdse) {
state->use_rootdse = true;
} else {
state->use_rootdse = false;
}
if (ret) {
}
return req;
}
{
struct sdap_cli_connect_state);
struct tevent_req *subreq;
/* Before stepping to next server destroy any connection from previous attempt */
/* NOTE: this call may cause service->uri to be refreshed
* with a new valid server. Do not use service->uri before */
if (!subreq) {
return ENOMEM;
}
return EOK;
}
{
struct tevent_req);
struct sdap_cli_connect_state);
int ret;
if (ret) {
/* all servers have been tried and none
* was found good, go offline */
return;
}
SDAP_ID_TLS));
if (!subreq) {
return;
}
}
{
struct tevent_req);
struct sdap_cli_connect_state);
const char *sasl_mech;
int ret;
if (ret) {
}
return;
}
return;
}
/* fetch the rootDSE this time */
return;
}
/* check if server claims to support GSSAPI */
sasl_mech)) {
return;
}
}
return;
}
}
}
{
struct sdap_cli_connect_state);
struct tevent_req *subreq;
int ret;
if (!subreq) {
return;
}
/* this rootdse search is performed before we actually do a bind,
* so we need to set up the callbacks or we will never get notified
* of a reply */
if (ret) {
}
}
}
{
struct tevent_req);
struct sdap_cli_connect_state);
const char *sasl_mech;
int ret;
if (ret) {
}
return;
}
/* RootDSE was not available on
* the server.
* Continue, and just assume that the
* features requested by the config
* work properly.
*/
state->use_rootdse = false;
}
else {
return;
}
}
/* check if server claims to support GSSAPI */
sasl_mech)) {
return;
}
}
return;
}
}
}
{
struct sdap_cli_connect_state);
struct tevent_req *subreq;
if (!subreq) {
return;
}
}
{
struct tevent_req);
struct sdap_cli_connect_state);
enum sdap_result result;
int ret;
if (ret) {
}
return;
}
return;
}
if (result != SDAP_AUTH_SUCCESS) {
return;
}
}
{
struct sdap_cli_connect_state);
struct tevent_req *subreq;
if (!subreq) {
return;
}
}
{
struct tevent_req);
enum sdap_result result;
int ret;
if (ret) {
return;
}
if (result != SDAP_AUTH_SUCCESS) {
return;
}
}
struct sdap_handle **gsh,
struct sysdb_attrs **rootdse)
{
}
bool *can_retry,
struct sdap_handle **gsh,
struct sysdb_attrs **rootdse)
{
struct sdap_cli_connect_state);
enum tevent_req_state tstate;
if (can_retry) {
*can_retry = true;
}
/* mark the server as bad if connection failed */
} else {
if (can_retry) {
*can_retry = false;
}
}
if (tstate == TEVENT_REQ_USER_ERROR) {
return err;
}
return EIO;
}
if (gsh) {
if (*gsh) {
talloc_zfree(*gsh);
}
if (!*gsh) {
return ENOMEM;
}
} else {
}
if (rootdse) {
if (state->use_rootdse) {
if (!*rootdse) {
return ENOMEM;
}
} else {
}
} else {
}
return EOK;
}