ldap_auth.c revision c9b0071bfcb8eb8c71e40248de46d23aceecc0f3
/*
SSSD
LDAP Backend Module
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2008 Red Hat
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/>.
*/
#ifdef WITH_MOZLDAP
#define LDAP_OPT_SUCCESS LDAP_SUCCESS
#endif
#include "config.h"
#include <time.h>
#include <errno.h>
#include <strings.h>
#include <shadow.h>
#include <security/pam_modules.h>
#include "util/user_info_msg.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/ldap_auth.h"
#include "providers/ldap/sdap_access.h"
#define LDAP_PWEXPIRE_WARNING_TIME 0
{
int ret;
return EINVAL;
}
return ENOMEM;
}
}
return EOK;
}
int pwd_exp_warning)
{
char *end;
int expiration_warning;
int ret = ERR_INTERNAL;
"Kerberos expire date [%s] invalid.\n", expire_date);
return EINVAL;
}
if (*end != '\0') {
"Kerberos expire date [%s] contains extra characters.\n",
return EINVAL;
}
if (expire_time == -1) {
"mktime failed to convert [%s].\n", expire_date);
return EINVAL;
}
tzset();
expire_time -= timezone;
"Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
"daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
} else {
if (pwd_exp_warning >= 0) {
} else {
}
expiration_warning == 0)) {
}
}
}
return ret;
}
{
long today;
long password_age;
long exp;
int ret;
"Last change day is not set, new password needed.\n");
return ERR_PASSWORD_EXPIRED;
}
if (password_age < 0) {
"The last password change time is in the future!.\n");
return EOK;
}
{
return ERR_ACCOUNT_EXPIRED;
}
return ERR_PASSWORD_EXPIRED;
}
/* add_expired_warning() expects time in seconds */
if (exp == 0) {
/* Seconds until next midnight */
}
}
}
return EOK;
}
struct sdap_ppolicy_data *ppolicy,
int pwd_exp_warning)
{
if (pwd_exp_warning < 0) {
pwd_exp_warning = 0;
}
return ENOMEM;
}
ptr++;
/* do not warn */
goto done;
}
/* send warning */
ptr++;
}
}
}
done:
return ret;
}
void *pw_expire_data,
{
switch (pw_expire_type) {
case PWEXPIRE_SHADOW:
break;
case PWEXPIRE_KERBEROS:
break;
break;
case PWEXPIRE_NONE:
break;
default:
}
return ret;
}
static errno_t
const struct ldb_message *msg,
{
const char *mark;
const char *val;
const char *pwd_policy;
int ret;
*type = PWEXPIRE_NONE;
if (pwd_policy == NULL) {
return EINVAL;
}
return EOK;
"Found Kerberos password expiration attributes.\n");
NULL);
return ENOMEM;
}
return EOK;
}
} else {
"No Kerberos password expiration attributes found, "
"but MIT Kerberos password policy was requested. "
"Access will be denied.\n");
return EACCES;
}
"Found shadow password expiration attributes.\n");
return ENOMEM;
}
*type = PWEXPIRE_SHADOW;
return EOK;
} else {
"but shadow password policy was requested. "
"Access will be denied.\n");
return EACCES;
}
}
return EOK;
return ret;
}
/* ==Get-User-DN========================================================== */
struct get_user_dn_state {
const char *username;
char *orig_dn;
};
struct tevent_context *ev,
struct sss_domain_info *domain,
struct sdap_handle *sh,
struct sdap_options *opts,
const char *username)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct get_user_dn_state *state;
char *clean_name;
char *filter;
const char **attrs;
goto done;
}
goto done;
}
/* We're mostly interested in the DN anyway */
goto done;
}
attrs[0] = "objectclass";
false);
if (!subreq) {
goto done;
}
return req;
done:
} else {
}
return req;
}
{
struct tevent_req);
struct get_user_dn_state);
struct ldb_message_element *el;
struct sysdb_attrs **users;
return;
}
if (count == 0) {
return;
} else if (count > 1) {
return;
}
/* exactly one user. Get the originalDN */
return;
}
return;
}
}
char **orig_dn)
{
struct get_user_dn_state);
if (orig_dn) {
}
return EOK;
}
struct sss_domain_info *domain,
struct sdap_options *opts,
const char *username,
char **user_dn,
enum pwexpire *user_pw_expire_type,
void **user_pw_expire_data)
{
enum pwexpire pw_expire_type;
void *pw_expire_data;
struct ldb_result *res;
const char **attrs;
const char *dn;
int ret;
if (!tmpctx) {
return ENOMEM;
}
if (!attrs) {
goto done;
}
attrs[0] = SYSDB_ORIG_DN;
if (ret) {
goto done;
}
case 0:
/* No such user entry? Look it up */
break;
case 1:
/* The user entry has no original DN. This is the case when the ID
* provider is not LDAP-based (proxy perhaps) */
break;
}
if (!dn) {
break;
}
"find_password_expiration_attributes failed.\n");
}
break;
default:
"User search by name (%s) returned > 1 results!\n",
username);
break;
}
done:
if (!*user_dn) {
}
/* pw_expire_data may be NULL */
}
return ret;
}
/* ==Authenticate-User==================================================== */
struct auth_state {
struct tevent_context *ev;
struct sdap_auth_ctx *ctx;
const char *username;
struct sss_auth_token *authtok;
struct sdap_service *sdap_service;
struct sdap_handle *sh;
char *dn;
enum pwexpire pw_expire_type;
void *pw_expire_data;
};
struct tevent_context *ev,
struct sdap_auth_ctx *ctx,
const char *username,
struct sss_auth_token *authtok,
bool try_chpass_service)
{
struct tevent_req *req;
struct auth_state *state;
/* The token must be a password token */
}
} else {
}
return req;
fail:
return NULL;
}
{
struct tevent_req *next_req;
struct auth_state);
/* NOTE: this call may cause service->uri to be refreshed
* with a new valid server. Do not use service->uri before */
if (!next_req) {
return NULL;
}
return next_req;
}
{
struct tevent_req);
struct auth_state);
int ret;
bool use_tls;
if (ret) {
/* all servers have been tried and none
* was found good, go offline */
return;
}
/* Determine whether we need to use TLS */
"[%s] is a secure channel. No need to run START_TLS\n",
use_tls = false;
} else {
/* Check for undocumented debugging feature to disable TLS
* for authentication. This should never be used in production
* for obvious reasons.
*/
if (!use_tls) {
"insecure connection. This should be done "
"for debugging purposes only.");
}
}
if (!subreq) {
return;
}
}
{
struct tevent_req);
struct auth_state);
int ret;
if (ret) {
/* mark this server as bad if connection failed */
}
}
return;
}
/* All required user data was pre-cached during an identity lookup.
* We can proceed with the bind */
return;
/* The cached user entry was missing the bind DN. Need to look
* it up based on user name in order to perform the bind */
return;
}
return;
}
return;
}
{
struct tevent_req);
return;
}
/* The DN was found with an LDAP lookup
* We can proceed with the bind */
return auth_do_bind(req);
}
{
struct tevent_req *subreq;
if (!subreq) {
return;
}
}
{
struct tevent_req);
struct auth_state);
int ret;
"assuming LDAP password policies are active.\n");
}
switch (ret) {
case EOK:
break;
case ETIMEDOUT:
case ERR_NETWORK_IO:
}
return;
default:
return;
}
}
{
}
}
if (pw_expire_data != NULL) {
}
return EOK;
}
/* ==Perform-Password-Change===================== */
struct sdap_pam_chpass_state {
const char *username;
char *dn;
struct sdap_handle *sh;
struct sdap_auth_ctx *ctx;
};
{
struct sdap_pam_chpass_state *state;
struct sdap_auth_ctx *ctx;
struct tevent_req *subreq;
int dp_err = DP_ERR_FATAL;
struct sdap_auth_ctx);
"Backend is marked offline, retry later!\n");
goto done;
}
"Password reset by root is not supported.\n");
goto done;
}
"chpass target was called by wrong pam command.\n");
goto done;
}
return;
done:
}
{
struct sdap_pam_chpass_state *state =
struct tevent_req *subreq;
enum pwexpire pw_expire_type;
void *pw_expire_data;
int dp_err = DP_ERR_FATAL;
int ret;
"Initial authentication for change password operation "
"successful.\n");
goto done;
}
switch (pw_expire_type) {
case PWEXPIRE_SHADOW:
break;
case PWEXPIRE_KERBEROS:
if (ret == ERR_PASSWORD_EXPIRED) {
"LDAP provider cannot change kerberos "
"passwords.\n");
goto done;
}
break;
case PWEXPIRE_NONE:
break;
default:
goto done;
}
}
switch (ret) {
case EOK:
case ERR_PASSWORD_EXPIRED:
if (pw_expire_type == PWEXPIRE_SHADOW) {
/* TODO: implement async ldap modify request */
"Changing shadow password attributes not implemented.\n");
goto done;
} else {
const char *password;
const char *new_password;
if (ret) {
goto done;
}
&new_password, NULL);
if (ret) {
goto done;
}
if (!subreq) {
goto done;
}
return;
}
break;
case ERR_AUTH_DENIED:
case ERR_AUTH_FAILED:
"pack_user_info_chpass_error failed.\n");
} else {
msg);
}
}
break;
case ETIMEDOUT:
case ERR_NETWORK_IO:
break;
default:
}
done:
}
{
struct sdap_pam_chpass_state *state =
int dp_err = DP_ERR_FATAL;
int ret;
char *user_error_message = NULL;
char *lastchanged_name;
struct tevent_req *subreq;
switch (ret) {
case EOK:
break;
case ERR_CHPASS_DENIED:
break;
case ERR_NETWORK_IO:
break;
default:
break;
}
} else {
msg);
}
}
}
goto done;
}
return;
}
done:
}
{
struct sdap_pam_chpass_state *state =
int dp_err = DP_ERR_FATAL;
goto done;
}
done:
}
/* ==Perform-User-Authentication-and-Password-Caching===================== */
struct sdap_pam_auth_state {
};
{
struct sdap_pam_auth_state *state;
struct sdap_auth_ctx *ctx;
struct tevent_req *subreq;
int dp_err = DP_ERR_FATAL;
struct sdap_auth_ctx);
"Backend is marked offline, retry later!\n");
goto done;
}
case SSS_PAM_AUTHENTICATE:
case SSS_PAM_CHAUTHTOK_PRELIM:
return;
case SSS_PAM_CHAUTHTOK:
break;
case SSS_PAM_ACCT_MGMT:
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
break;
default:
}
done:
}
{
struct sdap_pam_auth_state *state =
enum pwexpire pw_expire_type;
void *pw_expire_data;
const char *password;
int ret;
/* Unknown password expiration type. */
goto done;
}
}
switch (ret) {
case EOK:
break;
case ERR_AUTH_DENIED:
break;
case ERR_AUTH_FAILED:
break;
case ETIMEDOUT:
case ERR_NETWORK_IO:
break;
case ERR_ACCOUNT_EXPIRED:
break;
case ERR_PASSWORD_EXPIRED:
break;
default:
}
goto done;
}
password);
}
/* password caching failures are not fatal errors */
} else {
}
}
done:
}