On 05/04/2010 06:44 AM, Sumit Bose wrote:
> Hi,
>
> my comments are in line.
>
> bye,
> Sumit
>

>> @@ -727,6 +728,7 @@ libsss_ldap_la_SOURCES = \
>>       providers/ldap/sdap_child_helpers.c \
>>       providers/ldap/sdap_fd_events.c \
>>       providers/ldap/sdap.c \
>> +    providers/ipa/ipa_dyndns.c \
>
> Why does the LDAP provider need ipa_dyndns.c ?

That's a mistake. That should have been removed.

>
>>       util/user_info_msg.c \
>>       util/sss_ldap.c \
>>       util/sss_krb5.c
>> @@ -788,6 +790,7 @@ libsss_ipa_la_SOURCES = \
>>       providers/ipa/ipa_auth.c \
>>       providers/ipa/ipa_access.c \
>>       providers/ipa/ipa_timerules.c \
>> +    providers/ipa/ipa_dyndns.c \
>>       providers/ldap/ldap_id.c \
>>       providers/ldap/ldap_id_enum.c \
>>       providers/ldap/ldap_id_cleanup.c \
>
>
>> diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..c9f64bed50647e8a25dab109491de63abd9035b9
>> --- /dev/null
>> +++ b/src/providers/ipa/ipa_dyndns.c
>> +
>> +struct ipa_ipv4 {
>> +    struct ipa_ipv4 *next;
>> +    struct ipa_ipv4 *prev;
>> +
>> +    struct sockaddr_in *addr;
>> +    bool matched;
>> +};
>> +
>> +struct ipa_ipv6 {
>> +    struct ipa_ipv6 *next;
>> +    struct ipa_ipv6 *prev;
>> +
>> +    struct sockaddr_in6 *addr;
>> +    bool matched;
>> +};
>
> I would recommend to only have one list with a family (AF_INET,
> AF_INET6, ...) flag and a struct sockaddr_storage to hold the address.
>

Yeah, the separate lists were because originally I was only going to 
base updates on the lookup_family option, but I changed that. I'll 
combine them.

