/*
SSSD
sdap_dyndns.c: LDAP specific dynamic DNS update
Authors:
Jakub Hrozek <jhrozek@redhat.com>
Copyright (C) 2013 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 "resolv/async_resolv.h"
#include "providers/be_dyndns.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/sdap_dyndns.h"
#include "providers/ldap/sdap_id_op.h"
#include "providers/ldap/ldap_common.h"
static struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
const char *iface);
static errno_t
struct sss_iface_addr **_addresses);
struct sdap_dyndns_update_state {
const char *hostname;
const char *realm;
const char *servername;
int ttl;
bool update_ptr;
bool check_diff;
bool fallback_mode;
char *update_msg;
bool del_phase;
};
bool *_do_update);
static errno_t
struct tevent_req *req);
static struct sss_iface_addr*
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
enum be_nsupdate_auth auth_type,
const char *ifname,
const char *hostname,
const char *realm,
const int ttl,
bool check_diff)
{
const char *conf_servername;
return NULL;
}
state->fallback_mode = false;
/* fallback servername is overriden by user option */
if (conf_servername != NULL) {
}
if (ifname) {
/* Unless one family is restricted, just replace all
* address families during the update
*/
case IPV4_ONLY:
break;
case IPV6_ONLY:
break;
case IPV4_FIRST:
case IPV6_FIRST:
break;
}
} else {
/* If the interface isn't specified, we ONLY want to have the address
* that's connected to the LDAP server stored, so we need to check
* (and later remove) both address families.
*/
}
if (!subreq) {
goto done;
}
done:
}
return req;
}
static void
{
return;
}
/* Check if we need the update at all. In case we are updating the PTR
* records as well, we need to know the old addresses to be able to
* reliably delete the PTR records */
return;
}
return;
}
/* Perform update */
return;
}
/* Execution will resume in sdap_dyndns_update_done */
}
static void
{
bool do_update;
"Could not receive list of current addresses [%d]: %s\n",
return;
}
if (state->check_diff) {
return;
}
if (do_update == false) {
"No DNS update needed, addresses did not change\n");
return;
}
"Detected IP addresses change, will perform an update\n");
}
/* Either we needed the addresses for updating PTR records only or
* the addresses have changed (or both) */
}
return;
}
static errno_t
{
int i;
bool do_update = false;
"Converting DNS IP addresses to strings failed: [%d]: %s\n",
return ret;
}
"Converting local IP addresses to strings failed: [%d]: %s\n",
return ret;
}
/* Compare the lists */
return ret;
}
if (dns_only) {
for (i=0; dns_only[i]; i++) {
"Address in DNS only: %s\n", dns_only[i]);
do_update = true;
}
}
if (local_only) {
for (i=0; local_only[i]; i++) {
"Address on localhost only: %s\n", local_only[i]);
do_update = true;
}
}
*_do_update = do_update;
return EOK;
}
static errno_t
{
const char *servername;
const char *realm;
servername = NULL;
if (state->fallback_mode) {
}
&state->update_msg);
return ret;
}
/* Fork a child process to perform the DNS update */
return EIO;
}
return EOK;
}
static void
{
int child_status;
/* If the update didn't succeed, we can retry using the server name */
if (state->fallback_mode == false
&& WEXITSTATUS(child_status) != 0) {
state->fallback_mode = true;
"nsupdate failed, retrying.\n");
return;
}
}
}
if (state->update_ptr == false) {
return;
}
/* init iterator for addresses to be deleted */
/* init iterator for addresses to be added */
}
return;
}
/* Execution will resume in sdap_dyndns_update_ptr_done */
}
{
bool ret = false;
switch(address_family) {
case AF_INET:
if (remove_af & DYNDNS_REMOVE_A) {
ret = true;
}
break;
case AF_INET6:
if (remove_af & DYNDNS_REMOVE_AAAA) {
ret = true;
}
break;
default:
ret = false;
}
return ret;
}
static struct sss_iface_addr*
{
while (address_it != NULL) {
/* skip addresses that are not to be deleted */
break;
}
}
return address_it;
}
static errno_t
{
const char *servername;
const char *realm;
servername = NULL;
if (state->fallback_mode == true) {
}
return EIO;
}
&state->update_msg);
return ret;
}
/* Fork a child process to perform the DNS update */
return EIO;
}
return EOK;
}
static void
{
int child_status;
/* If the update didn't succeed, we can retry using the server name */
if (state->fallback_mode == false
&& WEXITSTATUS(child_status) != 0) {
state->fallback_mode = true;
return;
}
}
return;
}
return;
}
return;
}
}
static errno_t
struct tevent_req *req)
{
/* iterate to next address to delete */
/* init iterator for addresses to be added */
}
} else {
/* iterate to next address to add */
}
state->fallback_mode = false;
return EAGAIN;
}
}
return EOK;
}
{
return EOK;
}
/* A request to get addresses to update with */
struct sdap_dyndns_get_addrs_state {
};
struct sdap_handle *sh);
const char *iface,
struct sss_iface_addr **_result)
{
char **list_of_intfs;
int num_of_intfs;
int i;
goto done;
}
&num_of_intfs);
"Parsing names of interfaces failed - %d:[%s].\n",
goto done;
}
for (i = 0; i < num_of_intfs; i++) {
if (result_addrs != NULL) {
/* If there is already an existing list, head of this existing
* list will be considered as parent talloc context for the
* new list.
*/
}
/* non-critical failure */
"Cannot get interface %s or there are no addresses "
"bind to it.\n", list_of_intfs[i]);
} else {
"Cannot get list of addresses from interface %s - %d:[%s]\n",
goto done;
}
}
done:
return ret;
}
static struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
const char *iface)
{
struct sdap_dyndns_get_addrs_state);
return NULL;
}
if (iface) {
"get_ifaces_addrs() failed: %d:[%s]\n",
}
/* We're done. Just fake an async request completion */
goto done;
}
/* Detect DYNDNS address from LDAP connection */
goto done;
}
if (!subreq) {
goto done;
}
done:
}
/* EAGAIN - resolution in progress */
return req;
}
static void
{
int dp_error;
if (dp_error == DP_ERR_OFFLINE) {
"dynamic DNS update is skipped in offline mode.\n");
} else {
"Failed to connect to LDAP server: [%d](%s)\n",
}
return;
}
return;
}
/* Got the address! Done! */
}
static errno_t
struct sdap_handle *sh)
{
int ret;
int fd;
return EINVAL;
}
/* Get the file descriptor for the primary LDAP connection */
return ret;
}
errno = 0;
if (ret == -1) {
return ret;
}
"Connection to LDAP is neither IPv4 nor IPv6\n");
return EIO;
}
"sss_get_dualstack_addresses failed: %d:[%s]\n",
return ret;
}
return EOK;
}
static errno_t
struct sss_iface_addr **_addresses)
{
return EOK;
}
struct sdap_dyndns_timer_state {
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
struct be_nsupdate_ctx *dyndns_ctx)
{
return NULL;
}
/* In order to prevent the connection triggering an
* online callback which would in turn trigger a concurrent DNS
* update
*/
/* Make sure to have a valid LDAP connection */
goto fail;
}
goto fail;
}
return req;
fail:
dyndns_ctx->timer_in_progress = false;
return req;
}
static void
{
struct tevent_req);
struct sdap_dyndns_timer_state);
int dp_error;
if (dp_error == DP_ERR_OFFLINE) {
"dynamic DNS update is skipped in offline mode.\n");
/* Another timer will be scheduled when provider goes online */
} else {
"Failed to connect to LDAP server: [%d](%s)\n",
/* Just schedule another dyndns retry */
}
return;
}
/* All OK, schedule another refresh and let the user call its
* provider-specific update
*/
}
{
return EOK;
}