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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <netdb.h> 30 #include <arpa/inet.h> 31 #include <netinet/in.h> 32 #include <sys/socket.h> 33 #include <syslog.h> 34 #include <sys/systeminfo.h> 35 #include "ns_internal.h" 36 #include "ldap_common.h" 37 38 /* host attributes filters */ 39 #define _H_DN "dn" 40 #define _H_NAME "cn" 41 #define _H_ADDR "iphostnumber" 42 #define _F_GETHOSTBYNAME "(&(objectClass=ipHost)(cn=%s))" 43 #define _F_GETHOSTBYNAME_SSD "(&(%%s)(cn=%s))" 44 #define _F_GETHOSTDOTTEDBYNAME "(&(objectClass=ipHost)(|(cn=%s)(cn=%s)))" 45 #define _F_GETHOSTDOTTEDBYNAME_SSD "(&(%%s)(|(cn=%s)(cn=%s)))" 46 #define _F_GETHOSTBYADDR "(&(objectClass=ipHost)(ipHostNumber=%s))" 47 #define _F_GETHOSTBYADDR_SSD "(&(%%s)(ipHostNumber=%s))" 48 49 static const char *hosts_attrs[] = { 50 _H_NAME, 51 _H_ADDR, 52 (char *)NULL 53 }; 54 55 56 /* 57 * _nss_ldap_hosts2ent is the data marshaling method for the hosts getXbyY 58 * system call gethostbyname() and gethostbyaddr. The format of this call 59 * is a cononical name and alias (alias is cononical name too) and one or 60 * more IP addresses in support of multihomed hosts. This method is called 61 * after a successful synchronous search has been performed. This method 62 * will parse the search results into struct hostent = argp->buf.buffer 63 * which gets returned to the frontend process. One of three error 64 * conditions is also returned to nsswitch. 65 */ 66 67 static int 68 _nss_ldap_hosts2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) 69 { 70 int i, j; 71 int nss_result; 72 int buflen = (int)0; 73 int firstimename = (int)1; 74 int firstimedn = (int)1; 75 int firstimeaddr = (int)1; 76 unsigned long len = 0L; 77 char **hn, **ha, **dp; 78 char *cname = (char *)NULL; 79 char *buffer = (char *)NULL; 80 char *ceiling = (char *)NULL; 81 struct hostent *host = (struct hostent *)NULL; 82 in_addr_t addr; 83 ns_ldap_result_t *result = be->result; 84 ns_ldap_attr_t *attrptr; 85 in_addr_t inet_addr(const char *cp); 86 int namecount = 0; 87 int addrcount = 0; 88 int aliascount = 0; 89 int validaddress = 0; 90 int gluelen = 0; 91 ns_ldap_entry_t *entry; 92 ns_ldap_attr_t *attr; 93 #ifdef DEBUG 94 struct in_addr in; 95 #endif /* DEBUG */ 96 97 buffer = argp->buf.buffer; 98 buflen = (size_t)argp->buf.buflen; 99 if (!argp->buf.result) { 100 nss_result = (int)NSS_STR_PARSE_ERANGE; 101 goto result_hosts2ent; 102 } 103 104 host = (struct hostent *)argp->buf.result; 105 ceiling = buffer + buflen; 106 107 nss_result = (int)NSS_STR_PARSE_SUCCESS; 108 (void) memset(argp->buf.buffer, 0, buflen); 109 110 attrptr = getattr(result, 0); 111 if (attrptr == NULL) { 112 nss_result = (int)NSS_STR_PARSE_PARSE; 113 goto result_hosts2ent; 114 } 115 116 namecount = 0; 117 addrcount = 0; 118 for (entry = result->entry; entry != NULL; entry = entry->next) { 119 for (i = 0, attr = entry->attr_pair[i]; 120 i < entry->attr_count; i++) { 121 attr = entry->attr_pair[i]; 122 if (strcasecmp(attr->attrname, _H_NAME) == 0) 123 namecount += attr->value_count; 124 if (strcasecmp(attr->attrname, _H_ADDR) == 0) 125 addrcount += attr->value_count; 126 } 127 } 128 for (entry = result->entry; entry != NULL; entry = entry->next) { 129 for (i = 0; i < entry->attr_count; i++) { 130 attrptr = entry->attr_pair[i]; 131 if (attrptr == NULL) { 132 nss_result = (int)NSS_STR_PARSE_PARSE; 133 goto result_hosts2ent; 134 } 135 if (strcasecmp(attrptr->attrname, _H_DN) == 0) { 136 for (j = 0; j < attrptr->value_count; j++) { 137 if (firstimedn) { 138 /* get domain name associated with this dn */ 139 be->toglue = _get_domain_name( 140 attrptr->attrvalue[j]); 141 firstimedn = (int)0; 142 } 143 } 144 } 145 if (strcasecmp(attrptr->attrname, _H_NAME) == 0) { 146 for (j = 0; j < attrptr->value_count; j++) { 147 if (firstimename) { 148 /* canonical name */ 149 cname = __s_api_get_canonical_name(result->entry, 150 attrptr, 1); 151 if (cname == NULL || 152 (len = strlen(cname)) < 1) { 153 nss_result = (int)NSS_STR_PARSE_PARSE; 154 goto result_hosts2ent; 155 } 156 if (be->toglue != NULL && 157 !DOTTEDSUBDOMAIN(cname)) 158 gluelen = strlen(be->toglue) + 1; 159 else 160 gluelen = 0; 161 host->h_name = buffer; 162 buffer += len + gluelen + 1; 163 if (buffer >= ceiling) { 164 nss_result = (int)NSS_STR_PARSE_ERANGE; 165 goto result_hosts2ent; 166 } 167 (void) strcpy(host->h_name, cname); 168 if (gluelen > 0) { 169 (void) strcat(host->h_name, "."); 170 (void) strcat(host->h_name, be->toglue); 171 } 172 /* alias name */ 173 aliascount = (namecount >= 1 ? (namecount - 1) : 0); 174 hn = host->h_aliases = (char **)ROUND_UP(buffer, 175 sizeof (char **)); 176 buffer = (char *)host->h_aliases + 177 (sizeof (char *) * (aliascount + 1)); 178 buffer = (char *)ROUND_UP(buffer, 179 sizeof (char **)); 180 if (buffer >= ceiling) { 181 nss_result = (int)NSS_STR_PARSE_ERANGE; 182 goto result_hosts2ent; 183 } 184 firstimename = (int)0; 185 } 186 /* alias list */ 187 if (aliascount > 0) { 188 if ((attrptr->attrvalue[j] == NULL) || 189 (len = strlen(attrptr->attrvalue[j])) < 1) { 190 nss_result = (int)NSS_STR_PARSE_PARSE; 191 goto result_hosts2ent; 192 } 193 /* skip canonical name */ 194 if (strcmp(cname, attrptr->attrvalue[j]) == 0) 195 continue; 196 /* check for duplicates */ 197 for (dp = host->h_aliases; *dp != NULL; dp++) { 198 if (strcmp(*dp, attrptr->attrvalue[j]) == 0) 199 goto next_alias; 200 } 201 if (be->toglue != NULL && 202 !DOTTEDSUBDOMAIN(attrptr->attrvalue[j])) 203 gluelen = strlen(be->toglue) + 1; 204 else 205 gluelen = 0; 206 *hn = buffer; 207 buffer += len + gluelen + 1; 208 if (buffer >= ceiling) { 209 nss_result = (int)NSS_STR_PARSE_ERANGE; 210 goto result_hosts2ent; 211 } 212 (void) strcpy(*hn, attrptr->attrvalue[j]); 213 if (gluelen > 0) { 214 (void) strcat(*hn, "."); 215 (void) strcat(*hn, be->toglue); 216 } 217 hn++; 218 } 219 next_alias: 220 continue; 221 } 222 } 223 } 224 } 225 226 for (entry = result->entry; entry != NULL; entry = entry->next) { 227 for (i = 0; i < entry->attr_count; i++) { 228 attrptr = entry->attr_pair[i]; 229 if (attrptr == NULL) { 230 nss_result = (int)NSS_STR_PARSE_PARSE; 231 goto result_hosts2ent; 232 } 233 if (strcasecmp(attrptr->attrname, _H_ADDR) == 0) { 234 for (j = 0; j < attrptr->value_count; j++) { 235 if (firstimeaddr) { 236 /* allocate 1 address per entry */ 237 ha = host->h_addr_list = 238 (char **)ROUND_UP(buffer, 239 sizeof (char **)); 240 buffer = (char *)host->h_addr_list + 241 sizeof (char *) * 242 (addrcount + 1); 243 buffer = (char *)ROUND_UP(buffer, 244 sizeof (char **)); 245 if (buffer >= ceiling) { 246 nss_result = (int)NSS_STR_PARSE_ERANGE; 247 goto result_hosts2ent; 248 } 249 firstimeaddr = (int)0; 250 } 251 /* filter out IPV6 addresses */ 252 addr = inet_addr(_strip_quotes(attrptr->attrvalue[j])); 253 if (addr == (in_addr_t)-1) { 254 goto next_addr; 255 } 256 validaddress++; 257 /* check for duplicates */ 258 for (dp = host->h_addr_list; *dp != NULL; dp++) { 259 if (memcmp(*dp, &addr, (size_t)sizeof (in_addr_t)) == 0) 260 goto next_addr; 261 } 262 *ha = buffer; 263 len = (unsigned long)sizeof (in_addr_t); 264 buffer += len; 265 if (buffer >= ceiling) { 266 nss_result = (int)NSS_STR_PARSE_ERANGE; 267 goto result_hosts2ent; 268 } 269 (void) memcpy(*ha++, (char *)&addr, (size_t)len); 270 next_addr: 271 continue; 272 } 273 } 274 } 275 } 276 277 if (validaddress == 0) { 278 nss_result = (int)NSS_STR_PARSE_NO_ADDR; 279 goto result_hosts2ent; 280 } 281 282 host->h_addrtype = AF_INET; 283 host->h_length = sizeof (uint_t); 284 285 #ifdef DEBUG 286 (void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_hosts2ent]\n"); 287 (void) fprintf(stdout, " h_name: [%s]\n", host->h_name); 288 if (host->h_aliases != NULL) { 289 for (hn = host->h_aliases; *hn != NULL; hn++) 290 (void) fprintf(stdout, " h_aliases: [%s]\n", *hn); 291 } 292 (void) fprintf(stdout, " h_addrtype: [%d]\n", host->h_addrtype); 293 (void) fprintf(stdout, " h_length: [%d]\n", host->h_length); 294 for (ha = host->h_addr_list; *ha != NULL; ha++) { 295 (void) memcpy(&in.s_addr, *ha, sizeof (in.s_addr)); 296 if (inet_ntoa(in) != NULL) 297 (void) fprintf(stdout, " h_addr_list: [%s]\n", 298 inet_ntoa(in)); 299 else 300 (void) fprintf(stdout, " h_addr_list: <NULL>\n"); 301 } 302 #endif /* DEBUG */ 303 304 result_hosts2ent: 305 306 (void) __ns_ldap_freeResult(&be->result); 307 return ((int)nss_result); 308 } 309 310 311 /* 312 * getbyname gets a struct hostent by hostname. This function constructs 313 * an ldap search filter using the name invocation parameter and the 314 * gethostbyname search filter defined. Once the filter is constructed, 315 * we search for a matching entry and marshal the data results into 316 * struct hostent for the frontend process. Host name searches will be 317 * on fully qualified host names (foo.bar.sun.com) 318 */ 319 320 static nss_status_t 321 getbyname(ldap_backend_ptr be, void *a) 322 { 323 char hostname[3 * MAXHOSTNAMELEN]; 324 char realdomain[BUFSIZ]; 325 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 326 nss_status_t lstat; 327 char searchfilter[SEARCHFILTERLEN]; 328 char userdata[SEARCHFILTERLEN]; 329 int rc; 330 331 if (_ldap_filter_name(hostname, argp->key.name, sizeof (hostname)) != 0) 332 return ((nss_status_t)NSS_NOTFOUND); 333 334 rc = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYNAME, 335 hostname); 336 if (rc >= sizeof (searchfilter) || rc < 0) 337 return ((nss_status_t)NSS_NOTFOUND); 338 339 rc = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYNAME_SSD, 340 hostname); 341 if (rc >= sizeof (userdata) || rc < 0) 342 return ((nss_status_t)NSS_NOTFOUND); 343 344 /* get the domain we are in */ 345 rc = sysinfo(SI_SRPC_DOMAIN, realdomain, BUFSIZ); 346 if (rc <= 0) 347 return ((nss_status_t)NSS_NOTFOUND); 348 349 /* Is this a request for a host.domain */ 350 if (DOTTEDSUBDOMAIN(hostname)) { 351 char host[MAXHOSTNAMELEN]; 352 char domain[MAXHOSTNAMELEN]; 353 char hname[3 * MAXHOSTNAMELEN]; 354 355 /* separate host and domain. this function */ 356 /* will munge hname, so use argp->keyname */ 357 /* from here on for original string */ 358 359 (void) strcpy(hname, hostname); 360 361 if (chophostdomain(hname, host, domain) == -1) { 362 return ((nss_status_t)NSS_NOTFOUND); 363 } 364 365 /* if domain is a proper subset of realdomain */ 366 /* ie. domain = "eng" and realdomain */ 367 /* = "eng.wiz.com", we try to lookup both" */ 368 /* host.domain and host */ 369 370 if (propersubdomain(realdomain, domain) == 1) { 371 /* yes, it is a proper domain */ 372 rc = snprintf(searchfilter, sizeof (searchfilter), 373 _F_GETHOSTDOTTEDBYNAME, hostname, host); 374 if (rc >= sizeof (searchfilter) || rc < 0) 375 return ((nss_status_t)NSS_NOTFOUND); 376 377 rc = snprintf(userdata, sizeof (userdata), 378 _F_GETHOSTDOTTEDBYNAME_SSD, hostname, host); 379 if (rc >= sizeof (userdata) || rc < 0) 380 return ((nss_status_t)NSS_NOTFOUND); 381 } else { 382 /* it is not a proper domain, so only try to look up */ 383 /* host.domain */ 384 rc = snprintf(searchfilter, sizeof (searchfilter), 385 _F_GETHOSTBYNAME, hostname); 386 if (rc >= sizeof (searchfilter) || rc < 0) 387 return ((nss_status_t)NSS_NOTFOUND); 388 389 rc = snprintf(userdata, sizeof (userdata), 390 _F_GETHOSTBYNAME_SSD, hostname); 391 if (rc >= sizeof (userdata) || rc < 0) 392 return ((nss_status_t)NSS_NOTFOUND); 393 } 394 } else { 395 rc = snprintf(searchfilter, sizeof (searchfilter), 396 _F_GETHOSTBYNAME, hostname); 397 if (rc >= sizeof (searchfilter) || rc < 0) 398 return ((nss_status_t)NSS_NOTFOUND); 399 400 rc = snprintf(userdata, sizeof (userdata), 401 _F_GETHOSTBYNAME_SSD, hostname); 402 if (rc >= sizeof (userdata) || rc < 0) 403 return ((nss_status_t)NSS_NOTFOUND); 404 } 405 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, _HOSTS, 406 searchfilter, NULL, _merge_SSD_filter, 407 userdata); 408 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 409 return ((nss_status_t)NSS_SUCCESS); 410 411 argp->h_errno = __nss2herrno(lstat); 412 return ((nss_status_t)lstat); 413 } 414 415 416 /* 417 * getbyaddr gets a struct hostent by host address. This function 418 * constructs an ldap search filter using the host address invocation 419 * parameter and the gethostbyaddr search filter defined. Once the 420 * filter is constructed, we search for a matching entry and marshal 421 * the data results into struct hostent for the frontend process. 422 * 423 * extern char *inet_ntoa_r() not an advertised function from libnsl. 424 * There is no man page and no prototype. 425 */ 426 427 static nss_status_t 428 getbyaddr(ldap_backend_ptr be, void *a) 429 { 430 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 431 struct in_addr addr; 432 char buf[18]; 433 nss_status_t lstat; 434 extern char *inet_ntoa_r(); 435 char searchfilter[SEARCHFILTERLEN]; 436 char userdata[SEARCHFILTERLEN]; 437 int ret; 438 439 argp->h_errno = 0; 440 if ((argp->key.hostaddr.type != AF_INET) || 441 (argp->key.hostaddr.len != sizeof (addr))) 442 return (NSS_NOTFOUND); 443 444 (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); 445 (void) inet_ntoa_r(addr, buf); 446 447 ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYADDR, 448 buf); 449 if (ret >= sizeof (searchfilter) || ret < 0) 450 return ((nss_status_t)NSS_NOTFOUND); 451 452 ret = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYADDR_SSD, buf); 453 if (ret >= sizeof (userdata) || ret < 0) 454 return ((nss_status_t)NSS_NOTFOUND); 455 456 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, 457 _HOSTS, searchfilter, NULL, _merge_SSD_filter, userdata); 458 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 459 return ((nss_status_t)NSS_SUCCESS); 460 461 argp->h_errno = __nss2herrno(lstat); 462 return ((nss_status_t)lstat); 463 } 464 465 static ldap_backend_op_t hosts_ops[] = { 466 _nss_ldap_destr, 467 _nss_ldap_endent, 468 _nss_ldap_setent, 469 _nss_ldap_getent, 470 getbyname, 471 getbyaddr 472 }; 473 474 475 /* 476 * _nss_ldap_hosts_constr is where life begins. This function calls the generic 477 * ldap constructor function to define and build the abstract data types 478 * required to support ldap operations. 479 */ 480 481 /*ARGSUSED0*/ 482 nss_backend_t * 483 _nss_ldap_hosts_constr(const char *dummy1, const char *dummy2, 484 const char *dummy3) 485 { 486 487 #ifdef DEBUG 488 (void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_hosts_constr]\n"); 489 #endif /* DEBUG */ 490 return ((nss_backend_t *)_nss_ldap_constr(hosts_ops, 491 sizeof (hosts_ops)/sizeof (hosts_ops[0]), _HOSTS, 492 hosts_attrs, _nss_ldap_hosts2ent)); 493 } 494