>> +
>> +struct ipa_dyndns_ctx {
>> +    struct ipa_options *ipa_ctx;
>> +    char *hostname;
>> +    struct ipa_ipv4 *ipv4;
>> +    struct ipa_ipv6 *ipv6;
>> +    int child_status;
>> +};
>
>
>
>> +
>> +    if (iface) {
>> +        /* Get the IP addresses associated with the
>> +         * specified interface
>> +         */
>> +        errno = 0;
>> +        ret = getifaddrs(&ifaces);
>> +        if (ret == -1) {
>> +            ret = errno;
>> +            DEBUG(0, ("Could not read interfaces [%d][%s]\n",
>> +                      ret, strerror(ret)));
>> +            goto failed;
>> +        }
>> +
>> +        for(ifa = ifaces; ifa != NULL; ifa=ifa->ifa_next) {
>> +            /* Some interfaces don't have an ifa_addr */
>> +            if (!ifa->ifa_addr) continue;
>> +
>
> Although it is safe here I think using a
> switch(ifa->ifa_addr->sa_family) would make the code more clear, e.g
>
> if (strcasecmp(ifa->ifa_name, iface) == 0)
>      switch(ifa->ifa_addr->sa_family == AF_INET)
> ....
>

I'll clean that up.

>> +            /* Add IPv4 addresses to the list */
>> +            if(ifa->ifa_addr->sa_family == AF_INET&&
>> +               strcasecmp(ifa->ifa_name, iface) == 0) {
>> +                /* Add this address to the IPv4 list */
>> +                address4 = talloc_zero(state, struct ipa_ipv4);
>> +                if (!address4) {
>> +                    goto failed;
>> +                }
>> +
>> +                address4->addr = talloc_memdup(address4, ifa->ifa_addr,
>> +                                               sizeof(struct sockaddr_in));
>> +                if(address4->addr == NULL) {
>> +                    goto failed;
>> +                }
>> +                DLIST_ADD(state->ipv4, address4);
>> +            }
>> +
>> +            /* Add IPv6 addresses to the list */
>> +            if(ifa->ifa_addr->sa_family == AF_INET6&&
>> +               strcasecmp(ifa->ifa_name, iface) == 0) {
>> +                /* Add this address to the IPv6 list */
>> +                address6 = talloc_zero(state, struct ipa_ipv6);
>> +                if (!address6) {
>> +                    goto failed;
>> +                }
>> +
>> +                address6->addr = talloc_memdup(address6, ifa->ifa_addr,
>> +                                               sizeof(struct sockaddr_in6));
>> +                if(!address6->addr) {
>> +                    goto failed;
>> +                }
>> +                DLIST_ADD(state->ipv6, address6);
>> +            }
>> +        }
>> +
>> +        freeifaddrs(ifaces);
>> +    }
>> +
>> +    else {
>> +        /* Get the file descriptor for the primary LDAP connection */
>> +        ret = get_fd_from_ldap(ctx->id_ctx->gsh->ldap,&fd);
>> +        if (ret != EOK) {
>> +            goto failed;
>> +        }
>> +
>> +        ret = getsockname(fd,&sa,&sa_len);
>> +        if (ret == -1) {
>> +            DEBUG(0,("Failed to get socket name\n"));
>> +            goto failed;
>> +        }
>> +
>
> switch(sa.sa_family) ?

Agreed.

>
>> +        if (sa.sa_family == AF_INET) {
>> +            address4 = talloc(state, struct ipa_ipv4);
>> +            if (!address4) {
>> +                goto failed;
>> +            }
>> +            address4->addr = talloc_memdup(address4,&sa,
>> +                                           sizeof(struct sockaddr_in));
>> +            if(address4->addr == NULL) {
>> +                goto failed;
>> +            }
>> +            DLIST_ADD(state->ipv4, address4);
>> +        }
>> +
>> +        if (sa.sa_family == AF_INET6) {
>> +            address6 = talloc(state, struct ipa_ipv6);
>> +            if (!address6) {
>> +                goto failed;
>> +            }
>> +            address6->addr = talloc_memdup(address6,&sa,
>> +                                           sizeof(struct sockaddr_in6));
>> +            if(address6->addr == NULL) {
>> +                goto failed;
>> +            }
>> +            DLIST_ADD(state->ipv6, address6);
>> +        }
>> +    }
>> +
>> +
>
>
>
>> +static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx)
>> +{
>> +    int ret, i;
>> +    char *servername;
>> +    char *zone;
>> +    char ip_addr[128];
>> +    const char *ip;
>> +    struct ipa_ipv4 *a_record;
>> +    struct ipa_ipv6 *aaaa_record;
>> +
>> +    servername = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic,
>> +                                   IPA_SERVER);
>> +    if (!servername) {
>> +        return EIO;
>> +    }
>> +
>> +    zone = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic,
>> +                             IPA_DOMAIN);
>> +    if (!zone) {
>> +        return EIO;
>> +    }
>> +
>> +    /* The DNS zone for IPA is the lower-case
>> +     * version of hte IPA domain
>> +     */
>> +    for(i = 0; zone[i] != '\0'; i++) {
>> +        zone[i] = tolower(zone[i]);
>> +    }
>> +
>> +    /* Add the server and zone headers */
>> +    ctx->update_msg = talloc_asprintf(ctx, "server %s\nzone %s.\n",
>> +                                           servername,
>> +                                           zone);
>> +    if (ctx->update_msg == NULL) {
>> +        ret = ENOMEM;
>> +        goto done;
>> +    }
>
> I think you never check if both lists are empty. Does it make sense to
> send only the delete messages in this case?
>

Yes. If both lists are empty then we should remove the entries from DNS 
so that they aren't pointing at potentially the wrong address (which may 
or may not be a different host)

