1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <netdb.h> 29 #include <arpa/inet.h> 30 #include <netinet/in.h> 31 #include <sys/socket.h> 32 #include <syslog.h> 33 #include <sys/systeminfo.h> 34 #include "ns_internal.h" 35 #include "ldap_common.h" 36 37 /* host attributes filters */ 38 #define _H_DN "dn" 39 #define _H_NAME "cn" 40 #define _H_ADDR "iphostnumber" 41 #define _F_GETHOSTBYNAME "(&(objectClass=ipHost)(cn=%s))" 42 #define _F_GETHOSTBYNAME_SSD "(&(%%s)(cn=%s))" 43 #define _F_GETHOSTDOTTEDBYNAME "(&(objectClass=ipHost)(|(cn=%s)(cn=%s)))" 44 #define _F_GETHOSTDOTTEDBYNAME_SSD "(&(%%s)(|(cn=%s)(cn=%s)))" 45 #define _F_GETHOSTBYADDR "(&(objectClass=ipHost)(ipHostNumber=%s))" 46 #define _F_GETHOSTBYADDR_SSD "(&(%%s)(ipHostNumber=%s))" 47 48 static const char *hosts_attrs[] = { 49 _H_NAME, 50 _H_ADDR, 51 (char *)NULL 52 }; 53 54 /* 55 * _nss_ldap_hosts2str is the data marshaling method for the hosts getXbyY 56 * system call gethostbyname() and gethostbyaddr. 57 * This method is called after a successful search has been performed. 58 * This method will parse the search results into the file format. 59 * e.g. 60 * 61 * 9.9.9.9 jurassic jurassic1 jurassic2 62 * 10.10.10.10 puppy 63 * 64 */ 65 int 66 _nss_ldap_hosts2str_int(int af, ldap_backend_ptr be, nss_XbyY_args_t *argp) 67 { 68 uint_t i; 69 int nss_result; 70 int buflen, buflen1, buflen2, len; 71 int firstimedn = 1, first_entry; 72 int validaddress = 0, copy_cname; 73 char *cname = NULL, *h_name = NULL; 74 char *buffer = NULL; 75 char *name; 76 ns_ldap_result_t *result = be->result; 77 ns_ldap_attr_t *names; 78 ns_ldap_entry_t *entry; 79 char **ips = NULL, **dns = NULL; 80 char *first_host = NULL, *other_hosts = NULL; 81 char *buf1, *buf2; 82 83 if (result == NULL) 84 return (NSS_STR_PARSE_PARSE); 85 buflen = buflen1 = buflen2 = argp->buf.buflen; 86 87 if (argp->buf.result != NULL) { 88 if ((be->buffer = calloc(1, buflen)) == NULL) { 89 nss_result = NSS_STR_PARSE_PARSE; 90 goto result_host2str; 91 } 92 buffer = be->buffer; 93 } else 94 buffer = argp->buf.buffer; 95 if ((first_host = calloc(1, buflen1)) == NULL) { 96 nss_result = NSS_STR_PARSE_PARSE; 97 goto result_host2str; 98 } 99 if ((other_hosts = calloc(1, buflen2)) == NULL) { 100 nss_result = NSS_STR_PARSE_PARSE; 101 goto result_host2str; 102 } 103 104 nss_result = NSS_STR_PARSE_SUCCESS; 105 (void) memset(argp->buf.buffer, 0, buflen); 106 /* 107 * Multiple lines return will be sepereated by newlines 108 * Single line return or last line does not have newline 109 * e.g. 110 * 111 * 8.8.8.8 hostname 112 * 113 * or the search for hostname h1 returns 3 entries 114 * 115 * 9.9.9.9 h1 116 * 10.10.10.10 h1 xx 117 * 20.20.20.20 h1 yyy 118 * 119 * str2hostent expects all name/aliases in the first entry 120 * so the string is organized as 121 * 122 * "9.9.9.9 h1 xx yy\n10.10.10.10 \n20.20.20.20 " 123 * 124 * Use first_host to hold "9.9.9.9 h1 xx yy" and other_hosts to hold 125 * "\n10.10.10.10 \n20.20.20.20 " 126 * 127 */ 128 buf1 = first_host; 129 buf2 = other_hosts; 130 first_entry = 1; 131 for (entry = result->entry; entry != NULL; entry = entry->next) { 132 if (firstimedn) { 133 dns = __ns_ldap_getAttr(entry, _H_DN); 134 if (dns == NULL || dns[0] == NULL || strlen(dns[0]) < 1) { 135 nss_result = NSS_STR_PARSE_PARSE; 136 goto result_host2str; 137 } 138 /* get domain name associated with this dn */ 139 be->toglue = _get_domain_name(dns[0]); 140 firstimedn = 0; 141 } 142 143 /* Get IP */ 144 ips = __ns_ldap_getAttr(entry, _H_ADDR); 145 if (ips == NULL || ips[0] == NULL || strlen(ips[0]) < 1) { 146 nss_result = NSS_STR_PARSE_PARSE; 147 goto result_host2str; 148 } 149 /* Skip IPV6 address in AF_INET mode */ 150 if (af == AF_INET && 151 (inet_addr(_strip_quotes(ips[0])) == (in_addr_t)-1)) 152 continue; 153 154 /* A valid address for either af mode */ 155 validaddress++; 156 157 if (first_entry) { 158 len = snprintf(buf1, buflen1, "%s", ips[0]); 159 TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); 160 } else { 161 len = snprintf(buf2, buflen2, "\n%s ", ips[0]); 162 TEST_AND_ADJUST(len, buf2, buflen2, result_host2str); 163 } 164 165 /* Get host names */ 166 names = __ns_ldap_getAttrStruct(entry, _H_NAME); 167 if (names == NULL || names->attrvalue == NULL) { 168 nss_result = NSS_STR_PARSE_PARSE; 169 goto result_host2str; 170 } 171 172 /* Get canonical name of each entry */ 173 cname = __s_api_get_canonical_name(entry, 174 names, 1); 175 if (cname == NULL || strlen(cname) < 1) { 176 nss_result = NSS_STR_PARSE_PARSE; 177 goto result_host2str; 178 } 179 180 /* Filter cname that's identical to h_name */ 181 if (first_entry) { 182 h_name = cname; 183 first_entry = 0; 184 copy_cname = 1; 185 } else if (strcasecmp(cname, h_name) != 0) { 186 copy_cname = 1; 187 } else 188 copy_cname = 0; 189 190 if (copy_cname) { 191 /* Use the canonical name as the host name */ 192 if (DOTTEDSUBDOMAIN(cname)) 193 len = snprintf(buf1, buflen1, " %s", cname); 194 else 195 /* append domain name */ 196 len = snprintf(buf1, buflen1, " %s.%s", cname, 197 be->toglue); 198 199 TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); 200 } 201 202 /* Append aliases */ 203 for (i = 0; i < names->value_count; i++) { 204 name = names->attrvalue[i]; 205 if (name == NULL) { 206 nss_result = NSS_STR_PARSE_PARSE; 207 goto result_host2str; 208 } 209 /* Skip the canonical name and h_name */ 210 if (strcasecmp(name, cname) != 0 && 211 strcasecmp(name, h_name) != 0) { 212 if (DOTTEDSUBDOMAIN(name)) 213 len = snprintf(buf1, buflen1, " %s", name); 214 else 215 /* append domain name */ 216 len = snprintf(buf1, buflen1, " %s.%s", 217 name, be->toglue); 218 TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); 219 } 220 } 221 } 222 223 if (validaddress == 0) { 224 /* 225 * For AF_INET mode, it found an IPv6 address and skipped it. 226 */ 227 nss_result = NSS_STR_PARSE_NO_ADDR; 228 goto result_host2str; 229 } 230 /* Combine 2 strings */ 231 len = snprintf(buffer, buflen, "%s%s", first_host, other_hosts); 232 TEST_AND_ADJUST(len, buffer, buflen, result_host2str); 233 234 /* The front end marshaller doesn't need to copy trailing nulls */ 235 if (argp->buf.result != NULL) 236 be->buflen = strlen(be->buffer); 237 238 result_host2str: 239 if (first_host) 240 free(first_host); 241 if (other_hosts) 242 free(other_hosts); 243 (void) __ns_ldap_freeResult(&be->result); 244 return (nss_result); 245 } 246 247 static int 248 _nss_ldap_hosts2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { 249 return (_nss_ldap_hosts2str_int(AF_INET, be, argp)); 250 } 251 252 /* 253 * getbyname gets a struct hostent by hostname. This function constructs 254 * an ldap search filter using the name invocation parameter and the 255 * gethostbyname search filter defined. Once the filter is constructed, 256 * we search for a matching entry and marshal the data results into 257 * struct hostent for the frontend process. Host name searches will be 258 * on fully qualified host names (foo.bar.sun.com) 259 */ 260 261 static nss_status_t 262 getbyname(ldap_backend_ptr be, void *a) 263 { 264 char hostname[3 * MAXHOSTNAMELEN]; 265 char realdomain[BUFSIZ]; 266 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 267 nss_status_t lstat; 268 char searchfilter[SEARCHFILTERLEN]; 269 char userdata[SEARCHFILTERLEN]; 270 int rc; 271 272 if (_ldap_filter_name(hostname, argp->key.name, sizeof (hostname)) != 0) 273 return ((nss_status_t)NSS_NOTFOUND); 274 275 rc = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYNAME, 276 hostname); 277 if (rc >= sizeof (searchfilter) || rc < 0) 278 return ((nss_status_t)NSS_NOTFOUND); 279 280 rc = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYNAME_SSD, 281 hostname); 282 if (rc >= sizeof (userdata) || rc < 0) 283 return ((nss_status_t)NSS_NOTFOUND); 284 285 /* get the domain we are in */ 286 rc = sysinfo(SI_SRPC_DOMAIN, realdomain, BUFSIZ); 287 if (rc <= 0) 288 return ((nss_status_t)NSS_NOTFOUND); 289 290 /* Is this a request for a host.domain */ 291 if (DOTTEDSUBDOMAIN(hostname)) { 292 char host[MAXHOSTNAMELEN]; 293 char domain[MAXHOSTNAMELEN]; 294 char hname[3 * MAXHOSTNAMELEN]; 295 296 /* separate host and domain. this function */ 297 /* will munge hname, so use argp->keyname */ 298 /* from here on for original string */ 299 300 (void) strcpy(hname, hostname); 301 302 if (chophostdomain(hname, host, domain) == -1) { 303 return ((nss_status_t)NSS_NOTFOUND); 304 } 305 306 /* if domain is a proper subset of realdomain */ 307 /* ie. domain = "eng" and realdomain */ 308 /* = "eng.wiz.com", we try to lookup both" */ 309 /* host.domain and host */ 310 311 if (propersubdomain(realdomain, domain) == 1) { 312 /* yes, it is a proper domain */ 313 rc = snprintf(searchfilter, sizeof (searchfilter), 314 _F_GETHOSTDOTTEDBYNAME, hostname, host); 315 if (rc >= sizeof (searchfilter) || rc < 0) 316 return ((nss_status_t)NSS_NOTFOUND); 317 318 rc = snprintf(userdata, sizeof (userdata), 319 _F_GETHOSTDOTTEDBYNAME_SSD, hostname, host); 320 if (rc >= sizeof (userdata) || rc < 0) 321 return ((nss_status_t)NSS_NOTFOUND); 322 } else { 323 /* it is not a proper domain, so only try to look up */ 324 /* host.domain */ 325 rc = snprintf(searchfilter, sizeof (searchfilter), 326 _F_GETHOSTBYNAME, hostname); 327 if (rc >= sizeof (searchfilter) || rc < 0) 328 return ((nss_status_t)NSS_NOTFOUND); 329 330 rc = snprintf(userdata, sizeof (userdata), 331 _F_GETHOSTBYNAME_SSD, hostname); 332 if (rc >= sizeof (userdata) || rc < 0) 333 return ((nss_status_t)NSS_NOTFOUND); 334 } 335 } else { 336 rc = snprintf(searchfilter, sizeof (searchfilter), 337 _F_GETHOSTBYNAME, hostname); 338 if (rc >= sizeof (searchfilter) || rc < 0) 339 return ((nss_status_t)NSS_NOTFOUND); 340 341 rc = snprintf(userdata, sizeof (userdata), 342 _F_GETHOSTBYNAME_SSD, hostname); 343 if (rc >= sizeof (userdata) || rc < 0) 344 return ((nss_status_t)NSS_NOTFOUND); 345 } 346 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, _HOSTS, 347 searchfilter, NULL, _merge_SSD_filter, 348 userdata); 349 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 350 return ((nss_status_t)NSS_SUCCESS); 351 352 argp->h_errno = __nss2herrno(lstat); 353 return ((nss_status_t)lstat); 354 } 355 356 357 /* 358 * getbyaddr gets a struct hostent by host address. This function 359 * constructs an ldap search filter using the host address invocation 360 * parameter and the gethostbyaddr search filter defined. Once the 361 * filter is constructed, we search for a matching entry and marshal 362 * the data results into struct hostent for the frontend process. 363 * 364 * extern char *inet_ntoa_r() not an advertised function from libnsl. 365 * There is no man page and no prototype. 366 */ 367 368 static nss_status_t 369 getbyaddr(ldap_backend_ptr be, void *a) 370 { 371 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 372 struct in_addr addr; 373 char buf[18]; 374 nss_status_t lstat; 375 extern char *inet_ntoa_r(); 376 char searchfilter[SEARCHFILTERLEN]; 377 char userdata[SEARCHFILTERLEN]; 378 int ret; 379 380 argp->h_errno = 0; 381 if ((argp->key.hostaddr.type != AF_INET) || 382 (argp->key.hostaddr.len != sizeof (addr))) 383 return (NSS_NOTFOUND); 384 385 (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); 386 (void) inet_ntoa_r(addr, buf); 387 388 ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYADDR, 389 buf); 390 if (ret >= sizeof (searchfilter) || ret < 0) 391 return ((nss_status_t)NSS_NOTFOUND); 392 393 ret = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYADDR_SSD, buf); 394 if (ret >= sizeof (userdata) || ret < 0) 395 return ((nss_status_t)NSS_NOTFOUND); 396 397 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, 398 _HOSTS, searchfilter, NULL, _merge_SSD_filter, userdata); 399 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 400 return ((nss_status_t)NSS_SUCCESS); 401 402 argp->h_errno = __nss2herrno(lstat); 403 return ((nss_status_t)lstat); 404 } 405 406 static ldap_backend_op_t hosts_ops[] = { 407 _nss_ldap_destr, 408 _nss_ldap_endent, 409 _nss_ldap_setent, 410 _nss_ldap_getent, 411 getbyname, 412 getbyaddr 413 }; 414 415 416 /* 417 * _nss_ldap_hosts_constr is where life begins. This function calls the generic 418 * ldap constructor function to define and build the abstract data types 419 * required to support ldap operations. 420 */ 421 422 /*ARGSUSED0*/ 423 nss_backend_t * 424 _nss_ldap_hosts_constr(const char *dummy1, const char *dummy2, 425 const char *dummy3) 426 { 427 428 return ((nss_backend_t *)_nss_ldap_constr(hosts_ops, 429 sizeof (hosts_ops)/sizeof (hosts_ops[0]), _HOSTS, 430 hosts_attrs, _nss_ldap_hosts2str)); 431 } 432