b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * This file and its contents are supplied under the terms of the
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * You may only use this file in accordance with the terms of version
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * 1.0 of the CDDL.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * A full copy of the text of the CDDL should have accompanied this
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * source. A copy of the CDDL is also available via the Internet at
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * http://www.illumos.org/license/CDDL.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <stdio.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <string.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <strings.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <unistd.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <assert.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <stdlib.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <net/if.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <net/if.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <sys/types.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <sys/socket.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <sys/sockio.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <netinet/in.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <arpa/inet.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <arpa/nameser.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <resolv.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <netdb.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <ctype.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <errno.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <ldap.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <lber.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include <syslog.h>
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include "adutils_impl.h"
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#include "addisc_impl.h"
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define LDAP_PORT 389
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_ATTR_NAME "NetLogon"
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_1 0x00000001
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_5 0x00000002
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_5EX 0x00000004
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_5EX_WITH_IP 0x00000008
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_WITH_CLOSEST_SITE 0x00000010
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#define NETLOGON_NT_VERSION_AVOID_NT4EMUL 0x01000000
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosstypedef enum {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross OPCODE = 0,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross SBZ,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross FLAGS,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross DOMAIN_GUID,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross FOREST_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross DNS_DOMAIN_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross DNS_HOST_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross NET_DOMAIN_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross NET_COMP_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross USER_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross DC_SITE_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross CLIENT_SITE_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross SOCKADDR_SIZE,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross SOCKADDR,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross NEXT_CLOSEST_SITE_NAME,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross NTVER,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross LM_NT_TOKEN,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross LM_20_TOKEN
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross} field_5ex_t;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstruct _berelement {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *ber_buf;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *ber_ptr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *ber_end;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross};
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossextern int ldap_put_filter(BerElement *ber, char *);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic void send_to_cds(ad_disc_cds_t *, char *, size_t, int);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic ad_disc_cds_t *find_cds_by_addr(ad_disc_cds_t *, struct sockaddr_in6 *);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic boolean_t addrmatch(struct addrinfo *, struct sockaddr_in6 *);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic void save_ai(ad_disc_cds_t *, struct addrinfo *);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic void
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosscldap_escape_le64(char *buf, uint64_t val, int bytes)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *p = buf;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross while (bytes != 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p += sprintf(p, "\\%.2x", (uint8_t)(val & 0xff));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross val >>= 8;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross bytes--;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *p = '\0';
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Construct CLDAPMessage PDU for NetLogon search request.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * CLDAPMessage ::= SEQUENCE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * messageID MessageID,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * protocolOp searchRequest SearchRequest;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * SearchRequest ::=
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * [APPLICATION 3] SEQUENCE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * baseObject LDAPDN,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * scope ENUMERATED {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * baseObject (0),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * singleLevel (1),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * wholeSubtree (2)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * },
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * derefAliases ENUMERATED {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * neverDerefAliases (0),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * derefInSearching (1),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * derefFindingBaseObj (2),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * derefAlways (3)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * },
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * sizeLimit INTEGER (0 .. MaxInt),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * timeLimit INTEGER (0 .. MaxInt),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * attrsOnly BOOLEAN,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * filter Filter,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * attributes SEQUENCE OF AttributeType
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon RossBerElement *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosscldap_build_request(const char *dname,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross const char *host, uint32_t ntver, uint16_t msgid)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross BerElement *ber;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int len = 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *basedn = "";
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int scope = LDAP_SCOPE_BASE, deref = LDAP_DEREF_NEVER,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sizelimit = 0, timelimit = 0, attrsonly = 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char filter[512];
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char ntver_esc[13];
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char *p, *pend;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Construct search filter in LDAP format.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p = filter;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pend = p + sizeof (filter);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross len = snprintf(p, pend - p, "(&(DnsDomain=%s)", dname);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (len >= (pend - p))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p += len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (host != NULL) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross len = snprintf(p, (pend - p), "(Host=%s)", host);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (len >= (pend - p))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p += len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ntver != 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Format NtVer as little-endian with LDAPv3 escapes.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cldap_escape_le64(ntver_esc, ntver, sizeof (ntver));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross len = snprintf(p, (pend - p), "(NtVer=%s)", ntver_esc);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (len >= (pend - p))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p += len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross len = snprintf(p, pend - p, ")");
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (len >= (pend - p))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross p += len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Encode CLDAPMessage and beginning of SearchRequest sequence.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if ((ber = ber_alloc()) == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ber_printf(ber, "{it{seeiib", msgid,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross LDAP_REQ_SEARCH, basedn, scope, deref,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sizelimit, timelimit, attrsonly) < 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Encode Filter sequence.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ldap_put_filter(ber, filter) < 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Encode attribute and close Filter and SearchRequest sequences.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ber_printf(ber, "{s}}}", NETLOGON_ATTR_NAME) < 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Success
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (ber);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossfail:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ber != NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ber_free(ber, 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (NULL);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Parse incoming search responses and attribute to correct hosts.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * CLDAPMessage ::= SEQUENCE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * messageID MessageID,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * searchResponse SEQUENCE OF
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * SearchResponse;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * SearchResponse ::=
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * CHOICE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * entry [APPLICATION 4] SEQUENCE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * objectName LDAPDN,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * attributes SEQUENCE OF SEQUENCE {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * AttributeType,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * SET OF
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * AttributeValue
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * },
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * resultCode [APPLICATION 5] LDAPResult
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic int
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossdecode_name(uchar_t *base, uchar_t *cp, char *str)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross uchar_t *tmp = NULL, *st = cp;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross uint8_t len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * there should probably be some boundary checks on str && cp
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * maybe pass in strlen && msglen ?
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross while (*cp != 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (*cp == 0xc0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (tmp == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross tmp = cp + 2;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp = base + *(cp + 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross for (len = *cp++; len > 0; len--)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *str++ = *cp++;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *str++ = '.';
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (cp != st)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *(str-1) = '\0';
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross else
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *str = '\0';
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return ((tmp == NULL ? cp + 1 : tmp) - st);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic int
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosscldap_parse(ad_disc_t ctx, ad_disc_cds_t *cds, BerElement *ber)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_ds_t *dc = &cds->cds_ds;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross uchar_t *base = NULL, *cp = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char val[512]; /* how big should val be? */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int l, msgid, rc = 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross uint16_t opcode;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross field_5ex_t f = OPCODE;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Later, compare msgid's/some validation?
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ber_scanf(ber, "{i{x{{x[la", &msgid, &l, &cp) == LBER_ERROR) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross rc = 1;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto out;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross for (base = cp; ((cp - base) < l) && (f <= LM_20_TOKEN); f++) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross val[0] = '\0';
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross switch (f) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case OPCODE:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* opcode = *(uint16_t *)cp; */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* cp +=2; */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross opcode = *cp++;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross opcode |= (*cp++ << 8);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case SBZ:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += 2;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case FLAGS:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* dci->Flags = *(uint32_t *)cp; */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* cp +=4; */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross dc->flags = *cp++;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross dc->flags |= (*cp++ << 8);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross dc->flags |= (*cp++ << 16);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross dc->flags |= (*cp++ << 26);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case DOMAIN_GUID:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ctx != NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross auto_set_DomainGUID(ctx, cp);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += 16;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case FOREST_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ctx != NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross auto_set_ForestName(ctx, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case DNS_DOMAIN_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * We always have this already.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * (Could validate it here.)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case DNS_HOST_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (0 != strcasecmp(val, dc->host)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_ERR, "DC name %s != %s?",
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross val, dc->host);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case NET_DOMAIN_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * This is the "Flat" domain name.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * (i.e. the NetBIOS name)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * ignore for now.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case NET_COMP_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* not needed */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case USER_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* not needed */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case DC_SITE_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) strlcpy(dc->site, val, sizeof (dc->site));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case CLIENT_SITE_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross cp += decode_name(base, cp, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ctx != NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross auto_set_SiteName(ctx, val);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * These are all possible, but we don't really care about them.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Sockaddr_size && sockaddr might be useful at some point
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case SOCKADDR_SIZE:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case SOCKADDR:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case NEXT_CLOSEST_SITE_NAME:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case NTVER:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case LM_NT_TOKEN:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case LM_20_TOKEN:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross default:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross rc = 3;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto out;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossout:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (base)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross free(base);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross else if (cp)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross free(cp);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (rc);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Filter out unresponsive servers, and save the domain info
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * returned by the "LDAP ping" in the returned object.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * If ctx != NULL, this is a query for a DC, in which case we
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * also save the Domain GUID, Site name, and Forest name as
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * "auto" (discovered) values in the ctx.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Only return the "winner". (We only want one DC/GC)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossad_disc_ds_t *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossldap_ping(ad_disc_t ctx, ad_disc_cds_t *dclist, char *dname, int reqflags)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in6 addr6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross socklen_t addrlen;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct pollfd pingchk;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_cds_t *send_ds;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_cds_t *recv_ds = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_ds_t *ret_ds = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross BerElement *req = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross BerElement *res = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct _berelement *be, *rbe;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross size_t be_len, rbe_len;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int fd = -1;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int tries = 3;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int waitsec;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int r;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross uint16_t msgid;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* One plus a null entry. */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ret_ds = calloc(2, sizeof (ad_disc_ds_t));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ret_ds == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) < 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memset(&addr6, 0, sizeof (addr6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross addr6.sin6_family = AF_INET6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross addr6.sin6_addr = in6addr_any;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (bind(fd, (struct sockaddr *)&addr6, sizeof (addr6)) < 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * semi-unique msgid...
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross msgid = gethrtime() & 0xffff;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Is ntver right? It certainly works on w2k8... If others are needed,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * that might require changes to cldap_parse
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross req = cldap_build_request(dname, NULL,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross NETLOGON_NT_VERSION_5EX, msgid);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (req == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross be = (struct _berelement *)req;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross be_len = be->ber_end - be->ber_buf;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if ((res = ber_alloc()) == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross rbe = (struct _berelement *)res;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross rbe_len = rbe->ber_end - rbe->ber_buf;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pingchk.fd = fd;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pingchk.events = POLLIN;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pingchk.revents = 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosstry_again:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross send_ds = dclist;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross waitsec = 5;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross while (recv_ds == NULL && waitsec > 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * If there is another candidate, send to it.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (send_ds->cds_ds.host[0] != '\0') {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross send_to_cds(send_ds, be->ber_buf, be_len, fd);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross send_ds++;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Wait 1/10 sec. before the next send.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross r = poll(&pingchk, 1, 100);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#if 0 /* DEBUG */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /* Drop all responses 1st pass. */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (waitsec == 5)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross r = 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross#endif
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross } else {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * No more candidates to "ping", so
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * just wait a sec for responses.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross r = poll(&pingchk, 1, 1000);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (r == 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross --waitsec;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (r > 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Got a response.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memset(&addr6, 0, addrlen = sizeof (addr6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross r = recvfrom(fd, rbe->ber_buf, rbe_len, 0,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (struct sockaddr *)&addr6, &addrlen);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross recv_ds = find_cds_by_addr(dclist, &addr6);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (recv_ds == NULL)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross continue;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) cldap_parse(ctx, recv_ds, res);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if ((recv_ds->cds_ds.flags & reqflags) != reqflags) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_ERR, "Skip %s"
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross "due to flags 0x%X",
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross recv_ds->cds_ds.host,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross recv_ds->cds_ds.flags);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross recv_ds = NULL;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (recv_ds == NULL) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (--tries <= 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto fail;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto try_again;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memcpy(ret_ds, recv_ds, sizeof (*ret_ds));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ber_free(res, 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ber_free(req, 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) close(fd);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (ret_ds);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossfail:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ber_free(res, 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ber_free(req, 1);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) close(fd);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross free(ret_ds);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (NULL);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Attempt a send of the LDAP request to all known addresses
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * for this candidate server.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic void
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosssend_to_cds(ad_disc_cds_t *send_cds, char *ber_buf, size_t be_len, int fd)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in6 addr6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct addrinfo *ai;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int err;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 2)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_DEBUG, "send to: %s", send_cds->cds_ds.host);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross for (ai = send_cds->cds_ai; ai != NULL; ai = ai->ai_next) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Build the "to" address.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memset(&addr6, 0, sizeof (addr6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ai->ai_family == AF_INET6) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memcpy(&addr6, ai->ai_addr, sizeof (addr6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross } else if (ai->ai_family == AF_INET) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in *sin =
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void *)ai->ai_addr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross addr6.sin6_family = AF_INET6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross IN6_INADDR_TO_V4MAPPED(&sin->sin_addr,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross &addr6.sin6_addr);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross } else {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross continue;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross addr6.sin6_port = htons(LDAP_PORT);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Send the "ping" to this address.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross err = sendto(fd, ber_buf, be_len, 0,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (struct sockaddr *)&addr6, sizeof (addr6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross err = (err < 0) ? errno : 0;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 2)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char abuf[INET6_ADDRSTRLEN];
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross const char *pa;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pa = inet_ntop(AF_INET6,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross &addr6.sin6_addr,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross abuf, sizeof (abuf));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_ERR, " > %s rc=%d",
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross pa ? pa : "?", err);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross/*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * We have a response from some address. Find the candidate with
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * this address. In case a candidate had multiple addresses, we
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * keep track of which the response came from.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic ad_disc_cds_t *
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossfind_cds_by_addr(ad_disc_cds_t *dclist, struct sockaddr_in6 *sin6from)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross char abuf[INET6_ADDRSTRLEN];
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_cds_t *ds;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct addrinfo *ai;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross int eai;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 1)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross eai = getnameinfo((void *)sin6from, sizeof (*sin6from),
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross abuf, sizeof (abuf), NULL, 0, NI_NUMERICHOST);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (eai != 0)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) strlcpy(abuf, "?", sizeof (abuf));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_DEBUG, "LDAP ping resp: addr=%s", abuf);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Find the DS this response came from.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * (don't accept unexpected responses)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross for (ds = dclist; ds->cds_ds.host[0] != '\0'; ds++) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ai = ds->cds_ai;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross while (ai != NULL) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (addrmatch(ai, sin6from))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross goto found;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ai = ai->ai_next;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 1)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_DEBUG, " (unexpected)");
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (NULL);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossfound:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 2)) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_DEBUG, " from %s", ds->cds_ds.host);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross save_ai(ds, ai);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (ds);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic boolean_t
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossaddrmatch(struct addrinfo *ai, struct sockaddr_in6 *sin6from)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Note: on a GC query, the ds->addr port numbers are
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * the GC port, and our from addr has the LDAP port.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Just compare the IP addresses.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ai->ai_family == AF_INET6) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in6 *sin6p = (void *)ai->ai_addr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (!memcmp(&sin6from->sin6_addr, &sin6p->sin6_addr,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sizeof (struct in6_addr)))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (B_TRUE);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ai->ai_family == AF_INET) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct in6_addr in6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in *sin4p = (void *)ai->ai_addr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross IN6_INADDR_TO_V4MAPPED(&sin4p->sin_addr, &in6);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (!memcmp(&sin6from->sin6_addr, &in6,
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sizeof (struct in6_addr)))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (B_TRUE);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return (B_FALSE);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rossstatic void
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Rosssave_ai(ad_disc_cds_t *cds, struct addrinfo *ai)
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross{
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross ad_disc_ds_t *ds = &cds->cds_ds;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in *sin;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross struct sockaddr_in6 *sin6;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross /*
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * If this DS already saw a response, keep the first
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * address from which we received a response.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross */
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (ds->addr.ss_family != 0) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross if (DBG(DISC, 2))
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_DEBUG, "already have an address");
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross return;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross switch (ai->ai_family) {
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case AF_INET:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sin = (void *)&ds->addr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memcpy(sin, ai->ai_addr, sizeof (*sin));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sin->sin_port = htons(ds->port);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross case AF_INET6:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sin6 = (void *)&ds->addr;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross (void) memcpy(sin6, ai->ai_addr, sizeof (*sin6));
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross sin6->sin6_port = htons(ds->port);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross break;
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross default:
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross logger(LOG_ERR, "bad AF %d", ai->ai_family);
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross }
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross}