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 2007 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 "ldap_common.h" 29 #include <malloc.h> 30 #include <synch.h> 31 #include <syslog.h> 32 #include <rpcsvc/ypclnt.h> 33 #include <rpcsvc/yp_prot.h> 34 #include <thread.h> 35 #include <ctype.h> 36 #include <stdlib.h> 37 #include <signal.h> 38 #include <sys/stat.h> 39 40 /* getent attributes filters */ 41 #define _F_GETALIASENT "(objectClass=rfc822MailGroup)" 42 #define _F_GETAUTHNAME "(objectClass=SolarisAuthAttr)" 43 #define _F_GETAUUSERNAME "(objectClass=SolarisAuditUser)" 44 #define _F_GETEXECNAME "(objectClass=SolarisExecAttr)" 45 #define _F_GETGRENT "(objectClass=posixGroup)" 46 #define _F_GETHOSTENT "(objectClass=ipHost)" 47 #define _F_GETNETENT "(objectClass=ipNetwork)" 48 #define _F_GETPROFNAME \ 49 "(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))" 50 #define _F_GETPROTOENT "(objectClass=ipProtocol)" 51 #define _F_GETPWENT "(objectClass=posixAccount)" 52 #define _F_GETPRINTERENT "(objectClass=sunPrinter)" 53 #define _F_GETRPCENT "(objectClass=oncRpc)" 54 #define _F_GETSERVENT "(objectClass=ipService)" 55 #define _F_GETSPENT "(objectclass=shadowAccount)" 56 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)" 57 #define _F_GETPROJENT "(objectClass=SolarisProject)" 58 #define _F_GETTNRHDB "(objectClass=ipTnetHost)" 59 #define _F_GETTNRHTP "(&(objectClass=ipTnetTemplate)"\ 60 "(SolarisAttrKeyValue=*))" 61 #define _F_GETENT_SSD "(%s)" 62 63 static struct gettablefilter { 64 char *tablename; 65 char *tablefilter; 66 } gettablefilterent[] = { 67 {(char *)_PASSWD, (char *)_F_GETPWENT}, 68 {(char *)_SHADOW, (char *)_F_GETSPENT}, 69 {(char *)_GROUP, (char *)_F_GETGRENT}, 70 {(char *)_HOSTS, (char *)_F_GETHOSTENT}, 71 {(char *)_NETWORKS, (char *)_F_GETNETENT}, 72 {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT}, 73 {(char *)_RPC, (char *)_F_GETRPCENT}, 74 {(char *)_ALIASES, (char *)_F_GETALIASENT}, 75 {(char *)_SERVICES, (char *)_F_GETSERVENT}, 76 {(char *)_AUUSER, (char *)_F_GETAUUSERNAME}, 77 {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME}, 78 {(char *)_EXECATTR, (char *)_F_GETEXECNAME}, 79 {(char *)_PROFATTR, (char *)_F_GETPROFNAME}, 80 {(char *)_USERATTR, (char *)_F_GETUSERNAME}, 81 {(char *)_PROJECT, (char *)_F_GETPROJENT}, 82 {(char *)_PRINTERS, (char *)_F_GETPRINTERENT}, 83 {(char *)_TNRHDB, (char *)_F_GETTNRHDB}, 84 {(char *)_TNRHTP, (char *)_F_GETTNRHTP}, 85 {(char *)NULL, (char *)NULL} 86 }; 87 88 89 nss_status_t 90 switch_err(int rc, ns_ldap_error_t *error) 91 { 92 switch (rc) { 93 case NS_LDAP_SUCCESS: 94 return (NSS_SUCCESS); 95 96 case NS_LDAP_NOTFOUND: 97 return (NSS_NOTFOUND); 98 99 case NS_LDAP_PARTIAL: 100 return (NSS_TRYAGAIN); 101 102 case NS_LDAP_INTERNAL: 103 if (error && (error->status == LDAP_SERVER_DOWN || 104 error->status == LDAP_TIMEOUT)) 105 return (NSS_TRYAGAIN); 106 else 107 return (NSS_UNAVAIL); 108 109 default: 110 return (NSS_UNAVAIL); 111 } 112 } 113 /* ARGSUSED */ 114 nss_status_t 115 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, 116 char *database, char *searchfilter, char *domain, 117 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 118 char **realfilter, const void *userdata), 119 const void *userdata) 120 { 121 int callbackstat = 0; 122 ns_ldap_error_t *error = NULL; 123 int rc; 124 125 #ifdef DEBUG 126 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n"); 127 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter); 128 (void) fprintf(stdout, 129 "\tuserdata: %s\n", userdata ? userdata : "NULL"); 130 (void) fprintf(stdout, "\tdatabase: %s\n", database); 131 #endif /* DEBUG */ 132 133 (void) __ns_ldap_freeResult(&be->result); 134 135 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb, 136 be->attrs, NULL, 0, &be->result, &error, NULL, 137 userdata)) != NS_LDAP_SUCCESS) { 138 argp->returnval = 0; 139 rc = switch_err(rc, error); 140 (void) __ns_ldap_freeError(&error); 141 142 return (rc); 143 } 144 (void) __ns_ldap_freeError(&error); 145 /* callback function */ 146 if ((callbackstat = 147 be->ldapobj2str(be, argp)) != NSS_STR_PARSE_SUCCESS) { 148 goto error_out; 149 } 150 151 /* 152 * publickey does not have a front end marshaller and expects 153 * a string to be returned in NSS. 154 * No need to convert file format -> struct. 155 * 156 */ 157 if (be->db_type == NSS_LDAP_DB_PUBLICKEY) { 158 argp->returnval = argp->buf.buffer; 159 argp->returnlen = strlen(argp->buf.buffer); 160 be->db_type = NSS_LDAP_DB_NONE; 161 return (NSS_SUCCESS); 162 } 163 /* 164 * Assume the switch engine wants the returned data in the file 165 * format when argp->buf.result == NULL. 166 * The front-end marshaller str2ether(ethers) uses 167 * ent (argp->buf.result) and buffer (argp->buf.buffer) 168 * for different purpose so ethers has to be treated differently. 169 */ 170 if (argp->buf.result != NULL || 171 be->db_type == NSS_LDAP_DB_ETHERS) { 172 /* file format -> struct */ 173 if (argp->str2ent == NULL) { 174 callbackstat = NSS_STR_PARSE_PARSE; 175 goto error_out; 176 } 177 178 callbackstat = (*argp->str2ent)(be->buffer, 179 be->buflen, 180 argp->buf.result, 181 argp->buf.buffer, 182 argp->buf.buflen); 183 if (callbackstat == NSS_STR_PARSE_SUCCESS) { 184 if (be->db_type == NSS_LDAP_DB_ETHERS && 185 argp->buf.buffer != NULL) { 186 argp->returnval = argp->buf.buffer; 187 argp->returnlen = strlen(argp->buf.buffer); 188 } else { 189 argp->returnval = argp->buf.result; 190 argp->returnlen = 1; /* irrelevant */ 191 } 192 if (be->buffer != NULL) { 193 free(be->buffer); 194 be->buffer = NULL; 195 be->buflen = 0; 196 be->db_type = NSS_LDAP_DB_NONE; 197 } 198 return ((nss_status_t)NSS_SUCCESS); 199 } 200 } else { 201 /* return file format in argp->buf.buffer */ 202 argp->returnval = argp->buf.buffer; 203 argp->returnlen = strlen(argp->buf.buffer); 204 return ((nss_status_t)NSS_SUCCESS); 205 } 206 207 error_out: 208 if (be->buffer != NULL) { 209 free(be->buffer); 210 be->buffer = NULL; 211 be->buflen = 0; 212 be->db_type = NSS_LDAP_DB_NONE; 213 } 214 /* error */ 215 if (callbackstat == NSS_STR_PARSE_PARSE) { 216 argp->returnval = 0; 217 return ((nss_status_t)NSS_NOTFOUND); 218 } 219 if (callbackstat == NSS_STR_PARSE_ERANGE) { 220 argp->erange = 1; 221 return ((nss_status_t)NSS_NOTFOUND); 222 } 223 if (callbackstat == NSS_STR_PARSE_NO_ADDR) { 224 /* No IPV4 address is found */ 225 argp->h_errno = HOST_NOT_FOUND; 226 return ((nss_status_t)NSS_NOTFOUND); 227 } 228 return ((nss_status_t)NSS_UNAVAIL); 229 } 230 231 /* 232 * This function is similar to _nss_ldap_lookup except it does not 233 * do a callback. It is only used by getnetgrent.c 234 */ 235 236 /* ARGSUSED */ 237 nss_status_t 238 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, 239 char *database, char *searchfilter, char *domain, 240 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 241 char **realfilter, const void *userdata), 242 const void *userdata) 243 { 244 ns_ldap_error_t *error = NULL; 245 int rc; 246 247 #ifdef DEBUG 248 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n"); 249 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter); 250 (void) fprintf(stdout, "\tdatabase: %s\n", database); 251 (void) fprintf(stdout, 252 "\tuserdata: %s\n", userdata ? userdata : "NULL"); 253 #endif /* DEBUG */ 254 255 (void) __ns_ldap_freeResult(&be->result); 256 257 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb, 258 be->attrs, NULL, 0, &be->result, &error, NULL, 259 userdata)) != NS_LDAP_SUCCESS) { 260 argp->returnval = 0; 261 rc = switch_err(rc, error); 262 (void) __ns_ldap_freeError(&error); 263 return (rc); 264 } 265 266 return ((nss_status_t)NSS_SUCCESS); 267 } 268 269 270 /* 271 * 272 */ 273 274 void 275 _clean_ldap_backend(ldap_backend_ptr be) 276 { 277 ns_ldap_error_t *error; 278 279 #ifdef DEBUG 280 (void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n"); 281 #endif /* DEBUG */ 282 283 if (be->tablename != NULL) 284 free(be->tablename); 285 if (be->result != NULL) 286 (void) __ns_ldap_freeResult(&be->result); 287 if (be->enumcookie != NULL) 288 (void) __ns_ldap_endEntry(&be->enumcookie, &error); 289 if (be->services_cookie != NULL) 290 _nss_services_cookie_free((void **)&be->services_cookie); 291 if (be->toglue != NULL) { 292 free(be->toglue); 293 be->toglue = NULL; 294 } 295 if (be->buffer != NULL) { 296 free(be->buffer); 297 be->buffer = NULL; 298 } 299 free(be); 300 } 301 302 303 /* 304 * _nss_ldap_destr will free all smalloc'ed variable strings and structures 305 * before exiting this nsswitch shared backend library. This function is 306 * called before returning control back to nsswitch. 307 */ 308 309 /*ARGSUSED1*/ 310 nss_status_t 311 _nss_ldap_destr(ldap_backend_ptr be, void *a) 312 { 313 314 #ifdef DEBUG 315 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n"); 316 #endif /* DEBUG */ 317 318 (void) _clean_ldap_backend(be); 319 320 return ((nss_status_t)NSS_SUCCESS); 321 } 322 323 324 /* 325 * _nss_ldap_setent called before _nss_ldap_getent. This function is 326 * required by POSIX. 327 */ 328 329 nss_status_t 330 _nss_ldap_setent(ldap_backend_ptr be, void *a) 331 { 332 struct gettablefilter *gtf; 333 334 #ifdef DEBUG 335 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n"); 336 #endif /* DEBUG */ 337 338 if (be->setcalled == 1) 339 (void) _nss_ldap_endent(be, a); 340 be->filter = NULL; 341 for (gtf = gettablefilterent; gtf->tablename != (char *)NULL; gtf++) { 342 if (strcmp(gtf->tablename, be->tablename)) 343 continue; 344 be->filter = (char *)gtf->tablefilter; 345 break; 346 } 347 348 be->setcalled = 1; 349 be->enumcookie = NULL; 350 be->result = NULL; 351 be->services_cookie = NULL; 352 be->buffer = NULL; 353 return ((nss_status_t)NSS_SUCCESS); 354 } 355 356 357 /* 358 * _nss_ldap_endent called after _nss_ldap_getent. This function is 359 * required by POSIX. 360 */ 361 362 /*ARGSUSED1*/ 363 nss_status_t 364 _nss_ldap_endent(ldap_backend_ptr be, void *a) 365 { 366 ns_ldap_error_t *error = NULL; 367 368 #ifdef DEBUG 369 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n"); 370 #endif /* DEBUG */ 371 372 be->setcalled = 0; 373 be->filter = NULL; 374 if (be->enumcookie != NULL) { 375 (void) __ns_ldap_endEntry(&be->enumcookie, &error); 376 (void) __ns_ldap_freeError(&error); 377 } 378 if (be->result != NULL) { 379 (void) __ns_ldap_freeResult(&be->result); 380 } 381 if (be->services_cookie != NULL) { 382 _nss_services_cookie_free((void **)&be->services_cookie); 383 } 384 if (be->buffer != NULL) { 385 free(be->buffer); 386 be->buffer = NULL; 387 } 388 389 return ((nss_status_t)NSS_SUCCESS); 390 } 391 392 393 /* 394 * 395 */ 396 397 nss_status_t 398 _nss_ldap_getent(ldap_backend_ptr be, void *a) 399 { 400 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 401 ns_ldap_error_t *error = NULL; 402 int parsestat = 0; 403 int retcode = 0; 404 405 #ifdef DEBUG 406 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n"); 407 #endif /* DEBUG */ 408 409 if (be->setcalled == 0) 410 (void) _nss_ldap_setent(be, a); 411 412 next_entry: 413 if (be->enumcookie == NULL) { 414 retcode = __ns_ldap_firstEntry(be->tablename, 415 be->filter, _merge_SSD_filter, be->attrs, NULL, 416 0, &be->enumcookie, 417 &be->result, &error, _F_GETENT_SSD); 418 } else { 419 if (be->services_cookie == NULL) { 420 retcode = __ns_ldap_nextEntry(be->enumcookie, 421 &be->result, &error); 422 } 423 } 424 if (retcode != NS_LDAP_SUCCESS) { 425 retcode = switch_err(retcode, error); 426 (void) __ns_ldap_freeError(&error); 427 (void) _nss_ldap_endent(be, a); 428 return (retcode); 429 } else { 430 /* ns_ldap_entry_t -> file format */ 431 if ((parsestat = be->ldapobj2str(be, argp)) 432 == NSS_STR_PARSE_SUCCESS) { 433 if (argp->buf.result != NULL) { 434 /* file format -> struct */ 435 if (argp->str2ent == NULL) { 436 parsestat = NSS_STR_PARSE_PARSE; 437 goto error_out; 438 } 439 parsestat = (*argp->str2ent)(be->buffer, 440 be->buflen, 441 argp->buf.result, 442 argp->buf.buffer, 443 argp->buf.buflen); 444 if (parsestat == NSS_STR_PARSE_SUCCESS) { 445 if (be->buffer != NULL) { 446 free(be->buffer); 447 be->buffer = NULL; 448 be->buflen = 0; 449 } 450 be->result = NULL; 451 argp->returnval = argp->buf.result; 452 argp->returnlen = 1; /* irrevelant */ 453 return ((nss_status_t)NSS_SUCCESS); 454 } 455 } else { 456 /* 457 * nscd is not caching the enumerated 458 * entries. This code path would be dormant. 459 * Keep this path for the future references. 460 */ 461 argp->returnval = argp->buf.buffer; 462 argp->returnlen = 463 strlen(argp->buf.buffer) + 1; 464 } 465 } 466 error_out: 467 if (be->buffer != NULL) { 468 free(be->buffer); 469 be->buffer = NULL; 470 be->buflen = 0; 471 } 472 be->result = NULL; 473 if (parsestat == NSS_STR_PARSE_PARSE) { 474 argp->returnval = 0; 475 (void) _nss_ldap_endent(be, a); 476 return ((nss_status_t)NSS_NOTFOUND); 477 } 478 479 if (parsestat == NSS_STR_PARSE_ERANGE) { 480 argp->erange = 1; 481 (void) _nss_ldap_endent(be, a); 482 return ((nss_status_t)NSS_NOTFOUND); 483 } 484 if (parsestat == NSS_STR_PARSE_NO_ADDR) 485 /* 486 * No IPV4 address is found in the current entry. 487 * It indicates that the entry contains IPV6 addresses 488 * only. Instead of calling _nss_ldap_endent to 489 * terminate, get next entry to continue enumeration. 490 * If it returned NSS_NOTFOUND here, 491 * gethostent() would return NULL 492 * and the enumeration would stop prematurely. 493 */ 494 goto next_entry; 495 } 496 497 return ((nss_status_t)NSS_SUCCESS); 498 } 499 500 501 /* 502 * 503 */ 504 505 nss_backend_t * 506 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename, 507 const char **attrs, fnf ldapobj2str) 508 { 509 ldap_backend_ptr be; 510 511 #ifdef DEBUG 512 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n"); 513 #endif /* DEBUG */ 514 515 if ((be = (ldap_backend_ptr) calloc(1, sizeof (*be))) == 0) 516 return (0); 517 be->ops = ops; 518 be->nops = (nss_dbop_t)nops; 519 be->tablename = (char *)strdup(tablename); 520 be->attrs = attrs; 521 be->ldapobj2str = ldapobj2str; 522 523 return ((nss_backend_t *)be); 524 } 525 526 527 /* 528 * 529 */ 530 int 531 chophostdomain(char *string, char *host, char *domain) 532 { 533 char *dot; 534 535 if (string == NULL) 536 return (-1); 537 538 if ((dot = strchr(string, '.')) == NULL) { 539 return (0); 540 } 541 *dot = '\0'; 542 (void) strcpy(host, string); 543 (void) strcpy(domain, ++dot); 544 545 return (0); 546 } 547 548 549 /* 550 * 551 */ 552 int 553 propersubdomain(char *domain, char *subdomain) 554 { 555 int domainlen, subdomainlen; 556 557 /* sanity check */ 558 if (domain == NULL || subdomain == NULL) 559 return (-1); 560 561 domainlen = strlen(domain); 562 subdomainlen = strlen(subdomain); 563 564 /* is afterdot a substring of domain? */ 565 if ((strncasecmp(domain, subdomain, subdomainlen)) != 0) 566 return (-1); 567 568 if (domainlen == subdomainlen) 569 return (1); 570 571 if (subdomainlen > domainlen) 572 return (-1); 573 574 if (*(domain + subdomainlen) != '.') 575 return (-1); 576 577 return (1); 578 } 579