1/*++ 2/* NAME 3/* dict_nis 3 4/* SUMMARY 5/* dictionary manager interface to NIS maps 6/* SYNOPSIS 7/* #include <dict_nis.h> 8/* 9/* DICT *dict_nis_open(map, open_flags, dict_flags) 10/* const char *map; 11/* int open_flags; 12/* int dict_flags; 13/* DESCRIPTION 14/* dict_nis_open() makes the specified NIS map accessible via 15/* the generic dictionary operations described in dict_open(3). 16/* SEE ALSO 17/* dict(3) generic dictionary manager 18/* DIAGNOSTICS 19/* Fatal errors: out of memory, attempt to update NIS map. 20/* LICENSE 21/* .ad 22/* .fi 23/* The Secure Mailer license must be distributed with this software. 24/* AUTHOR(S) 25/* Wietse Venema 26/* IBM T.J. Watson Research 27/* P.O. Box 704 28/* Yorktown Heights, NY 10598, USA 29/*--*/ 30 31/* System library. */ 32 33#include "sys_defs.h" 34#include <string.h> 35 36#ifdef STRCASECMP_IN_STRINGS_H 37#include <strings.h> 38#endif 39 40#ifdef HAS_NIS 41 42#include <rpcsvc/ypclnt.h> 43#ifndef YPERR_BUSY 44#define YPERR_BUSY 16 45#endif 46#ifndef YPERR_ACCESS 47#define YPERR_ACCESS 15 48#endif 49 50#endif 51 52/* Utility library. */ 53 54#include "msg.h" 55#include "mymalloc.h" 56#include "vstring.h" 57#include "stringops.h" 58#include "dict.h" 59#include "dict_nis.h" 60 61#ifdef HAS_NIS 62 63/* Application-specific. */ 64 65typedef struct { 66 DICT dict; /* generic members */ 67} DICT_NIS; 68 69 /* 70 * Class variables, so that multiple maps can share this info. 71 */ 72static char dict_nis_disabled[1]; 73static char *dict_nis_domain; 74 75/* dict_nis_init - NIS binding */ 76 77static void dict_nis_init(void) 78{ 79 const char *myname = "dict_nis_init"; 80 81 if (yp_get_default_domain(&dict_nis_domain) != 0 82 || dict_nis_domain == 0 || *dict_nis_domain == 0 83 || strcasecmp(dict_nis_domain, "(none)") == 0) { 84 dict_nis_domain = dict_nis_disabled; 85 msg_warn("%s: NIS domain name not set - NIS lookups disabled", myname); 86 } 87 if (msg_verbose) 88 msg_info("%s: NIS domain %s", myname, dict_nis_domain); 89} 90 91/* dict_nis_strerror - map error number to string */ 92 93static char *dict_nis_strerror(int err) 94{ 95 96 /* 97 * Grr. There should be a standard function for this. 98 */ 99 switch (err) { 100 case YPERR_BADARGS: 101 return ("args to function are bad"); 102 case YPERR_RPC: 103 return ("RPC failure - domain has been unbound"); 104 case YPERR_DOMAIN: 105 return ("can't bind to server on this domain"); 106 case YPERR_MAP: 107 return ("no such map in server's domain"); 108 case YPERR_KEY: 109 return ("no such key in map"); 110 case YPERR_YPERR: 111 return ("internal yp server or client error"); 112 case YPERR_RESRC: 113 return ("resource allocation failure"); 114 case YPERR_NOMORE: 115 return ("no more records in map database"); 116 case YPERR_PMAP: 117 return ("can't communicate with portmapper"); 118 case YPERR_YPBIND: 119 return ("can't communicate with ypbind"); 120 case YPERR_YPSERV: 121 return ("can't communicate with ypserv"); 122 case YPERR_NODOM: 123 return ("local domain name not set"); 124 case YPERR_BADDB: 125 return ("yp database is bad"); 126 case YPERR_VERS: 127 return ("yp version mismatch"); 128 case YPERR_ACCESS: 129 return ("access violation"); 130 case YPERR_BUSY: 131 return ("database busy"); 132 default: 133 return ("unknown NIS lookup error"); 134 } 135} 136 137/* dict_nis_lookup - find table entry */ 138 139static const char *dict_nis_lookup(DICT *dict, const char *key) 140{ 141 DICT_NIS *dict_nis = (DICT_NIS *) dict; 142 static char *result; 143 int result_len; 144 int err; 145 static VSTRING *buf; 146 147 dict->error = 0; 148 149 /* 150 * Sanity check. 151 */ 152 if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) 153 msg_panic("dict_nis_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); 154 155 if (dict_nis_domain == dict_nis_disabled) 156 return (0); 157 158 /* 159 * Optionally fold the key. 160 */ 161 if (dict->flags & DICT_FLAG_FOLD_FIX) { 162 if (dict->fold_buf == 0) 163 dict->fold_buf = vstring_alloc(10); 164 vstring_strcpy(dict->fold_buf, key); 165 key = lowercase(vstring_str(dict->fold_buf)); 166 } 167 168 /* 169 * See if this NIS map was written with one null byte appended to key and 170 * value. 171 */ 172 if (dict->flags & DICT_FLAG_TRY1NULL) { 173 err = yp_match(dict_nis_domain, dict_nis->dict.name, 174 (void *) key, strlen(key) + 1, 175 &result, &result_len); 176 if (err == 0) { 177 dict->flags &= ~DICT_FLAG_TRY0NULL; 178 return (result); 179 } 180 } 181 182 /* 183 * See if this NIS map was written with no null byte appended to key and 184 * value. This should never be the case, but better play safe. 185 */ 186 if (dict->flags & DICT_FLAG_TRY0NULL) { 187 err = yp_match(dict_nis_domain, dict_nis->dict.name, 188 (void *) key, strlen(key), 189 &result, &result_len); 190 if (err == 0) { 191 dict->flags &= ~DICT_FLAG_TRY1NULL; 192 if (buf == 0) 193 buf = vstring_alloc(10); 194 vstring_strncpy(buf, result, result_len); 195 return (vstring_str(buf)); 196 } 197 } 198 199 /* 200 * When the NIS lookup fails for reasons other than "key not found", keep 201 * logging warnings, and hope that someone will eventually notice the 202 * problem and fix it. 203 */ 204 if (err != YPERR_KEY) { 205 msg_warn("lookup %s, NIS domain %s, map %s: %s", 206 key, dict_nis_domain, dict_nis->dict.name, 207 dict_nis_strerror(err)); 208 dict->error = DICT_ERR_RETRY; 209 } 210 return (0); 211} 212 213/* dict_nis_close - close NIS map */ 214 215static void dict_nis_close(DICT *dict) 216{ 217 if (dict->fold_buf) 218 vstring_free(dict->fold_buf); 219 dict_free(dict); 220} 221 222/* dict_nis_open - open NIS map */ 223 224DICT *dict_nis_open(const char *map, int open_flags, int dict_flags) 225{ 226 DICT_NIS *dict_nis; 227 228 if (open_flags != O_RDONLY) 229 return (dict_surrogate(DICT_TYPE_NIS, map, open_flags, dict_flags, 230 "%s:%s map requires O_RDONLY access mode", 231 DICT_TYPE_NIS, map)); 232 233 dict_nis = (DICT_NIS *) dict_alloc(DICT_TYPE_NIS, map, sizeof(*dict_nis)); 234 dict_nis->dict.lookup = dict_nis_lookup; 235 dict_nis->dict.close = dict_nis_close; 236 dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED; 237 if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) 238 dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL); 239 if (dict_flags & DICT_FLAG_FOLD_FIX) 240 dict_nis->dict.fold_buf = vstring_alloc(10); 241 if (dict_nis_domain == 0) 242 dict_nis_init(); 243 dict_nis->dict.owner.status = DICT_OWNER_TRUSTED; 244 return (DICT_DEBUG (&dict_nis->dict)); 245} 246 247#endif 248