text: /*++
  /* NAME
  /*	dict_nis 3
  /* SUMMARY
  /*	dictionary manager interface to NIS maps
  /* SYNOPSIS
  /*	#include <dict_nis.h>
  /*
  /*	DICT	*dict_nis_open(map, open_flags, dict_flags)
  /*	const char *map;
  /*	int	open_flags;
  /*	int	dict_flags;
  /* DESCRIPTION
  /*	dict_nis_open() makes the specified NIS map accessible via
  /*	the generic dictionary operations described in dict_open(3).
  /* SEE ALSO
  /*	dict(3) generic dictionary manager
  /* DIAGNOSTICS
  /*	Fatal errors: out of memory, attempt to update NIS map.
  /* LICENSE
  /* .ad
  /* .fi
  /*	The Secure Mailer license must be distributed with this software.
  /* AUTHOR(S)
  /*	Wietse Venema
  /*	IBM T.J. Watson Research
  /*	P.O. Box 704
  /*	Yorktown Heights, NY 10598, USA
  /*--*/
  
  /* System library. */
  
  #include "sys_defs.h"
  #include <string.h>
  
  #ifdef STRCASECMP_IN_STRINGS_H
  #include <strings.h>
  #endif
  
  #ifdef HAS_NIS
  
  #include <rpcsvc/ypclnt.h>
  #ifndef YPERR_BUSY
  #define YPERR_BUSY  16
  #endif
  #ifndef YPERR_ACCESS
  #define YPERR_ACCESS  15
  #endif
  
  #endif
  
  /* Utility library. */
  
  #include "msg.h"
  #include "mymalloc.h"
  #include "vstring.h"
  #include "stringops.h"
  #include "dict.h"
  #include "dict_nis.h"
  
  #ifdef HAS_NIS
  
  /* Application-specific. */
  
  typedef struct {
      DICT    dict;			/* generic members */
  } DICT_NIS;
  
   /*
    * Class variables, so that multiple maps can share this info.
    */
  static char dict_nis_disabled[1];
  static char *dict_nis_domain;
  
  /* dict_nis_init - NIS binding */
  
  static void dict_nis_init(void)
  {
      const char *myname = "dict_nis_init";
  
      if (yp_get_default_domain(&dict_nis_domain) != 0
  	|| dict_nis_domain == 0 || *dict_nis_domain == 0
  	|| strcasecmp(dict_nis_domain, "(none)") == 0) {
  	dict_nis_domain = dict_nis_disabled;
  	msg_warn("%s: NIS domain name not set - NIS lookups disabled", myname);
      }
      if (msg_verbose)
  	msg_info("%s: NIS domain %s", myname, dict_nis_domain);
  }
  
  /* dict_nis_strerror - map error number to string */
  
  static char *dict_nis_strerror(int err)
  {
  
      /*
       * Grr. There should be a standard function for this.
       */
      switch (err) {
  	case YPERR_BADARGS:
  	return ("args to function are bad");
      case YPERR_RPC:
  	return ("RPC failure - domain has been unbound");
      case YPERR_DOMAIN:
  	return ("can't bind to server on this domain");
      case YPERR_MAP:
  	return ("no such map in server's domain");
      case YPERR_KEY:
  	return ("no such key in map");
      case YPERR_YPERR:
  	return ("internal yp server or client error");
      case YPERR_RESRC:
  	return ("resource allocation failure");
      case YPERR_NOMORE:
  	return ("no more records in map database");
      case YPERR_PMAP:
  	return ("can't communicate with portmapper");
      case YPERR_YPBIND:
  	return ("can't communicate with ypbind");
      case YPERR_YPSERV:
  	return ("can't communicate with ypserv");
      case YPERR_NODOM:
  	return ("local domain name not set");
      case YPERR_BADDB:
  	return ("yp database is bad");
      case YPERR_VERS:
  	return ("yp version mismatch");
      case YPERR_ACCESS:
  	return ("access violation");
      case YPERR_BUSY:
  	return ("database busy");
      default:
  	return ("unknown NIS lookup error");
      }
  }
  
  /* dict_nis_lookup - find table entry */
  
  static const char *dict_nis_lookup(DICT *dict, const char *key)
  {
      DICT_NIS *dict_nis = (DICT_NIS *) dict;
      static char *result;
      int     result_len;
      int     err;
      static VSTRING *buf;
  
      dict->error = 0;
  
      /*
       * Sanity check.
       */
      if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
  	msg_panic("dict_nis_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
  
      if (dict_nis_domain == dict_nis_disabled)
  	return (0);
  
      /*
       * Optionally fold the key.
       */
      if (dict->flags & DICT_FLAG_FOLD_FIX) {
  	if (dict->fold_buf == 0)
  	    dict->fold_buf = vstring_alloc(10);
  	vstring_strcpy(dict->fold_buf, key);
  	key = lowercase(vstring_str(dict->fold_buf));
      }
  
      /*
       * See if this NIS map was written with one null byte appended to key and
       * value.
       */
      if (dict->flags & DICT_FLAG_TRY1NULL) {
  	err = yp_match(dict_nis_domain, dict_nis->dict.name,
  		       (void *) key, strlen(key) + 1,
  		       &result, &result_len);
  	if (err == 0) {
  	    dict->flags &= ~DICT_FLAG_TRY0NULL;
  	    return (result);
  	}
      }
  
      /*
       * See if this NIS map was written with no null byte appended to key and
       * value. This should never be the case, but better play safe.
       */
      if (dict->flags & DICT_FLAG_TRY0NULL) {
  	err = yp_match(dict_nis_domain, dict_nis->dict.name,
  		       (void *) key, strlen(key),
  		       &result, &result_len);
  	if (err == 0) {
  	    dict->flags &= ~DICT_FLAG_TRY1NULL;
  	    if (buf == 0)
  		buf = vstring_alloc(10);
  	    vstring_strncpy(buf, result, result_len);
  	    return (vstring_str(buf));
  	}
      }
  
      /*
       * When the NIS lookup fails for reasons other than "key not found", keep
       * logging warnings, and hope that someone will eventually notice the
       * problem and fix it.
       */
      if (err != YPERR_KEY) {
  	msg_warn("lookup %s, NIS domain %s, map %s: %s",
  		 key, dict_nis_domain, dict_nis->dict.name,
  		 dict_nis_strerror(err));
  	dict->error = DICT_ERR_RETRY;
      }
      return (0);
  }
  
  /* dict_nis_close - close NIS map */
  
  static void dict_nis_close(DICT *dict)
  {
      if (dict->fold_buf)
  	vstring_free(dict->fold_buf);
      dict_free(dict);
  }
  
  /* dict_nis_open - open NIS map */
  
  DICT   *dict_nis_open(const char *map, int open_flags, int dict_flags)
  {
      DICT_NIS *dict_nis;
  
      if (open_flags != O_RDONLY)
  	return (dict_surrogate(DICT_TYPE_NIS, map, open_flags, dict_flags,
  			       "%s:%s map requires O_RDONLY access mode",
  			       DICT_TYPE_NIS, map));
  
      dict_nis = (DICT_NIS *) dict_alloc(DICT_TYPE_NIS, map, sizeof(*dict_nis));
      dict_nis->dict.lookup = dict_nis_lookup;
      dict_nis->dict.close = dict_nis_close;
      dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED;
      if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
  	dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
      if (dict_flags & DICT_FLAG_FOLD_FIX)
  	dict_nis->dict.fold_buf = vstring_alloc(10);
      if (dict_nis_domain == 0)
  	dict_nis_init();
      dict_nis->dict.owner.status = DICT_OWNER_TRUSTED;
      return (DICT_DEBUG (&dict_nis->dict));
  }
  
  #endif
  