ldap_common.c revision 2830:5228d1267a01
117706Sjulian/* 217706Sjulian * CDDL HEADER START 317706Sjulian * 417706Sjulian * The contents of this file are subject to the terms of the 517706Sjulian * Common Development and Distribution License (the "License"). 617706Sjulian * You may not use this file except in compliance with the License. 717706Sjulian * 817706Sjulian * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 917706Sjulian * or http://www.opensolaris.org/os/licensing. 1017706Sjulian * See the License for the specific language governing permissions 1117706Sjulian * and limitations under the License. 1217706Sjulian * 13165967Simp * When distributing Covered Code, include this CDDL HEADER in each 1417706Sjulian * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1517706Sjulian * If applicable, add the following below this CDDL HEADER, with the 1617706Sjulian * fields enclosed by brackets "[]" replaced with your own identifying 1717706Sjulian * information: Portions Copyright [yyyy] [name of copyright owner] 1817706Sjulian * 1917706Sjulian * CDDL HEADER END 2049439Sdeischen */ 2117706Sjulian/* 2217706Sjulian * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2317706Sjulian * Use is subject to license terms. 2417706Sjulian */ 2517706Sjulian 2617706Sjulian#pragma ident "%Z%%M% %I% %E% SMI" 2717706Sjulian 2817706Sjulian#include "ldap_common.h" 2950476Speter#include <malloc.h> 3017706Sjulian#include <synch.h> 31174112Sdeischen#include <syslog.h> 32174112Sdeischen#include <rpcsvc/ypclnt.h> 3317706Sjulian#include <rpcsvc/yp_prot.h> 3417706Sjulian#include <thread.h> 35174112Sdeischen#include <ctype.h> 36103388Smini#include <stdlib.h> 3717706Sjulian#include <signal.h> 38174112Sdeischen#include <sys/stat.h> 39174112Sdeischen 40174112Sdeischen/* getent attributes filters */ 41117907Sdeischen#define _F_GETALIASENT "(objectClass=rfc822MailGroup)" 4297204Sdeischen#define _F_GETAUTHNAME "(objectClass=SolarisAuthAttr)" 4375369Sdeischen#define _F_GETAUUSERNAME "(objectClass=SolarisAuditUser)" 4497204Sdeischen#define _F_GETEXECNAME "(objectClass=SolarisExecAttr)" 4571581Sdeischen#define _F_GETGRENT "(objectClass=posixGroup)" 46113658Sdeischen#define _F_GETHOSTENT "(objectClass=ipHost)" 4735509Sjb#define _F_GETNETENT "(objectClass=ipNetwork)" 4817706Sjulian#define _F_GETPROFNAME \ 4971581Sdeischen"(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))" 5017706Sjulian#define _F_GETPROTOENT "(objectClass=ipProtocol)" 51113658Sdeischen#define _F_GETPWENT "(objectClass=posixAccount)" 52117907Sdeischen#define _F_GETPRINTERENT "(objectClass=sunPrinter)" 5397204Sdeischen#define _F_GETRPCENT "(objectClass=oncRpc)" 5435509Sjb#define _F_GETSERVENT "(objectClass=ipService)" 55113658Sdeischen#define _F_GETSPENT "(objectclass=shadowAccount)" 56113658Sdeischen#define _F_GETUSERNAME "(objectClass=SolarisUserAttr)" 57114664Sdeischen#define _F_GETPROJENT "(objectClass=SolarisProject)" 58114664Sdeischen#define _F_GETTNRHDB "(objectClass=ipTnetHost)" 59117907Sdeischen#define _F_GETTNRHTP "(&(objectClass=ipTnetTemplate)"\ 60114664Sdeischen "(SolarisAttrKeyValue=*))" 61113658Sdeischen#define _F_GETENT_SSD "(%s)" 62117907Sdeischen 63117907Sdeischenstatic struct gettablefilter { 6497204Sdeischen char *tablename; 6597204Sdeischen char *tablefilter; 6697204Sdeischen} gettablefilterent[] = { 6744963Sjb {(char *)_PASSWD, (char *)_F_GETPWENT}, 6897204Sdeischen {(char *)_SHADOW, (char *)_F_GETSPENT}, 6997204Sdeischen {(char *)_GROUP, (char *)_F_GETGRENT}, 7097204Sdeischen {(char *)_HOSTS, (char *)_F_GETHOSTENT}, 71113658Sdeischen {(char *)_NETWORKS, (char *)_F_GETNETENT}, 72113658Sdeischen {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT}, 73117907Sdeischen {(char *)_RPC, (char *)_F_GETRPCENT}, 74113658Sdeischen {(char *)_ALIASES, (char *)_F_GETALIASENT}, 7597204Sdeischen {(char *)_SERVICES, (char *)_F_GETSERVENT}, 76113658Sdeischen {(char *)_AUUSER, (char *)_F_GETAUUSERNAME}, 77113658Sdeischen {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME}, 78113658Sdeischen {(char *)_EXECATTR, (char *)_F_GETEXECNAME}, 7997204Sdeischen {(char *)_PROFATTR, (char *)_F_GETPROFNAME}, 8097204Sdeischen {(char *)_USERATTR, (char *)_F_GETUSERNAME}, 81114664Sdeischen {(char *)_PROJECT, (char *)_F_GETPROJENT}, 82113658Sdeischen {(char *)_PRINTERS, (char *)_F_GETPRINTERENT}, 83117907Sdeischen {(char *)_TNRHDB, (char *)_F_GETTNRHDB}, 84113658Sdeischen {(char *)_TNRHTP, (char *)_F_GETTNRHTP}, 85117907Sdeischen {(char *)NULL, (char *)NULL} 86117907Sdeischen}; 87113658Sdeischen 8817706Sjulian 8997204Sdeischenstatic nss_status_t 90113658Sdeischenswitch_err(int rc, ns_ldap_error_t *error) 91113658Sdeischen{ 92113658Sdeischen switch (rc) { 9317706Sjulian case NS_LDAP_SUCCESS: 9497204Sdeischen return (NSS_SUCCESS); 95117907Sdeischen 9697204Sdeischen case NS_LDAP_NOTFOUND: 9797204Sdeischen return (NSS_NOTFOUND); 9897204Sdeischen 99113658Sdeischen case NS_LDAP_PARTIAL: 10097204Sdeischen return (NSS_TRYAGAIN); 10197204Sdeischen 10297204Sdeischen case NS_LDAP_INTERNAL: 10397204Sdeischen if (error && (error->status == LDAP_SERVER_DOWN || 10497204Sdeischen error->status == LDAP_TIMEOUT)) 10597204Sdeischen return (NSS_TRYAGAIN); 106113658Sdeischen else 107117907Sdeischen return (NSS_UNAVAIL); 108117907Sdeischen 109117907Sdeischen default: 11097204Sdeischen return (NSS_UNAVAIL); 111 } 112} 113/* ARGSUSED */ 114nss_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 207error_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 */ 237nss_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 274void 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*/ 310nss_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 329nss_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*/ 363nss_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 397nss_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 412next_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 } 466error_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 505nss_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 */ 530int 531chophostdomain(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 */ 552int 553propersubdomain(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