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 "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 "(objectClass=SolarisProfAttr)" 49 #define _F_GETPROTOENT "(objectClass=ipProtocol)" 50 #define _F_GETPWENT "(objectClass=posixAccount)" 51 #define _F_GETPRINTERENT "(objectClass=sunPrinter)" 52 #define _F_GETRPCENT "(objectClass=oncRpc)" 53 #define _F_GETSERVENT "(objectClass=ipService)" 54 #define _F_GETSPENT "(objectclass=shadowAccount)" 55 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)" 56 #define _F_GETPROJENT "(objectClass=SolarisProject)" 57 #define _F_GETTNRHDB "(objectClass=ipTnetHost)" 58 #define _F_GETTNRHTP "(&(objectClass=ipTnetTemplate)"\ 59 "(SolarisAttrKeyValue=*))" 60 #define _F_GETENT_SSD "(%s)" 61 62 static struct gettablefilter { 63 char *tablename; 64 char *tablefilter; 65 } gettablefilterent[] = { 66 {(char *)_PASSWD, (char *)_F_GETPWENT}, 67 {(char *)_SHADOW, (char *)_F_GETSPENT}, 68 {(char *)_GROUP, (char *)_F_GETGRENT}, 69 {(char *)_HOSTS, (char *)_F_GETHOSTENT}, 70 {(char *)_NETWORKS, (char *)_F_GETNETENT}, 71 {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT}, 72 {(char *)_RPC, (char *)_F_GETRPCENT}, 73 {(char *)_ALIASES, (char *)_F_GETALIASENT}, 74 {(char *)_SERVICES, (char *)_F_GETSERVENT}, 75 {(char *)_AUUSER, (char *)_F_GETAUUSERNAME}, 76 {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME}, 77 {(char *)_EXECATTR, (char *)_F_GETEXECNAME}, 78 {(char *)_PROFATTR, (char *)_F_GETPROFNAME}, 79 {(char *)_USERATTR, (char *)_F_GETUSERNAME}, 80 {(char *)_PROJECT, (char *)_F_GETPROJENT}, 81 {(char *)_PRINTERS, (char *)_F_GETPRINTERENT}, 82 {(char *)_TNRHDB, (char *)_F_GETTNRHDB}, 83 {(char *)_TNRHTP, (char *)_F_GETTNRHTP}, 84 {(char *)NULL, (char *)NULL} 85 }; 86 87 88 nss_status_t 89 switch_err(int rc, ns_ldap_error_t *error) 90 { 91 switch (rc) { 92 case NS_LDAP_SUCCESS: 93 return (NSS_SUCCESS); 94 95 case NS_LDAP_NOTFOUND: 96 return (NSS_NOTFOUND); 97 98 case NS_LDAP_PARTIAL: 99 return (NSS_TRYAGAIN); 100 101 case NS_LDAP_INTERNAL: 102 if (error && (error->status == LDAP_SERVER_DOWN || 103 error->status == LDAP_TIMEOUT)) 104 return (NSS_TRYAGAIN); 105 else 106 return (NSS_UNAVAIL); 107 108 default: 109 return (NSS_UNAVAIL); 110 } 111 } 112 nss_status_t 113 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, 114 char *database, char *searchfilter, char *domain, 115 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 116 char **realfilter, const void *userdata), 117 const void *userdata) 118 { 119 int callbackstat = 0; 120 ns_ldap_error_t *error = NULL; 121 int rc; 122 123 #ifdef DEBUG 124 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n"); 125 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter); 126 (void) fprintf(stdout, 127 "\tuserdata: %s\n", userdata ? userdata : "NULL"); 128 (void) fprintf(stdout, "\tdatabase: %s\n", database); 129 #endif /* DEBUG */ 130 131 (void) __ns_ldap_freeResult(&be->result); 132 133 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb, 134 be->attrs, NULL, 0, &be->result, &error, NULL, 135 userdata)) != NS_LDAP_SUCCESS) { 136 argp->returnval = 0; 137 rc = switch_err(rc, error); 138 (void) __ns_ldap_freeError(&error); 139 return (rc); 140 } 141 /* callback function */ 142 if ((callbackstat = 143 be->ldapobj2ent(be, argp)) == NSS_STR_PARSE_SUCCESS) { 144 argp->returnval = argp->buf.result; 145 return ((nss_status_t)NSS_SUCCESS); 146 } 147 (void) __ns_ldap_freeResult(&be->result); 148 149 /* error */ 150 if (callbackstat == NSS_STR_PARSE_PARSE) { 151 argp->returnval = 0; 152 return ((nss_status_t)NSS_NOTFOUND); 153 } 154 if (callbackstat == NSS_STR_PARSE_ERANGE) { 155 argp->erange = 1; 156 return ((nss_status_t)NSS_NOTFOUND); 157 } 158 if (callbackstat == NSS_STR_PARSE_NO_ADDR) { 159 /* No IPV4 address is found */ 160 argp->h_errno = HOST_NOT_FOUND; 161 return ((nss_status_t)NSS_NOTFOUND); 162 } 163 return ((nss_status_t)NSS_UNAVAIL); 164 } 165 166 167 /* 168 * This function is similar to _nss_ldap_lookup except it does not 169 * do a callback. It is only used by getnetgrent.c 170 */ 171 172 nss_status_t 173 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, 174 char *database, char *searchfilter, char *domain, 175 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 176 char **realfilter, const void *userdata), 177 const void *userdata) 178 { 179 ns_ldap_error_t *error = NULL; 180 int rc; 181 182 #ifdef DEBUG 183 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n"); 184 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter); 185 (void) fprintf(stdout, "\tdatabase: %s\n", database); 186 (void) fprintf(stdout, 187 "\tuserdata: %s\n", userdata ? userdata : "NULL"); 188 #endif /* DEBUG */ 189 190 (void) __ns_ldap_freeResult(&be->result); 191 192 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb, 193 be->attrs, NULL, 0, &be->result, &error, NULL, 194 userdata)) != NS_LDAP_SUCCESS) { 195 argp->returnval = 0; 196 rc = switch_err(rc, error); 197 (void) __ns_ldap_freeError(&error); 198 return (rc); 199 } 200 201 return ((nss_status_t)NSS_SUCCESS); 202 } 203 204 205 /* 206 * 207 */ 208 209 void 210 _clean_ldap_backend(ldap_backend_ptr be) 211 { 212 ns_ldap_error_t *error; 213 214 #ifdef DEBUG 215 (void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n"); 216 #endif /* DEBUG */ 217 218 if (be->tablename != NULL) 219 free(be->tablename); 220 if (be->result != NULL) 221 (void) __ns_ldap_freeResult(&be->result); 222 if (be->enumcookie != NULL) 223 (void) __ns_ldap_endEntry(&be->enumcookie, &error); 224 if (be->services_cookie != NULL) 225 _nss_services_cookie_free((void **)&be->services_cookie); 226 if (be->toglue != NULL) { 227 free(be->toglue); 228 be->toglue = NULL; 229 } 230 free(be); 231 } 232 233 234 /* 235 * _nss_ldap_destr will free all smalloc'ed variable strings and structures 236 * before exiting this nsswitch shared backend library. This function is 237 * called before returning control back to nsswitch. 238 */ 239 240 /*ARGSUSED1*/ 241 nss_status_t 242 _nss_ldap_destr(ldap_backend_ptr be, void *a) 243 { 244 245 #ifdef DEBUG 246 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n"); 247 #endif /* DEBUG */ 248 249 (void) _clean_ldap_backend(be); 250 251 return ((nss_status_t)NSS_SUCCESS); 252 } 253 254 255 /* 256 * _nss_ldap_setent called before _nss_ldap_getent. This function is 257 * required by POSIX. 258 */ 259 260 nss_status_t 261 _nss_ldap_setent(ldap_backend_ptr be, void *a) 262 { 263 struct gettablefilter *gtf; 264 265 #ifdef DEBUG 266 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n"); 267 #endif /* DEBUG */ 268 269 if (be->setcalled == 1) 270 (void) _nss_ldap_endent(be, a); 271 be->filter = NULL; 272 for (gtf = gettablefilterent; gtf->tablename != (char *)NULL; gtf++) { 273 if (strcmp(gtf->tablename, be->tablename)) 274 continue; 275 be->filter = (char *)gtf->tablefilter; 276 break; 277 } 278 279 be->setcalled = 1; 280 be->enumcookie = NULL; 281 be->result = NULL; 282 be->services_cookie = NULL; 283 return ((nss_status_t)NSS_SUCCESS); 284 } 285 286 287 /* 288 * _nss_ldap_endent called after _nss_ldap_getent. This function is 289 * required by POSIX. 290 */ 291 292 /*ARGSUSED1*/ 293 nss_status_t 294 _nss_ldap_endent(ldap_backend_ptr be, void *a) 295 { 296 ns_ldap_error_t *error = NULL; 297 298 #ifdef DEBUG 299 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n"); 300 #endif /* DEBUG */ 301 302 be->setcalled = 0; 303 be->filter = NULL; 304 if (be->enumcookie != NULL) { 305 (void) __ns_ldap_endEntry(&be->enumcookie, &error); 306 (void) __ns_ldap_freeError(&error); 307 } 308 if (be->result != NULL) { 309 (void) __ns_ldap_freeResult(&be->result); 310 } 311 if (be->services_cookie != NULL) { 312 _nss_services_cookie_free((void **)&be->services_cookie); 313 } 314 315 return ((nss_status_t)NSS_SUCCESS); 316 } 317 318 319 /* 320 * 321 */ 322 323 nss_status_t 324 _nss_ldap_getent(ldap_backend_ptr be, void *a) 325 { 326 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 327 ns_ldap_error_t *error = NULL; 328 int parsestat = 0; 329 int retcode = 0; 330 331 #ifdef DEBUG 332 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n"); 333 #endif /* DEBUG */ 334 335 if (be->setcalled == 0) 336 (void) _nss_ldap_setent(be, a); 337 338 next_entry: 339 if (be->enumcookie == NULL) { 340 retcode = __ns_ldap_firstEntry(be->tablename, 341 be->filter, _merge_SSD_filter, be->attrs, NULL, 342 0, &be->enumcookie, 343 &be->result, &error, _F_GETENT_SSD); 344 } else { 345 if (be->services_cookie == NULL) { 346 retcode = __ns_ldap_nextEntry(be->enumcookie, 347 &be->result, &error); 348 } 349 } 350 if (retcode != NS_LDAP_SUCCESS) { 351 retcode = switch_err(retcode, error); 352 (void) __ns_ldap_freeError(&error); 353 (void) _nss_ldap_endent(be, a); 354 return (retcode); 355 } else { 356 if ((parsestat = be->ldapobj2ent(be, argp)) 357 == NSS_STR_PARSE_SUCCESS) { 358 be->result = NULL; 359 argp->returnval = argp->buf.result; 360 return ((nss_status_t)NSS_SUCCESS); 361 } 362 be->result = NULL; 363 if (parsestat == NSS_STR_PARSE_PARSE) { 364 argp->returnval = 0; 365 (void) _nss_ldap_endent(be, a); 366 return ((nss_status_t)NSS_NOTFOUND); 367 } 368 369 if (parsestat == NSS_STR_PARSE_ERANGE) { 370 argp->erange = 1; 371 (void) _nss_ldap_endent(be, a); 372 return ((nss_status_t)NSS_NOTFOUND); 373 } 374 if (parsestat == NSS_STR_PARSE_NO_ADDR) 375 /* 376 * No IPV4 address is found in the current entry. 377 * It indicates that the entry contains IPV6 addresses 378 * only. Instead of calling _nss_ldap_endent to 379 * terminate, get next entry to continue enumeration. 380 * If it returned NSS_NOTFOUND here, 381 * gethostent() would return NULL 382 * and the enumeration would stop prematurely. 383 */ 384 goto next_entry; 385 } 386 387 return ((nss_status_t)NSS_SUCCESS); 388 } 389 390 391 /* 392 * 393 */ 394 395 nss_backend_t * 396 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename, 397 const char **attrs, fnf ldapobj2ent) 398 { 399 ldap_backend_ptr be; 400 401 #ifdef DEBUG 402 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n"); 403 #endif /* DEBUG */ 404 405 if ((be = (ldap_backend_ptr) malloc(sizeof (*be))) == 0) 406 return (0); 407 be->ops = ops; 408 be->nops = (nss_dbop_t)nops; 409 be->tablename = (char *)strdup(tablename); 410 be->attrs = attrs; 411 be->result = NULL; 412 be->ldapobj2ent = ldapobj2ent; 413 be->setcalled = 0; 414 be->filter = NULL; 415 be->enumcookie = NULL; 416 be->netgroup_cookie = NULL; 417 be->services_cookie = NULL; 418 be->toglue = NULL; 419 420 return ((nss_backend_t *)be); 421 } 422 423 424 /* 425 * 426 */ 427 int 428 chophostdomain(char *string, char *host, char *domain) 429 { 430 char *dot; 431 432 if (string == NULL) 433 return (-1); 434 435 if ((dot = strchr(string, '.')) == NULL) { 436 return (0); 437 } 438 *dot = '\0'; 439 strcpy(host, string); 440 strcpy(domain, ++dot); 441 442 return (0); 443 } 444 445 446 /* 447 * 448 */ 449 int 450 propersubdomain(char *domain, char *subdomain) 451 { 452 int domainlen, subdomainlen; 453 454 /* sanity check */ 455 if (domain == NULL || subdomain == NULL) 456 return (-1); 457 458 domainlen = strlen(domain); 459 subdomainlen = strlen(subdomain); 460 461 /* is afterdot a substring of domain? */ 462 if ((strncasecmp(domain, subdomain, subdomainlen)) != 0) 463 return (-1); 464 465 if (domainlen == subdomainlen) 466 return (1); 467 468 if (subdomainlen > domainlen) 469 return (-1); 470 471 if (*(domain + subdomainlen) != '.') 472 return (-1); 473 474 return (1); 475 } 476