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 if (be->toglue) { 244 free(be->toglue); 245 be->toglue = NULL; 246 } 247 (void) __ns_ldap_freeResult(&be->result); 248 return (nss_result); 249 } 250 251 static int 252 _nss_ldap_hosts2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { 253 return (_nss_ldap_hosts2str_int(AF_INET, be, argp)); 254 } 255 256 /* 257 * getbyname gets a struct hostent by hostname. This function constructs 258 * an ldap search filter using the name invocation parameter and the 259 * gethostbyname search filter defined. Once the filter is constructed, 260 * we search for a matching entry and marshal the data results into 261 * struct hostent for the frontend process. Host name searches will be 262 * on fully qualified host names (foo.bar.sun.com) 263 */ 264 265 static nss_status_t 266 getbyname(ldap_backend_ptr be, void *a) 267 { 268 char hostname[3 * MAXHOSTNAMELEN]; 269 char realdomain[BUFSIZ]; 270 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 271 nss_status_t lstat; 272 char searchfilter[SEARCHFILTERLEN]; 273 char userdata[SEARCHFILTERLEN]; 274 int rc; 275 276 if (_ldap_filter_name(hostname, argp->key.name, sizeof (hostname)) != 0) 277 return ((nss_status_t)NSS_NOTFOUND); 278 279 rc = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYNAME, 280 hostname); 281 if (rc >= sizeof (searchfilter) || rc < 0) 282 return ((nss_status_t)NSS_NOTFOUND); 283 284 rc = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYNAME_SSD, 285 hostname); 286 if (rc >= sizeof (userdata) || rc < 0) 287 return ((nss_status_t)NSS_NOTFOUND); 288 289 /* get the domain we are in */ 290 rc = sysinfo(SI_SRPC_DOMAIN, realdomain, BUFSIZ); 291 if (rc <= 0) 292 return ((nss_status_t)NSS_NOTFOUND); 293 294 /* Is this a request for a host.domain */ 295 if (DOTTEDSUBDOMAIN(hostname)) { 296 char host[MAXHOSTNAMELEN]; 297 char domain[MAXHOSTNAMELEN]; 298 char hname[3 * MAXHOSTNAMELEN]; 299 300 /* separate host and domain. this function */ 301 /* will munge hname, so use argp->keyname */ 302 /* from here on for original string */ 303 304 (void) strcpy(hname, hostname); 305 306 if (chophostdomain(hname, host, domain) == -1) { 307 return ((nss_status_t)NSS_NOTFOUND); 308 } 309 310 /* if domain is a proper subset of realdomain */ 311 /* ie. domain = "eng" and realdomain */ 312 /* = "eng.wiz.com", we try to lookup both" */ 313 /* host.domain and host */ 314 315 if (propersubdomain(realdomain, domain) == 1) { 316 /* yes, it is a proper domain */ 317 rc = snprintf(searchfilter, sizeof (searchfilter), 318 _F_GETHOSTDOTTEDBYNAME, hostname, host); 319 if (rc >= sizeof (searchfilter) || rc < 0) 320 return ((nss_status_t)NSS_NOTFOUND); 321 322 rc = snprintf(userdata, sizeof (userdata), 323 _F_GETHOSTDOTTEDBYNAME_SSD, hostname, host); 324 if (rc >= sizeof (userdata) || rc < 0) 325 return ((nss_status_t)NSS_NOTFOUND); 326 } else { 327 /* it is not a proper domain, so only try to look up */ 328 /* host.domain */ 329 rc = snprintf(searchfilter, sizeof (searchfilter), 330 _F_GETHOSTBYNAME, hostname); 331 if (rc >= sizeof (searchfilter) || rc < 0) 332 return ((nss_status_t)NSS_NOTFOUND); 333 334 rc = snprintf(userdata, sizeof (userdata), 335 _F_GETHOSTBYNAME_SSD, hostname); 336 if (rc >= sizeof (userdata) || rc < 0) 337 return ((nss_status_t)NSS_NOTFOUND); 338 } 339 } else { 340 rc = snprintf(searchfilter, sizeof (searchfilter), 341 _F_GETHOSTBYNAME, hostname); 342 if (rc >= sizeof (searchfilter) || rc < 0) 343 return ((nss_status_t)NSS_NOTFOUND); 344 345 rc = snprintf(userdata, sizeof (userdata), 346 _F_GETHOSTBYNAME_SSD, hostname); 347 if (rc >= sizeof (userdata) || rc < 0) 348 return ((nss_status_t)NSS_NOTFOUND); 349 } 350 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, _HOSTS, 351 searchfilter, NULL, _merge_SSD_filter, 352 userdata); 353 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 354 return ((nss_status_t)NSS_SUCCESS); 355 356 argp->h_errno = __nss2herrno(lstat); 357 return ((nss_status_t)lstat); 358 } 359 360 361 /* 362 * getbyaddr gets a struct hostent by host address. This function 363 * constructs an ldap search filter using the host address invocation 364 * parameter and the gethostbyaddr search filter defined. Once the 365 * filter is constructed, we search for a matching entry and marshal 366 * the data results into struct hostent for the frontend process. 367 * 368 * extern char *inet_ntoa_r() not an advertised function from libnsl. 369 * There is no man page and no prototype. 370 */ 371 372 static nss_status_t 373 getbyaddr(ldap_backend_ptr be, void *a) 374 { 375 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 376 struct in_addr addr; 377 char buf[18]; 378 nss_status_t lstat; 379 extern char *inet_ntoa_r(); 380 char searchfilter[SEARCHFILTERLEN]; 381 char userdata[SEARCHFILTERLEN]; 382 int ret; 383 384 argp->h_errno = 0; 385 if ((argp->key.hostaddr.type != AF_INET) || 386 (argp->key.hostaddr.len != sizeof (addr))) 387 return (NSS_NOTFOUND); 388 389 (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); 390 (void) inet_ntoa_r(addr, buf); 391 392 ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETHOSTBYADDR, 393 buf); 394 if (ret >= sizeof (searchfilter) || ret < 0) 395 return ((nss_status_t)NSS_NOTFOUND); 396 397 ret = snprintf(userdata, sizeof (userdata), _F_GETHOSTBYADDR_SSD, buf); 398 if (ret >= sizeof (userdata) || ret < 0) 399 return ((nss_status_t)NSS_NOTFOUND); 400 401 lstat = (nss_status_t)_nss_ldap_lookup(be, argp, 402 _HOSTS, searchfilter, NULL, _merge_SSD_filter, userdata); 403 if (lstat == (nss_status_t)NS_LDAP_SUCCESS) 404 return ((nss_status_t)NSS_SUCCESS); 405 406 argp->h_errno = __nss2herrno(lstat); 407 return ((nss_status_t)lstat); 408 } 409 410 static ldap_backend_op_t hosts_ops[] = { 411 _nss_ldap_destr, 412 _nss_ldap_endent, 413 _nss_ldap_setent, 414 _nss_ldap_getent, 415 getbyname, 416 getbyaddr 417 }; 418 419 420 /* 421 * _nss_ldap_hosts_constr is where life begins. This function calls the generic 422 * ldap constructor function to define and build the abstract data types 423 * required to support ldap operations. 424 */ 425 426 /*ARGSUSED0*/ 427 nss_backend_t * 428 _nss_ldap_hosts_constr(const char *dummy1, const char *dummy2, 429 const char *dummy3) 430 { 431 432 return ((nss_backend_t *)_nss_ldap_constr(hosts_ops, 433 sizeof (hosts_ops)/sizeof (hosts_ops[0]), _HOSTS, 434 hosts_attrs, _nss_ldap_hosts2str)); 435 } 436