/* $NetBSD: dict_nis.c,v 1.1.1.2 2013/01/02 18:59:12 tron Exp $ */
/*++
/* 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