sdap_access.c revision 57cd3443dcb7c073c5a00a9f2c3c3a3030ae2d3e
/*
SSSD
Authors:
Stephen Gallagher <sgallagh@redhat.com>
Copyright (C) 2010 Red Hat
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 <time.h>
#include <security/pam_modules.h>
#include <talloc.h>
#include <tevent.h>
#include <errno.h>
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_access.h"
#include "providers/ldap/sdap_async.h"
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
struct tevent_context *ev,
struct sss_domain_info *domain,
struct sdap_access_ctx *access_ctx,
const char *username,
struct ldb_message *user_entry);
struct ldb_message *user_entry);
struct ldb_message *user_entry);
struct sdap_access_req_ctx {
struct tevent_context *ev;
struct sdap_access_ctx *access_ctx;
struct sss_domain_info *domain;
struct ldb_message *user_entry;
};
struct tevent_req *req);
struct tevent_req *
struct tevent_context *ev,
struct sss_domain_info *domain,
struct sdap_access_ctx *access_ctx,
{
struct sdap_access_req_ctx *state;
struct tevent_req *req;
struct ldb_result *res;
struct sss_domain_info *user_dom;
return NULL;
}
state->current_rule = 0;
goto done;
}
/* Get original user DN, take care of subdomain users as well */
goto done;
}
} else {
}
/* If we can't find the user, return access denied */
goto done;
}
goto done;
}
else {
/* If we can't find the user, return access denied */
goto done;
}
goto done;
}
}
return req;
}
done:
} else {
}
return req;
}
struct tevent_req *req)
{
struct tevent_req *subreq;
case LDAP_ACCESS_EMPTY:
/* we are done with no errors */
return EOK;
case LDAP_ACCESS_FILTER:
state->user_entry);
return ENOMEM;
}
return EAGAIN;
case LDAP_ACCESS_EXPIRE:
break;
case LDAP_ACCESS_SERVICE:
break;
case LDAP_ACCESS_HOST:
break;
default:
}
state->current_rule++;
}
return ret;
}
{
struct sdap_access_req_ctx *state =
return;
}
state->current_rule++;
switch (ret) {
case EAGAIN:
return;
case EOK:
return;
default:
return;
}
}
{
return EOK;
}
#define SHADOW_EXPIRE_MSG "Account expired according to shadow attributes"
struct ldb_message *user_entry)
{
int ret;
const char *val;
long sp_expire;
long today;
"Access will be granted.\n"));
return EOK;
}
return ret;
}
sizeof(SHADOW_EXPIRE_MSG),
(const uint8_t *) SHADOW_EXPIRE_MSG);
}
return ERR_ACCOUNT_EXPIRED;
}
return EOK;
}
#define UAC_ACCOUNTDISABLE 0x00000002
#define AD_NEVER_EXP 0x7fffffffffffffffLL
#define AD_TO_UNIX_TIME_CONST 11644473600LL
#define AD_DISABLE_MESSAGE "The user account is disabled on the AD server"
#define AD_EXPIRED_MESSAGE "The user account is expired on the AD server"
{
int err;
return false;
}
return true;
}
/* NT timestamps start at 1601-01-01 and use a 100ns base */
if (nt_now > expiration_time) {
return true;
}
return false;
}
struct ldb_message *user_entry)
{
int ret;
0);
if (uac & UAC_ACCOUNTDISABLE) {
sizeof(AD_DISABLE_MESSAGE),
(const uint8_t *) AD_DISABLE_MESSAGE);
}
return ERR_ACCESS_DENIED;
} else if (ad_account_expired(expiration_time)) {
sizeof(AD_EXPIRED_MESSAGE),
(const uint8_t *) AD_EXPIRED_MESSAGE);
}
return ERR_ACCOUNT_EXPIRED;
}
return EOK;
}
#define RHDS_LOCK_MSG "The user account is locked on the server"
struct ldb_message *user_entry)
{
bool locked;
int ret;
if (locked) {
sizeof(RHDS_LOCK_MSG),
(const uint8_t *) RHDS_LOCK_MSG);
}
return ERR_ACCESS_DENIED;
}
return EOK;
}
#define NDS_DISABLE_MSG "The user account is disabled on the server"
#define NDS_EXPIRED_MSG "The user account is expired"
#define NDS_TIME_MAP_MSG "The user account is not allowed at this time"
static bool nds_check_expired(const char *exp_time_str)
{
char *end;
if (exp_time_str == NULL) {
return false;
}
return true;
}
if (*end != '\0') {
exp_time_str));
return true;
}
if (expire_time == -1) {
return true;
}
tzset();
expire_time -= timezone;
("Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
"daylight [%d] now [%d] expire_time [%d].\n", tzname[0],
return true;
}
return false;
}
/* There is no real documentation of the byte string value of
* loginAllowedTimeMap, but some good example code in
*/
{
div_t q;
return false;
}
return true;
}
if (map_index > 335) {
("Unexpected index value [%d] for time map.\n", map_index));
return true;
}
("Unexpected result of div(), [%d][%d][%d].\n",
return true;
}
if (q.rem > 0) {
}
return false;
}
return true;
}
struct ldb_message *user_entry)
{
bool locked = true;
int ret;
const char *exp_time_str;
false);
if (locked) {
sizeof(NDS_DISABLE_MSG),
(const uint8_t *) NDS_DISABLE_MSG);
}
return ERR_ACCESS_DENIED;
} else {
NULL);
if (locked) {
sizeof(NDS_EXPIRED_MSG),
(const uint8_t *) NDS_EXPIRED_MSG);
}
return ERR_ACCESS_DENIED;
} else {
if (locked) {
sizeof(NDS_TIME_MAP_MSG),
(const uint8_t *) NDS_TIME_MAP_MSG);
}
return ERR_ACCESS_DENIED;
}
}
}
return EOK;
}
struct ldb_message *user_entry)
{
const char *expire;
int ret;
return ERR_ACCESS_DENIED;
} else {
}
}
}
}
} else {
"Access denied.\n", expire));
}
}
return ret;
}
struct sdap_access_filter_req_ctx {
const char *username;
const char *filter;
struct tevent_context *ev;
struct sdap_access_ctx *access_ctx;
struct sdap_id_ctx *sdap_ctx;
struct sdap_id_op *sdap_op;
struct sysdb_handle *handle;
struct sss_domain_info *domain;
bool cached_access;
char *basedn;
};
struct tevent_context *ev,
struct sss_domain_info *domain,
struct sdap_access_ctx *access_ctx,
const char *username,
struct ldb_message *user_entry)
{
struct sdap_access_filter_req_ctx *state;
struct tevent_req *req;
const char *basedn;
char *clean_username;
return NULL;
}
/* If no filter is set, default to restrictive */
goto done;
}
false);
/* Ok, we have one result, check if we are online or offline */
if (be_is_offline(be_ctx)) {
/* Ok, we're offline. Return from the cache */
goto done;
}
/* Perform online operation */
goto done;
}
goto done;
}
/* Construct the filter */
goto done;
}
"(&(%s=%s)(objectclass=%s)%s)",
DEBUG(0, ("Could not construct access filter\n"));
goto done;
}
goto done;
}
goto done;
}
return req;
done:
} else {
}
return req;
}
{
struct sdap_access_filter_req_ctx *state =
if (state->cached_access) {
return EOK;
} else {
return ERR_ACCESS_DENIED;
}
}
{
struct sdap_access_filter_req_ctx *state =
struct tevent_req *subreq;
int ret;
if (!subreq) {
return ret;
}
return EOK;
}
{
struct tevent_req);
struct sdap_access_filter_req_ctx *state =
if (dp_error == DP_ERR_OFFLINE) {
return;
}
}
return;
}
/* Connection to LDAP succeeded
* Send filter request
*/
NULL, 0,
false);
return;
}
}
{
bool found = false;
struct sysdb_attrs *attrs;
struct sysdb_attrs **results;
struct tevent_req *req =
struct sdap_access_filter_req_ctx *state =
&num_results, &results);
/* retry */
return;
}
} else if (dp_error == DP_ERR_OFFLINE) {
} else {
}
goto done;
}
/* Check the number of responses we got
* If it's exactly 1, we passed the check
* If it's < 1, we failed the check
* Anything else is an error
*/
if (num_results < 1) {
found = false;
}
ret = ERR_INTERNAL;
goto done;
}
else if (num_results > 1) {
/* It should not be possible to get more than one reply
* here, since we're doing a base-scoped search
*/
ret = ERR_INTERNAL;
goto done;
}
else { /* Ok, we got a single reply */
found = true;
}
if (found) {
/* Save "allow" to the cache for future offline
:q* access checks.
*/
}
else {
/* Save "disallow" to the cache for future offline
* access checks.
*/
}
goto done;
}
/* Failing to save to the cache is non-fatal.
* Just return the result.
*/
goto done;
}
/* Failing to save to the cache is non-fatal.
* Just return the result.
*/
goto done;
}
done:
}
else {
}
}
{
return EOK;
}
#define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
"access denied"
#define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
#define AUTHR_SRV_NO_MATCH_MSG "Authorized service attribute has " \
"no matching rule, access denied"
struct ldb_message *user_entry)
{
struct ldb_message_element *el;
unsigned int i;
char *service;
sizeof(AUTHR_SRV_MISSING_MSG),
(const uint8_t *) AUTHR_SRV_MISSING_MSG);
}
return ERR_ACCESS_DENIED;
}
for (i = 0; i < el->num_values; i++) {
if (service[0] == '!' &&
/* This service is explicitly denied */
sizeof(AUTHR_SRV_DENY_MSG),
(const uint8_t *) AUTHR_SRV_DENY_MSG);
}
/* A denial trumps all. Break here */
return ERR_ACCESS_DENIED;
/* This service is explicitly allowed */
/* We still need to loop through to make sure
* that it's not also explicitly denied
*/
/* This user has access to all services */
/* We still need to loop through to make sure
* that it's not also explicitly denied
*/
}
}
sizeof(AUTHR_SRV_NO_MATCH_MSG),
(const uint8_t *) AUTHR_SRV_NO_MATCH_MSG);
}
}
return ret;
}
{
struct ldb_message_element *el;
unsigned int i;
char *host;
return ERR_ACCESS_DENIED;
}
return ERR_ACCESS_DENIED;
}
/* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname
* Not sure this is a good idea, but we might want to add it in
* order to be compatible...
*/
for (i = 0; i < el->num_values; i++) {
if (host[0] == '!' &&
/* This host is explicitly denied */
/* A denial trumps all. Break here */
return ERR_ACCESS_DENIED;
/* This host is explicitly allowed */
/* We still need to loop through to make sure
* that it's not also explicitly denied
*/
/* This user has access to all hosts */
/* We still need to loop through to make sure
* that it's not also explicitly denied
*/
}
}
}
return ret;
}