>> +
>> +    /* Remove any existing entries */
>> +    ctx->update_msg = talloc_asprintf_append(ctx->update_msg,
>> +                                             "update delete %s. in 
>> A\nsend\n"
>> +                                             "update delete %s. in 
>> AAAA\nsend\n",
>> +                                             ctx->dyndns_ctx->hostname,
>> +                                             ctx->dyndns_ctx->hostname);
>> +    if (ctx->update_msg == NULL) {
>> +        ret = ENOMEM;
>> +        goto done;
>> +    }
>> +
>> +    /* Determine if we're updating IPv4, IPv6 or both */
>> +    if (ctx->dyndns_ctx->ipv4) {
>> +        /* At least one A record */
>> +        DLIST_FOR_EACH(a_record, ctx->dyndns_ctx->ipv4) {
>> +            ip = inet_ntop(a_record->addr->sin_family,
>> +&a_record->addr->sin_addr,
>> +                           ip_addr, 128);
>> +            if (ip == NULL) {
>> +                ret = EIO;
>> +                goto done;
>> +            }
>> +
>> +            /* Format the A record update */
>> +            ctx->update_msg = talloc_asprintf_append(
>> +                    ctx->update_msg,
>> +                    "update add %s. 86400 in A %s\n",
>> +                    ctx->dyndns_ctx->hostname, ip_addr);
>> +            if (ctx->update_msg == NULL) {
>> +                ret = ENOMEM;
>> +                goto done;
>> +            }
>> +        }
>> +
>> +        ctx->update_msg = talloc_asprintf_append(ctx->update_msg, "send\n");
>> +        if (ctx->update_msg == NULL) {
>> +            ret = ENOMEM;
>> +            goto done;
>> +        }
>> +    }
>> +
>> +    if (ctx->dyndns_ctx->ipv6) {
>> +        /* At least one AAAA record */
>> +        DLIST_FOR_EACH(aaaa_record, ctx->dyndns_ctx->ipv6) {
>> +            ip = inet_ntop(aaaa_record->addr->sin6_family,
>> +&aaaa_record->addr->sin6_addr,
>> +                           ip_addr, 128);
>> +            if (ip == NULL) {
>> +                ret = EIO;
>> +                goto done;
>> +            }
>> +
>> +            /* Format the AAAA message */
>> +            ctx->update_msg = talloc_asprintf_append(
>> +                    ctx->update_msg,
>> +                    "update add %s. 86400 in AAAA %s\n",
>> +                    ctx->dyndns_ctx->hostname, ip_addr);
>> +            if(ctx->update_msg == NULL) {
>> +                ret = ENOMEM;
>> +                goto done;
>> +            }
>> +        }
>> +        ctx->update_msg = talloc_asprintf_append(ctx->update_msg, "send\n");
>> +        if(ctx->update_msg == NULL) {
>> +            ret = ENOMEM;
>> +            goto done;
>> +        }
>> +    }
>> +
>> +    ret = EOK;
>> +
>> +done:
>> +    return ret;
>> +}
>> +
>> +
>> +
>> +    ret = pipe(pipefd_to_child);
>> +    if (ret == -1) {
>> +        err = errno;
>> +        DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno)));
>
> use err instead of errno as you have done below

Whoops.

>
>> +        return NULL;
>> +    }
>> +
>> +    pid = fork();
>> +
>> +    if (pid == 0) { /* child */
>> +        args[0] = talloc_strdup(ctx, NSUPDATE_PATH);
>> +        args[1] = talloc_strdup(ctx, "-g");
>> +        args[2] = NULL;
>> +        if (args[0] == NULL || args[1] == NULL) {
>> +            return NULL;
>> +        }
>> +
>> +        close(pipefd_to_child[1]);
>> +        ret = dup2(pipefd_to_child[0], STDIN_FILENO);
>> +        if (ret == -1) {
>> +            err = errno;
>> +            DEBUG(1, ("dup2 failed [%d][%s].\n", err, strerror(err)));
>> +            return NULL;
>> +        }
>> +
>> +        errno = 0;
>> +        ret = execv(NSUPDATE_PATH, args);
>> +        if(ret == -1) {
>> +            err = errno;
>> +            DEBUG(1, ("execv failed [%d][%s].\n", err, strerror(err)));
>> +        }
>> +        return NULL;
>> +    }
>> +
>> +    else if (pid>  0) { /* parent */
>> +        close(pipefd_to_child[0]);
>> +
>> +        ctx->pipefd_to_child = pipefd_to_child[1];
>> +
>> +        /* Write the update message to the nsupdate child */
>> +        subreq = write_pipe_send(req,
>> +                                 ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,
>> +                                 (uint8_t *)ctx->update_msg,
>> +                                 strlen(ctx->update_msg)+1,
>> +                                 ctx->pipefd_to_child);
>> +        if (subreq == NULL) {
>> +            return NULL;
>> +        }
>> +        tevent_req_set_callback(subreq, ipa_dyndns_stdin_done, req);
>> +
>> +        /* Set up SIGCHLD handler */
>> +        ret = child_handler_setup(req,
>> +                                  ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,
>> +                                  pid, ipa_dyndns_child_handler, 
>> req,&ctx->sige);
>> +        if (ret != EOK) {
>> +            return NULL;
>> +        }
>> +        talloc_steal(ctx, ctx->sige);
>> +
>> +        /* Set up timeout handler */
>> +        tv = tevent_timeval_current_ofs(15,0);
>
> it would be nice to have a #define IPA_DNYDNS_TIMEOUT 15

Yeah, I meant to do that, then promptly forgot :)

>
>> +        ctx->timeout_handler = tevent_add_timer(
>> +                ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,
>> +                req, tv, ipa_dyndns_timeout, req);
>> +        if(ctx->timeout_handler == NULL) {
>> +            return NULL;
>> +        }
>> +    }
>> +
>> +    else { /* error */
>> +        err = errno;
>> +        DEBUG(1, ("fork failed [%d][%s].\n", errno, strerror(errno)));
>
> use err, see above

Thanks.

>
>> +        return NULL;
>> +    }
>> +
>> +    return req;
>> +}
>> +
>

Thanks for the review. Updated patch coming soon.

-- 
Stephen Gallagher
RHCE 804006346421761

Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/
_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to