summaryrefslogtreecommitdiff
path: root/usr/src/cmd/nscd/gethost.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/nscd/gethost.c')
-rw-r--r--usr/src/cmd/nscd/gethost.c694
1 files changed, 56 insertions, 638 deletions
diff --git a/usr/src/cmd/nscd/gethost.c b/usr/src/cmd/nscd/gethost.c
index c38b7f0b2b..b0cee1ad7e 100644
--- a/usr/src/cmd/nscd/gethost.c
+++ b/usr/src/cmd/nscd/gethost.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,654 +29,73 @@
* Routines to handle gethost* calls in nscd
*/
-#include <assert.h>
-#include <errno.h>
-#include <memory.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#include <sys/door.h>
-#include <sys/stat.h>
-#include <sys/time.h>
+#include <stdlib.h>
#include <sys/types.h>
-#include <sys/wait.h>
-#include <thread.h>
-#include <unistd.h>
-#include <ucred.h>
-#include <nss_common.h>
-
-#include "getxby_door.h"
-#include "server_door.h"
-#include "nscd.h"
-
-static hash_t *addr_hash;
-static hash_t *hnam_hash;
-static mutex_t host_lock = DEFAULTMUTEX;
-static waiter_t host_wait;
-
-static void gethost_addrkeepalive(int keep, int interval);
-static void gethost_invalidate_unlocked(void);
-static void gethost_namekeepalive(int keep, int interval);
-static int addr_to_int(char *addr);
-static int int_to_addr(int h);
-static void update_host_bucket(nsc_bucket_t **old, nsc_bucket_t *new,
- int callnumber);
-static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen);
-static void do_findhaddrs(nsc_bucket_t *ptr, int *table, int intaddr);
-static void do_findhnams(nsc_bucket_t *ptr, int *table, char *name);
-static void do_invalidate(nsc_bucket_t **ptr, int callnumber);
-
-static int
-addr_to_int(char *addr)
-{
- union {
- char data[4];
- int hashval;
- } u;
-
-/*
- * following code is byte order dependant, but since all we use this for
- * is hashing this works out just fine.
- */
- u.data[0] = *addr++;
- u.data[1] = *addr++;
- u.data[2] = *addr++;
- u.data[3] = *addr++;
-
- return (u.hashval);
-}
-
-static int
-int_to_addr(int h)
-{
- union {
- char data[4];
- int hashval;
- } u;
-
-/*
- * following code is byte order dependant, but since all we use this for
- * is hashing this works out just fine.
- */
- u.hashval = h;
- return (* ((int *)u.data));
-}
-
-void
-gethost_init(void)
-{
- addr_hash = make_ihash(current_admin.host.nsc_suggestedsize);
- hnam_hash = make_hash(current_admin.host.nsc_suggestedsize);
-}
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "cache.h"
-static void
-do_invalidate(nsc_bucket_t ** ptr, int callnumber)
-{
- if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) {
- /* leave pending calls alone */
- update_host_bucket(ptr, NULL, callnumber);
- }
-}
+#define hnam_db ctx->nsc_db[0]
+#define addr_db ctx->nsc_db[1]
-static void
-do_findhnams(nsc_bucket_t *ptr, int *table, char *name)
-{
- /*
- * be careful with ptr - it may be -1 or NULL.
- */
+#define NSC_NAME_HOSTS_BYNAME "gethostbyname"
+#define NSC_NAME_HOSTS_BYADDR "gethostbyaddr"
- if (ptr != NULL && ptr != (nsc_bucket_t *)-1) {
- /* leave pending calls alone */
- char *tmp = (char *)insertn(table, ptr->nsc_hits,
- (int)strdup(name));
- if (tmp != (char *)-1)
- free(tmp);
- }
-}
-
-static void
-do_findhaddrs(nsc_bucket_t *ptr, int *table, int intaddr)
-{
- if (ptr != NULL && ptr != (nsc_bucket_t *)-1) {
- /* leave pending calls alone */
- insertn(table, ptr->nsc_hits, int_to_addr(intaddr));
- }
-}
+static int hostaddr_compar(const void *, const void *);
+static uint_t hostaddr_gethash(nss_XbyY_key_t *, int);
+static void hostaddr_getlogstr(char *, char *, size_t, nss_XbyY_args_t *);
void
-gethost_revalidate(void)
-{
- for (;;) {
- int slp;
- int interval;
- int count;
-
- slp = current_admin.host.nsc_pos_ttl;
-
- if (slp < 60)
- slp = 60;
- count = current_admin.host.nsc_keephot;
- if (count != 0) {
- interval = (slp/2)/count;
- if (interval == 0) interval = 1;
- sleep(slp*2/3);
- gethost_namekeepalive(count, interval);
- gethost_addrkeepalive(count, interval);
- } else {
- sleep(slp);
- }
- }
-}
-
-static void
-gethost_namekeepalive(int keep, int interval)
-{
- int *table;
- union {
- nsc_data_t ping;
- char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN];
- } u;
-
- int i;
-
- if (!keep)
- return;
-
- table = maken(keep);
- mutex_lock(&host_lock);
- operate_hash(hnam_hash, do_findhnams, (char *)table);
- mutex_unlock(&host_lock);
-
- for (i = 1; i <= keep; i++) {
- char *tmp;
- u.ping.nsc_call.nsc_callnumber = GETHOSTBYNAME;
-
- if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1)
- continue; /* unused slot in table */
- if (current_admin.debug_level >= DBG_ALL)
- logit("keepalive: reviving host %s\n", tmp);
- strcpy(u.ping.nsc_call.nsc_u.name, tmp);
-
- launch_update(&u.ping.nsc_call);
- sleep(interval);
- }
-
- for (i = 1; i <= keep; i++) {
- char *tmp;
- if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1)
- free(tmp);
- }
-
- free(table);
-}
-
-static void
-gethost_addrkeepalive(int keep, int interval)
-{
- int *table;
- union {
- nsc_data_t ping;
- char space[sizeof (nsc_data_t) + 80];
- } u;
-
- int i;
-
- if (!keep)
- return;
-
- table = maken(keep);
- mutex_lock(&host_lock);
- operate_hash(addr_hash, do_findhaddrs, (char *)table);
- mutex_unlock(&host_lock);
-
- for (i = 1; i <= keep; i++) {
- int tmp;
- u.ping.nsc_call.nsc_callnumber = GETHOSTBYADDR;
-
- if ((tmp = table[keep + 1 + i]) == -1)
- continue; /* unused slot in table */
- u.ping.nsc_call.nsc_u.addr.a_type = AF_INET;
- u.ping.nsc_call.nsc_u.addr.a_length = sizeof (int);
- memcpy(u.ping.nsc_call.nsc_u.addr.a_data, &tmp, sizeof (int));
- launch_update(&u.ping.nsc_call);
- sleep(interval);
- }
-
- free(table);
-}
-
-/*
- * This routine marks all entries as invalid
- *
- */
-void
-gethost_invalidate(void)
-{
- mutex_lock(&host_lock);
- gethost_invalidate_unlocked();
- mutex_unlock(&host_lock);
-}
-
-static void
-gethost_invalidate_unlocked(void)
-{
- operate_hash_addr(hnam_hash, do_invalidate, (char *)GETHOSTBYNAME);
- operate_hash_addr(addr_hash, do_invalidate, (char *)GETHOSTBYADDR);
- current_admin.host.nsc_invalidate_count++;
-}
-
-void
-gethost_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now)
-{
- int out_of_date;
- nsc_bucket_t *retb;
- char **bucket;
-
- static time_t lastmod;
-
- int bufferspace = maxsize - sizeof (nsc_return_t);
-
- if (current_admin.host.nsc_enabled == 0) {
- out->nsc_return_code = NOSERVER;
- out->nsc_bufferbytesused = sizeof (*out);
- return;
- }
-
- mutex_lock(&host_lock);
-
- if (current_admin.host.nsc_check_files) {
- struct stat buf;
+host_init_ctx(nsc_ctx_t *ctx) {
+ ctx->dbname = NSS_DBNAM_HOSTS;
+ ctx->db_count = 2;
+ ctx->file_name = "/etc/inet/hosts";
- if (stat("/etc/hosts", &buf) < 0) {
- /*EMPTY*/;
- } else if (lastmod == 0) {
- lastmod = buf.st_mtime;
- } else if (lastmod < buf.st_mtime) {
- gethost_invalidate_unlocked();
- lastmod = buf.st_mtime;
- }
- }
-
-
- if (current_admin.debug_level >= DBG_ALL) {
- if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) {
- logit("gethost_lookup: looking for address %s\n",
- inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data)));
- } else {
- logit("gethost_lookup: looking for hostname %s\n",
- in->nsc_u.name);
- }
- }
-
- for (;;) {
- if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) {
- bucket = get_hash(addr_hash,
- (char *)addr_to_int(in->nsc_u.addr.a_data));
- } else { /* bounce excessively long requests */
- if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) {
- ucred_t *uc = NULL;
-
- if (door_ucred(&uc) != 0) {
- logit("gethost_lookup: Name too long, "
- "but no user credential: %s\n",
- strerror(errno));
- } else {
- logit("gethost_lookup: Name too long "
- "from pid %d uid %d\n",
- ucred_getpid(uc),
- ucred_getruid(uc));
- ucred_free(uc);
- }
-
- out->nsc_errno = NSS_NOTFOUND;
- out->nsc_return_code = NOTFOUND;
- out->nsc_bufferbytesused = sizeof (*out);
- goto getout;
- }
- bucket = get_hash(hnam_hash, in->nsc_u.name);
- }
-
- if (*bucket == (char *)-1) { /* pending lookup */
- if (get_clearance(in->nsc_callnumber) != 0) {
- /* no threads available */
- out->nsc_return_code = NOSERVER;
- /* cannot process now */
- out->nsc_bufferbytesused = sizeof (*out);
- current_admin.host.nsc_throttle_count++;
- goto getout;
- }
- nscd_wait(&host_wait, &host_lock, bucket);
- release_clearance(in->nsc_callnumber);
- continue; /* go back and relookup hash bucket */
- }
- break;
- }
-
- /*
- * check for no name_service mode
- */
-
- if (*bucket == NULL && current_admin.avoid_nameservice) {
- out->nsc_return_code = NOTFOUND;
- out->nsc_bufferbytesused = sizeof (*out);
- } else if ((*bucket == NULL) || /* New entry in name service */
- (in->nsc_callnumber & UPDATEBIT) || /* needs updating */
- (out_of_date = (!current_admin.avoid_nameservice &&
- (current_admin.host.nsc_old_data_ok == 0) &&
- (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) {
- /* time has expired */
- int saved_errno;
- int saved_hits = 0;
- struct hostent *p;
-
- if (get_clearance(in->nsc_callnumber) != 0) {
- /* no threads available */
- out->nsc_return_code = NOSERVER;
- /* cannot process now */
- out->nsc_bufferbytesused = sizeof (*out);
- current_admin.host.nsc_throttle_count++;
- goto getout;
- }
-
- if (*bucket != NULL) {
- saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits;
- }
-
- /*
- * block any threads accessing this bucket if data is
- * non-existent or out of date
- */
-
- if (*bucket == NULL || out_of_date) {
- update_host_bucket((nsc_bucket_t **)bucket,
- (nsc_bucket_t *)-1,
- in->nsc_callnumber);
- } else {
- /*
- * if still not -1 bucket we are doing update... mark
- * to prevent pileups of threads if the name service
- * is hanging....
- */
- ((nsc_bucket_t *)(*bucket))->nsc_status |=
- ST_UPDATE_PENDING;
- /* cleared by deletion of old data */
- }
- mutex_unlock(&host_lock);
-
- if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) {
- p = _uncached_gethostbyaddr_r(in->nsc_u.addr.a_data,
- in->nsc_u.addr.a_length,
- in->nsc_u.addr.a_type,
- &out->nsc_u.hst,
- out->nsc_u.buff+sizeof (struct hostent),
- bufferspace,
- &saved_errno);
- } else {
- p = _uncached_gethostbyname_r(in->nsc_u.name,
- &out->nsc_u.hst,
- out->nsc_u.buff+sizeof (struct hostent),
- bufferspace,
- &saved_errno);
- }
-
- mutex_lock(&host_lock);
-
- release_clearance(in->nsc_callnumber);
-
- if (p == NULL) { /* data not found */
- if (current_admin.debug_level >= DBG_CANT_FIND) {
- if (MASKUPDATEBIT(in->nsc_callnumber) ==
- GETHOSTBYADDR) {
- logit("gethost_lookup: nscd COULDN'T FIND address %s\n",
- inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data)));
- } else {
- logit("gethost_lookup: nscd COULDN'T FIND host name %s\n",
- in->nsc_u.name);
- }
- }
+ hnam_db = make_cache(nsc_key_cis,
+ NSS_DBOP_HOSTS_BYNAME,
+ NSC_NAME_HOSTS_BYNAME,
+ NULL, NULL, NULL, nsc_ht_default, -1);
- if (!(UPDATEBIT & in->nsc_callnumber))
- current_admin.host.nsc_neg_cache_misses++;
-
- retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t));
-
- retb->nsc_refcount = 1;
- retb->nsc_data.nsc_return_code = NOTFOUND;
- retb->nsc_data.nsc_bufferbytesused =
- sizeof (nsc_return_t);
- retb->nsc_data.nsc_errno = saved_errno;
- memcpy(out, &(retb->nsc_data),
- retb->nsc_data.nsc_bufferbytesused);
- update_host_bucket((nsc_bucket_t **)bucket, retb,
- in->nsc_callnumber);
- goto getout;
- } else {
- if (current_admin.debug_level >= DBG_ALL) {
- if (MASKUPDATEBIT(in->nsc_callnumber) ==
- GETHOSTBYADDR) {
- logit("gethost_lookup: nscd FOUND addr %s\n",
- inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data)));
- } else {
- logit("gethost_lookup: nscd FOUND host name %s\n",
- in->nsc_u.name);
- }
- }
- if (!(UPDATEBIT & in->nsc_callnumber))
- current_admin.host.nsc_pos_cache_misses++;
-
- retb = fixbuffer(out, bufferspace);
-
- update_host_bucket((nsc_bucket_t **)bucket, retb,
- in->nsc_callnumber);
- if (saved_hits)
- retb->nsc_hits = saved_hits;
- }
- } else { /* found entry in cache */
- retb = (nsc_bucket_t *)*bucket;
-
- retb->nsc_hits++;
-
- memcpy(out, &(retb->nsc_data),
- retb->nsc_data.nsc_bufferbytesused);
-
- if (out->nsc_return_code == SUCCESS) {
- if (!(UPDATEBIT & in->nsc_callnumber))
- current_admin.host.nsc_pos_cache_hits++;
- if (current_admin.debug_level >= DBG_ALL) {
- if (MASKUPDATEBIT(in->nsc_callnumber) ==
- GETHOSTBYADDR) {
- logit("gethost_lookup: found address %s in cache\n",
- inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data)));
- } else {
- logit("gethost_lookup: found host name %s in cache\n",
- in->nsc_u.name);
- }
- }
- } else {
- if (!(UPDATEBIT & in->nsc_callnumber))
- current_admin.host.nsc_neg_cache_hits++;
- if (current_admin.debug_level >= DBG_ALL) {
- if (MASKUPDATEBIT(in->nsc_callnumber) ==
- GETHOSTBYADDR) {
- logit("gethost_lookup: %s marked as NOT FOUND in cache.\n",
- inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data)));
- } else {
- logit("gethost_lookup: %s marked as NOT FOUND in cache.\n",
- in->nsc_u.name);
- }
- }
- }
-
- if ((retb->nsc_timestamp < now) &&
- !(in->nsc_callnumber & UPDATEBIT) &&
- !(retb->nsc_status & ST_UPDATE_PENDING)) {
- logit("launch update since time = %d\n", retb->nsc_timestamp);
- /* cleared by deletion of old data */
- retb->nsc_status |= ST_UPDATE_PENDING;
- launch_update(in);
- }
- }
-
-getout:
-
- mutex_unlock(&host_lock);
+ addr_db = make_cache(nsc_key_other,
+ NSS_DBOP_HOSTS_BYADDR,
+ NSC_NAME_HOSTS_BYADDR,
+ hostaddr_compar,
+ hostaddr_getlogstr,
+ hostaddr_gethash, nsc_ht_default, -1);
}
-/*ARGSUSED*/
static void
-update_host_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber)
-{
- if (*old != NULL && *old != (nsc_bucket_t *)-1) {
- /* old data exists */
- free(*old);
- current_admin.host.nsc_entries--;
- }
-
- /*
- * we can do this before reseting *old since we're holding the lock
- */
+hostaddr_getlogstr(char *name, char *whoami, size_t len,
+ nss_XbyY_args_t *argp) {
+ char addr[INET6_ADDRSTRLEN];
- else if (*old == (nsc_bucket_t *)-1) {
- nscd_signal(&host_wait, (char **)old);
- }
-
-
-
- *old = new;
-
- if ((new != NULL) &&
- (new != (nsc_bucket_t *)-1)) {
- /* real data, not just update pending or invalidate */
-
- new->nsc_hits = 1;
- new->nsc_status = 0;
- new->nsc_refcount = 1;
- current_admin.host.nsc_entries++;
-
- if (new->nsc_data.nsc_return_code == SUCCESS) {
- new->nsc_timestamp = time(NULL) +
- current_admin.host.nsc_pos_ttl;
- } else {
- new->nsc_timestamp = time(NULL) +
- current_admin.host.nsc_neg_ttl;
- }
+ if (inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, addr,
+ sizeof (addr)) == NULL) {
+ (void) snprintf(whoami, len, "%s", name);
+ } else {
+ (void) snprintf(whoami, len, "%s [key=%s, addrtype=%d]",
+ name, addr, argp->key.hostaddr.type);
}
}
-
-/*ARGSUSED*/
-static nsc_bucket_t *
-fixbuffer(nsc_return_t *in, int maxlen)
-{
- nsc_return_t *out;
- nsc_bucket_t *retb;
- char *dest;
- char **aliaseslist;
- char **addrlist;
- int offset;
- int strs;
- int i;
- int numaliases;
- int numaddrs;
-
- /*
- * find out the size of the data block we're going to need
- */
-
- strs = 1 + strlen(in->nsc_u.hst.h_name);
- for (numaliases = 0; in->nsc_u.hst.h_aliases[numaliases]; numaliases++)
- strs += 1 + strlen(in->nsc_u.hst.h_aliases[numaliases]);
- strs += sizeof (char *) * (numaliases+1);
- for (numaddrs = 0; in->nsc_u.hst.h_addr_list[numaddrs]; numaddrs++)
- strs += in->nsc_u.hst.h_length;
- strs += sizeof (char *) * (numaddrs+1+3);
-
- /*
- * allocate it and copy it in
- * code doesn't assume packing order in original buffer
- */
-
- if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) {
- return (NULL);
- }
-
- out = &(retb->nsc_data);
- out->nsc_bufferbytesused = sizeof (*in) + strs;
- out->nsc_return_code = SUCCESS;
- out->nsc_errno = 0;
-
-
- dest = retb->nsc_data.nsc_u.buff + sizeof (struct hostent);
-
- offset = (int)dest;
-
- /*
- * allocat the h_aliases list and the h_addr_list first to align 'em.
- */
- aliaseslist = (char **)dest;
-
- dest += sizeof (char *) * (numaliases+1);
-
- addrlist = (char **)dest;
-
- dest += sizeof (char *) * (numaddrs+1);
-
- strcpy(dest, in->nsc_u.hst.h_name);
- strs = 1 + strlen(in->nsc_u.hst.h_name);
- out->nsc_u.hst.h_name = dest - offset;
- dest += strs;
-
-
- /*
- * fill out the h_aliases list
- */
- for (i = 0; i < numaliases; i++) {
- strcpy(dest, in->nsc_u.hst.h_aliases[i]);
- strs = 1 + strlen(in->nsc_u.hst.h_aliases[i]);
- aliaseslist[i] = dest - offset;
- dest += strs;
- }
- aliaseslist[i] = 0; /* null term ptr chain */
-
- out->nsc_u.hst.h_aliases = (char **)((int)aliaseslist-offset);
-
- /*
- * fill out the h_addr list
- */
-
- dest = (char *)(((int)dest + 3) & ~3);
-
- for (i = 0; i < numaddrs; i++) {
- memcpy(dest, in->nsc_u.hst.h_addr_list[i],
- in->nsc_u.hst.h_length);
- strs = in->nsc_u.hst.h_length;
- addrlist[i] = dest - offset;
- dest += strs;
- dest = (char *)(((int)dest + 3) & ~3);
- }
-
- addrlist[i] = 0; /* null term ptr chain */
-
- out->nsc_u.hst.h_addr_list = (char **)((int)addrlist-offset);
-
- out->nsc_u.hst.h_length = in->nsc_u.hst.h_length;
- out->nsc_u.hst.h_addrtype = in->nsc_u.hst.h_addrtype;
-
- memcpy(in, &(retb->nsc_data), retb->nsc_data.nsc_bufferbytesused);
-
- return (retb);
-
-}
-
-void
-gethost_nam_reaper()
-{
- nsc_reaper("gethost_nam", hnam_hash, &current_admin.host, &host_lock);
-}
-
-void
-gethost_addr_reaper()
-{
- nsc_reaper("gethost_addr", addr_hash, &current_admin.host, &host_lock);
+static int
+hostaddr_compar(const void *n1, const void *n2) {
+ nsc_entry_t *e1, *e2;
+ int res, l1, l2;
+
+ e1 = (nsc_entry_t *)n1;
+ e2 = (nsc_entry_t *)n2;
+ l1 = e1->key.hostaddr.len;
+ l2 = e2->key.hostaddr.len;
+ res = memcmp(e1->key.hostaddr.addr, e2->key.hostaddr.addr,
+ (l2 > l1)?l1:l2);
+ return ((res) ? _NSC_INT_KEY_CMP(res, 0) : _NSC_INT_KEY_CMP(l1, l2));
+}
+
+static uint_t
+hostaddr_gethash(nss_XbyY_key_t *key, int htsize) {
+ return (db_gethash(key->hostaddr.addr,
+ key->hostaddr.len, htsize));
}