summaryrefslogtreecommitdiffstats
path: root/src/util/dict_nis.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/dict_nis.c')
-rw-r--r--src/util/dict_nis.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/util/dict_nis.c b/src/util/dict_nis.c
new file mode 100644
index 0000000..357011f
--- /dev/null
+++ b/src/util/dict_nis.c
@@ -0,0 +1,247 @@
+/*++
+/* 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