ldap_common.c revision 69905bf968003216d444fc68d8597e139362f2e6
/*
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 "db/sysdb_sudo.h"
#include "db/sysdb_services.h"
#include "db/sysdb_autofs.h"
#include "util/sss_krb5.h"
#include "util/crypto/sss_crypto.h"
#include "providers/ldap/ldap_opts.h"
#include "providers/ldap/sdap_idmap.h"
/* a fd the child process would log into */
int ldap_child_debug_fd = -1;
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_attr_map *default_service_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 */
/* Service 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;
}
&opts->service_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 confdb_ctx *cdb,
const char *conf_path,
struct sdap_options *opts,
bool *use_host_filter,
bool *include_regexp,
bool *include_netgroups)
{
const char *search_base;
int ret;
/* search base */
if (search_base != NULL) {
/* set sudo search bases if they are not */
"to default value\n"));
return ret;
}
}
} else {
"connecting to the LDAP server.\n"));
}
return ret;
}
/* attrs map */
&opts->sudorule_map);
return ret;
}
/* host filter */
return EOK;
}
struct confdb_ctx *cdb,
const char *conf_path,
struct sdap_options *opts)
{
const char *search_base;
struct sdap_attr_map *default_entry_map;
struct sdap_attr_map *default_mobject_map;
int ret;
/* search base */
if (search_base != NULL) {
/* set autofs search bases if they are not */
"to default value\n"));
return ret;
}
}
} else {
return ENOENT;
}
return ret;
}
/* attribute maps */
switch (opts->schema_type) {
case SDAP_SCHEMA_RFC2307:
break;
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_IPA_V1:
case SDAP_SCHEMA_AD:
break;
default:
return EINVAL;
}
("Could not get autofs map object attribute map\n"));
return ret;
}
&opts->autofs_entry_map);
("Could not get autofs entry object attribute map\n"));
return ret;
}
return EOK;
}
struct sdap_search_base ***_search_bases)
{
const char *class_name;
char *unparsed_base;
const char *old_filter = NULL;
*_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;
case SDAP_SUDO_SEARCH_BASE:
class_name = "SUDO";
break;
case SDAP_SERVICE_SEARCH_BASE:
class_name = "SERVICE";
break;
case SDAP_AUTOFS_SEARCH_BASE:
class_name = "AUTOFS";
break;
default:
("Unknown search base type: [%d]\n", class));
class_name = "UNKNOWN";
/* Non-fatal */
break;
}
}
const char *unparsed_base,
const char *class_name,
const char *old_filter,
struct sdap_search_base ***_search_bases)
{
struct sdap_search_base **search_bases;
struct ldb_context *ldb;
struct ldb_parse_tree *tree;
char **split_bases;
char *filter;
int count;
int i, c;
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,
struct sysdb_attrs *recvd_attrs,
char ***missing_attrs)
{
size_t attr_count = 0;
size_t i, j, k;
const char **expected_attrs;
char *sysdb_name;
if (!recvd_attrs || !missing_attrs) {
return EINVAL;
}
if (!tmp_ctx) {
return ENOMEM;
}
&expected_attrs, &attr_count);
goto done;
}
/* 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++;
}
}
if (k == 0) {
*missing_attrs = NULL;
} else {
/* 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 sdap_idmap_ctx *idmap_ctx,
struct sysdb_attrs *sysdb_attrs,
const char *sid_attr,
char **_sid_str)
{
enum idmap_error_code err;
struct ldb_message_element *el;
char *sid_str;
("No [%s] attribute while id-mapping. [%d][%s]\n",
return ret;
}
&sid_str);
if (err != IDMAP_SUCCESS) {
("Could not convert SID: [%s]\n",
return EIO;
}
return EOK;
}