-static si_list_t *
-ds_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *ignored, uint32_t *err)
-{
- static int proc = -1;
- si_list_t *list, *out;
- si_item_t *item;
- kvbuf_t *request = NULL;
- kvdict_t *dict;
- kvarray_t *reply = NULL;
- kern_return_t status = 0;
- uint16_t scope = 0;
- int i, k, kcount, d;
- uint32_t port;
-
- struct hostent *h;
- char *h_name = NULL;
- int h_aliases_cnt = 0;
- const char **h_aliases = NULL;
- struct in_addr *a4 = NULL;
- struct in6_addr *a6 = NULL;
- int a4_cnt = 0;
- int a6_cnt = 0;
- struct servent *s;
- const char *s_name = NULL;
- int s_aliases_cnt = 0;
- const char **s_aliases = NULL;
- uint16_t s_port = 0;
- const char *s_proto = NULL;
- const char *protoname;
- int wantv4, wantv6;
-
- int numericserv = ((flags & AI_NUMERICSERV) != 0);
- int numerichost = ((flags & AI_NUMERICHOST) != 0);
-
- wantv4 = 0;
- wantv6 = 0;
-
- if (node != NULL)
- {
- wantv4 = ((family != AF_INET6) || (flags & AI_V4MAPPED));
- wantv6 = (family != AF_INET);
- }
-
- if (err != NULL) *err = SI_STATUS_NO_ERROR;
-
- if (proc < 0)
- {
- status = LI_DSLookupGetProcedureNumber("gethostbyname_service", &proc);
- if (status != KERN_SUCCESS)
- {
- if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
- return NULL;
- }
- }
-
- /* look up canonical name of numeric host */
- if ((numerichost == 1) && (flags & AI_CANONNAME) && (node != NULL))
- {
- item = si_host_byaddr(si, node, family, NULL, NULL);
- if (item != NULL)
- {
- h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
- h_name = strdup(h->h_name);
- si_item_release(item);
- }
- }
-
- if (numericserv == 1)
- {
- s_port = *(int16_t *)serv;
- }
-
- if ((numericserv == 0) || (numerichost == 0))
- {
- request = kvbuf_new();
- if (request != NULL)
- {
- kvbuf_add_dict(request);
-
- if (numerichost == 0)
- {
- kvbuf_add_key(request, "name");
- kvbuf_add_val(request, node);
- kvbuf_add_key(request, "ipv4");
- kvbuf_add_val(request, wantv4 ? "1" : "0");
- kvbuf_add_key(request, "ipv6");
- kvbuf_add_val(request, wantv6 ? "1" : "0");
- }
-
- if (numericserv == 0)
- {
- protoname = NULL;
- if (proto == IPPROTO_UDP) protoname = "udp";
- if (proto == IPPROTO_TCP) protoname = "tcp";
-
- kvbuf_add_key(request, "s_name");
- kvbuf_add_val(request, serv);
- if (protoname != NULL)
- {
- kvbuf_add_key(request, "s_proto");
- kvbuf_add_val(request, protoname);
- }
- }
-
- status = LI_DSLookupQuery(proc, request, &reply);
- kvbuf_free(request);
- }
- else
- {
- if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
- }
- }
-
- if ((status != KERN_SUCCESS) || (reply == NULL))
- {
- free(h_name);
- return NULL;
- }
-
- for (d = 0; d < reply->count; d++)
- {
- dict = reply->dict + d;
- kcount = dict->kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(dict->key[k], "h_name"))
- {
- if (dict->vcount[k] == 0) continue;
- h_name = strdup(dict->val[k][0]);
- }
- else if (string_equal(dict->key[k], "h_aliases"))
- {
- h_aliases_cnt = dict->vcount[k];
- h_aliases = (const char **)calloc(h_aliases_cnt, sizeof(char *));
- if (h_aliases == NULL) h_aliases_cnt = 0;
-
- for (i = 0; i < h_aliases_cnt; ++i)
- {
- h_aliases[i] = dict->val[k][i];
- }
- }
- else if (wantv4 && (string_equal(dict->key[k], "h_ipv4_addr_list")))
- {
- a4_cnt = dict->vcount[k];
- a4 = calloc(a4_cnt, sizeof(struct in_addr));
- if (a4 == NULL) a4_cnt = 0;
-
- for (i = 0; i < a4_cnt; ++i)
- {
- memset(&a4[i], 0, sizeof(struct in_addr));
- inet_pton(AF_INET, dict->val[k][i], &a4[i]);
- }
- }
- else if (wantv6 && (string_equal(dict->key[k], "h_ipv6_addr_list")))
- {
- a6_cnt = dict->vcount[k];
- a6 = calloc(a6_cnt, sizeof(struct in6_addr));
- if (a6 == NULL) a6_cnt = 0;
-
- for (i = 0; i < a6_cnt; ++i)
- {
- memset(&a6[i], 0, sizeof(struct in6_addr));
- inet_pton(AF_INET6, dict->val[k][i], &a6[i]);
- }
- }
- else if (string_equal(dict->key[k], "s_name"))
- {
- if (dict->vcount[k] == 0) continue;
- s_name = dict->val[k][0];
- }
- else if (string_equal(dict->key[k], "s_port"))
- {
- if (dict->vcount[k] == 0) continue;
- s_port = atoi(dict->val[k][0]);
- }
- else if (string_equal(dict->key[k], "s_aliases"))
- {
- s_aliases_cnt = dict->vcount[k];
- s_aliases = (const char **)calloc(s_aliases_cnt+1, sizeof(char *));
- if (s_aliases == NULL) s_aliases_cnt = 0;
-
- for (i = 0; i < s_aliases_cnt; ++i)
- {
- s_aliases[i] = dict->val[k][i];
- }
- }
- else if (string_equal(dict->key[k], "s_proto"))
- {
- if (dict->vcount[k] == 0) continue;
- s_proto = dict->val[k][0];
- }
- }
- }
-
- kvarray_free(reply);
-
- /* check if we actually got back what we wanted */
- if (((wantv4 || wantv6) && (a4_cnt == 0) && (a6_cnt == 0)) || ((serv != NULL) && (s_port == 0)))
- {
- if (err != NULL) *err = SI_STATUS_EAI_NONAME;
-
- free(h_name);
- free(h_aliases);
- free(s_aliases);
- free(a4);
- free(a6);
-
- return NULL;
- }
-
- /*
- * Cache the service entry regardless of whether there is a host match.
- * This allows later modules to get the service entry quickly.
- * This should really be part of the general cache mechanism, but that's
- * not currently visible outside of the search module.
- */
- if ((s_name != NULL) && (s_port != 0))
- {
- port = htons(s_port);
-
- item = pthread_getspecific(_ds_serv_cache_key);
- if (item != NULL)
- {
- s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
- if ((port != s->s_port) || string_not_equal(s_name, s->s_name))
- {
- si_item_release(item);
- item = NULL;
- }
- }
-
- if (item == NULL)
- {
- item = LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, (uint64_t)1, (uint64_t)1, s_name, s_aliases, port, s_proto);
- pthread_setspecific(_ds_serv_cache_key, item);
- }
- }
-
- /* Construct the addrinfo list from the returned addresses (if found). */
- out = NULL;
- for (i = 0; i < a6_cnt; i++)
- {
- list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6[i], s_port, scope, NULL, h_name);
- out = si_list_concat(out, list);
- si_list_release(list);
- }
-
- for (i = 0; i < a4_cnt; i++)
- {
- list = si_addrinfo_list(si, flags, socktype, proto, &a4[i], NULL, s_port, 0, h_name, NULL);
- out = si_list_concat(out, list);
- si_list_release(list);
- }
-
- free(h_name);
- free(h_aliases);
- free(s_aliases);
- free(a4);
- free(a6);
-
- return out;
-}
-
-static int
-ds_is_valid(si_mod_t *si, si_item_t *item)
-{
- si_mod_t *src;
- ds_si_private_t *pp;
- int status;
- uint32_t oldval, newval;
-
- if (si == NULL) return 0;
- if (item == NULL) return 0;
- if (si->name == NULL) return 0;
- if (item->src == NULL) return 0;
-
- pp = (ds_si_private_t *)si->private;
- if (pp == NULL) return 0;
-
- src = (si_mod_t *)item->src;
-
- if (src->name == NULL) return 0;
- if (string_not_equal(si->name, src->name)) return 0;
-
- /* check global invalidation */
- oldval = item->validation_a;
- newval = -1;
- status = notify_peek(pp->notify_token_global, &newval);
- if (status != NOTIFY_STATUS_OK) return 0;
-
- newval = ntohl(newval);
- if (oldval != newval) return 0;
-
- oldval = item->validation_b;
- newval = -1;
- if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval);
- else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval);
- else if (item->type == CATEGORY_HOST_IPV4) status = notify_peek(pp->notify_token_host, &newval);
- else if (item->type == CATEGORY_HOST_IPV6) status = notify_peek(pp->notify_token_host, &newval);
- else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval);
- else return 0;
-
- if (status != NOTIFY_STATUS_OK) return 0;
-
- newval = ntohl(newval);
- if (oldval != newval) return 0;
-
- return 1;
-}