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