ldap_common.c revision 8c60644bd8f2d739ff7a58b3717929254d09dfbe
/*
SSSD
LDAP Provider Common Functions
Authors:
Simo Sorce <ssorce@redhat.com>
Copyright (C) 2008-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 "providers/ldap/ldap_common.h"
#include "providers/fail_over.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/krb5/krb5_common.h"
#include "util/sss_krb5.h"
#include "util/crypto/sss_crypto.h"
/* a fd the child process would log into */
int ldap_child_debug_fd = -1;
struct dp_option default_basic_opts[] = {
/* use the same parm name as the krb5 module so we set it only once */
/* Do not include ldap_auth_disable_tls_never_use_in_production in the
* manpages or SSSDConfig API
*/
};
struct sdap_attr_map generic_attr_map[] = {
};
struct sdap_attr_map gen_ipa_attr_map[] = {
};
struct sdap_attr_map gen_ad_attr_map[] = {
};
struct sdap_attr_map rfc2307_user_map[] = {
{ "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
{ "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL }
};
struct sdap_attr_map rfc2307_group_map[] = {
};
struct sdap_attr_map rfc2307bis_user_map[] = {
/* FIXME: this is 389ds specific */
{ "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
{ "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL }
};
struct sdap_attr_map rfc2307bis_group_map[] = {
/* FIXME: this is 389ds specific */
};
struct sdap_attr_map netgroup_map[] = {
/* FIXME: this is 389ds specific */
};
struct confdb_ctx *cdb,
const char *conf_path,
struct sdap_options **_opts)
{
struct sdap_attr_map *default_attr_map;
struct sdap_attr_map *default_user_map;
struct sdap_attr_map *default_group_map;
struct sdap_attr_map *default_netgroup_map;
struct sdap_options *opts;
char *schema;
const char *search_base;
const char *pwd_policy;
int ret;
const char *ldap_deref;
int ldap_deref_val;
int o;
const char *authtok_type;
struct dp_opt_blob authtok_blob;
char *cleartext;
const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
-1 };
goto done;
}
/* Handle search bases */
if (search_base != NULL) {
for (o = 0; search_base_options[o] != -1; o++) {
goto done;
}
search_base_options[o])));
}
}
} else {
"connecting to the LDAP server.\n"));
}
/* Default search */
&opts->search_bases);
/* User search */
/* Group search base */
/* Netgroup search */
if (pwd_policy == NULL) {
goto done;
}
goto done;
}
/* account_cache_expiration must be >= than offline_credentials_expiration */
goto done;
}
/* account cache_expiration must not be smaller than
* offline_credentials_expiration to prevent deleting entries that
* still contain credentials valid for offline login.
*
* offline_credentials_expiration == 0 is a special case that says
* that the cached credentials are valid forever. Therefore, the cached
* entries must not be purged from cache.
*/
"and %s (%d)\n",
goto done;
}
"than value of %s (now %d)\n",
goto done;
}
if (ldap_deref != NULL) {
goto done;
}
}
#ifndef HAVE_LDAP_CONNCB
bool ldap_referrals;
if (ldap_referrals) {
"is too old, see sssd-ldap(5) for details.\n"));
}
#endif
/* schema type */
} else
} else
} else
} else {
goto done;
}
goto done;
}
goto done;
}
goto done;
}
&opts->netgroup_map);
goto done;
}
/* If there is no KDC, try the deprecated krb5_kdcip option, too */
/* FIXME - this can be removed in a future version */
goto done;
}
if (authtok_type != NULL &&
"trying to convert to cleartext.\n"));
return EINVAL;
}
&cleartext);
"password back to cleartext\n"));
return ret;
}
return ret;
}
"password");
return ret;
}
}
done:
}
return ret;
}
struct sdap_search_base ***_search_bases)
{
struct sdap_search_base **search_bases;
struct ldb_context *ldb;
struct ldb_parse_tree *tree;
const char *class_name;
char *unparsed_base;
char **split_bases;
char *filter;
const char *old_filter = NULL;
int count;
int i, c;
*_search_bases = NULL;
switch (class) {
case SDAP_SEARCH_BASE:
class_name = "DEFAULT";
break;
case SDAP_USER_SEARCH_BASE:
class_name = "USER";
break;
case SDAP_GROUP_SEARCH_BASE:
class_name = "GROUP";
break;
class_name = "NETGROUP";
break;
default:
("Unknown search base type: [%d]\n", class));
class_name = "UNKNOWN";
/* Non-fatal */
}
if (!tmp_ctx) {
goto done;
}
/* Create a throwaway LDB context for validating the DN */
if (!ldb) {
goto done;
}
&split_bases, &count);
/* The split must be either exactly one value or a multiple of
* three in order to be valid.
* One value: just a base, backwards-compatible with pre-1.7.0 versions
* Multiple: search_base?scope?filter[?search_base?scope?filter]*
*/
goto done;
}
if (count == 1) {
if (!search_bases) {
goto done;
}
if (!search_bases[0]) {
goto done;
}
if (!search_bases[0]->basedn) {
goto done;
}
/* Validate the basedn */
if (!ldn) {
goto done;
}
if (!ldb_dn_validate(ldn)) {
("Invalid base DN [%s]\n",
goto done;
}
/* Use a search filter specified in the old style if available */
("Search base added: [%s][%s][%s][%s]\n",
search_bases[0]->basedn,
"SUBTREE",
} else {
if (!search_bases) {
goto done;
}
i = 0;
for (c = 0; c < count; c += 3) {
struct sdap_search_base);
if (!search_bases[i]) {
goto done;
}
if (split_bases[c][0] == '\0') {
("Zero-length search base: [%s]\n", unparsed_base));
goto done;
}
/* Validate the basedn */
if (!ldn) {
goto done;
}
if (!ldb_dn_validate(ldn)) {
("Invalid base DN [%s]\n",
split_bases[c]));
goto done;
}
/* Set the search base DN */
split_bases[c]);
if (!search_bases[i]->basedn) {
goto done;
}
/* Set the search scope for this base DN */
/* If unspecified, default to subtree */
} else {
goto done;
}
/* Get a specialized filter if provided */
} else {
/* Filters need to be enclosed in parentheses
* to be validated properly by ldb_parse_tree()
*/
split_bases[c+2]);
} else {
}
if (!filter) {
goto done;
}
if(!tree) {
("Invalid search filter: [%s]\n", filter));
goto done;
}
filter);
}
("Search base added: [%s][%s][%s][%s]\n",
search_bases[i]->basedn,
i++;
}
search_bases[i] = NULL;
}
done:
return ret;
}
{
}
{
}
{
int delay;
bool has_enumerated;
/* set up enumeration task */
/* If this is the first startup, we need to kick off
* an enumeration immediately, to close a window where
* clients requesting get*ent information won't get an
* immediate reply with no entries
*/
return ret;
}
if (has_enumerated) {
/* At least one enumeration has previously run,
* so clients will get cached data. We will delay
* starting to enumerate by 10s so we don't slow
* down the startup process if this is happening
* during system boot.
*/
} else {
/* This is our first startup. Schedule the
* enumeration to start immediately once we
* enter the mainloop.
*/
tv = tevent_timeval_current();
}
} else {
/* the enumeration task, runs the cleanup process by itself,
* but if enumeration is not running we need to schedule it */
if (delay == 0) {
/* Cleanup has been explicitly disabled, so we won't
* schedule any cleanup tasks.
*/
return EOK;
}
/* run the first one in a couple of seconds so that we have time to
* finish initializations first*/
}
return ret;
}
{
struct sdap_service *service;
struct resolv_hostent *srvaddr;
struct sockaddr_storage *sockaddr;
const char *tmp;
const char *srv_name;
char *new_uri;
return;
}
if (!service) {
return;
}
if (!srvaddr) {
return;
}
return;
}
if (fo_is_srv_lookup(server)) {
if (!tmp) {
}
return;
}
} else {
}
if (!new_uri) {
return;
}
/* free old one and replace with new one */
}
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
char *realm = (char *) private_data;
int ret;
}
}
struct tevent_context *ev,
const char *realm)
{
char *sig_realm;
struct tevent_signal *sige;
BlockSignals(false, SIGTERM);
return ENOMEM;
}
return ENOMEM;
}
return EOK;
}
void sdap_remove_kdcinfo_files_callback(void *pvt)
{
int ret;
struct remove_info_files_ctx);
"krb5 info files will not be removed, because "
"it is unclear if they will be recreated properly.\n"));
return;
}
return;
}
}
}
const char *realm,
const char *service_name)
{
int ret;
struct remove_info_files_ctx *ctx;
return ENOMEM;
}
goto done;
}
goto done;
}
done:
}
return ret;
}
static const char *
{
char *krb5_realm = NULL;
if (krberr) {
goto done;
}
if (krberr) {
goto done;
}
if (!realm) {
DEBUG(0, ("Out of memory\n"));
goto done;
}
done:
return realm;
}
struct sdap_service *sdap_service,
struct krb5_service **krb5_service)
{
int ret;
const char *krb5_servers;
const char *krb5_realm;
const char *krb5_opt_realm;
if (krb5_servers == NULL) {
}
if (krb5_opt_realm == NULL) {
if (krb5_realm == NULL) {
DEBUG(0, ("Cannot determine the Kerberos realm, aborting\n"));
goto done;
}
} else {
if (krb5_realm == NULL) {
goto done;
}
}
krb5_realm, &service);
DEBUG(0, ("Failed to init KRB5 failover service!\n"));
goto done;
}
DEBUG(0, ("Failed to install sigterm handler\n"));
goto done;
}
DEBUG(0, ("Failed to install sigterm handler\n"));
goto done;
}
goto done;
}
*krb5_service = service;
done:
return ret;
}
const char *service_name, const char *dns_service_name,
{
struct sdap_service *service;
char *srv_user_data;
int ret;
int i;
if (!tmp_ctx) {
return ENOMEM;
}
if (!service) {
goto done;
}
goto done;
}
goto done;
}
if (!urls) {
}
/* split server parm into a list */
goto done;
}
/* now for each URI add a new server to the failover service */
for (i = 0; list[i]; i++) {
if (be_fo_is_srv_identifier(list[i])) {
if (!dns_service_name) {
DEBUG(0, ("Missing DNS service name for service [%s].\n",
service_name));
goto done;
}
if (!srv_user_data) {
goto done;
}
BE_FO_PROTO_TCP, false, srv_user_data);
if (ret) {
DEBUG(0, ("Failed to add server\n"));
goto done;
}
continue;
}
if (ret != LDAP_SUCCESS) {
goto done;
}
list[i]));
continue;
}
if (ret) {
goto done;
}
}
goto done;
}
done:
}
return ret;
}
errno_t string_to_shadowpw_days(const char *s, long *d)
{
long l;
char *endptr;
if (s == NULL || *s == '\0') {
*d = -1;
return EOK;
}
errno = 0;
if (errno != 0) {
return errno;
}
if (*endptr != '\0') {
return EINVAL;
}
if (l < 0) {
l));
return EINVAL;
}
*d = l;
return EOK;
}
struct sdap_attr_map *map,
const char *ldap_name,
char **sysdb_name)
{
size_t i;
for (i = 0; i < map_size; i++) {
/* Skip map entries with no name (may depend on
* schema selected)
*/
/* Check if it is a mapped attribute */
}
if (i < map_size) {
/* We found a mapped name, return that */
} else {
/* Not mapped, use the same name */
}
if (!*sysdb_name) {
return ENOMEM;
}
return EOK;
}
struct sdap_attr_map *map,
const char **expected_attrs,
struct sysdb_attrs *recvd_attrs,
char ***missing_attrs)
{
size_t attr_count = 0;
size_t i, j, k;
char *sysdb_name;
return EINVAL;
}
if (!tmp_ctx) {
return ENOMEM;
}
/* Count the expected attrs */
/* Allocate the maximum possible values for missing_attrs, to
* be on the safe side
*/
if (!missing) {
goto done;
}
k = 0;
/* Check for each expected attribute */
for (i = 0; i < attr_count; i++) {
expected_attrs[i],
&sysdb_name);
goto done;
}
/* objectClass is a special-case and we need to
* check for it explicitly.
*/
continue;
}
/* GECOS is another special case. Its value can come
* either from the 'gecos' attribute or the 'cn'
* attribute. It's best if we just never remove it.
*/
continue;
}
for (j = 0; j < recvd_attrs->num; j++) {
/* Check whether this expected attribute appeared in the
* received attributes and had a non-zero number of
* values.
*/
(recvd_attrs->a[j].num_values > 0)) {
break;
}
}
if (j < recvd_attrs->num) {
/* Attribute was found, therefore not missing */
} else {
/* Attribute could not be found. Add to the missing list */
k++;
}
}
/* Terminate the list */
done:
return ret;
}
bool sdap_is_secure_uri(const char *uri)
{
/* LDAPS URI's are secure channels */
return true;
}
return false;
}
const char *base_filter,
const char *extra_filter)
{
if (!extra_filter) {
}
if (extra_filter[0] == '(') {
} else {
}
return filter; /* NULL or not */
}
struct ldb_message **msgs,
struct sysdb_attrs ***attrs)
{
int i;
struct sysdb_attrs **a;
if (a == NULL) {
return ENOMEM;
}
for (i = 0; i < count; i++) {
a[i] = talloc(a, struct sysdb_attrs);
if (a[i] == NULL) {
talloc_free(a);
return ENOMEM;
}
}
*attrs = a;
return EOK;
}