1e1dd0a2fSth /* 2e1dd0a2fSth * CDDL HEADER START 3e1dd0a2fSth * 4e1dd0a2fSth * The contents of this file are subject to the terms of the 5e1dd0a2fSth * Common Development and Distribution License (the "License"). 6e1dd0a2fSth * You may not use this file except in compliance with the License. 7e1dd0a2fSth * 8e1dd0a2fSth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9e1dd0a2fSth * or http://www.opensolaris.org/os/licensing. 10e1dd0a2fSth * See the License for the specific language governing permissions 11e1dd0a2fSth * and limitations under the License. 12e1dd0a2fSth * 13e1dd0a2fSth * When distributing Covered Code, include this CDDL HEADER in each 14e1dd0a2fSth * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15e1dd0a2fSth * If applicable, add the following below this CDDL HEADER, with the 16e1dd0a2fSth * fields enclosed by brackets "[]" replaced with your own identifying 17e1dd0a2fSth * information: Portions Copyright [yyyy] [name of copyright owner] 18e1dd0a2fSth * 19e1dd0a2fSth * CDDL HEADER END 20e1dd0a2fSth */ 21e1dd0a2fSth /* 22*434c5a06SMilan Jurik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23e1dd0a2fSth * Use is subject to license terms. 24e1dd0a2fSth */ 25e1dd0a2fSth 26e1dd0a2fSth #define __STANDALONE_MODULE__ 27e1dd0a2fSth 28e1dd0a2fSth #include <stdio.h> 29e1dd0a2fSth #include <sys/types.h> 30e1dd0a2fSth #include <stdlib.h> 31e1dd0a2fSth #include <libintl.h> 32e1dd0a2fSth #include <string.h> 33e1dd0a2fSth #include <ctype.h> 34e1dd0a2fSth 35e1dd0a2fSth #include <sys/stat.h> 36e1dd0a2fSth #include <fcntl.h> 37e1dd0a2fSth #include <unistd.h> 38e1dd0a2fSth #include <syslog.h> 39e1dd0a2fSth #include <locale.h> 40e1dd0a2fSth #include <errno.h> 41e1dd0a2fSth #include <sys/time.h> 42e1dd0a2fSth 43e1dd0a2fSth #include <arpa/inet.h> 44e1dd0a2fSth #include <netdb.h> 45e1dd0a2fSth #include <strings.h> 46e1dd0a2fSth 47e1dd0a2fSth #include <thread.h> 48e1dd0a2fSth 49e1dd0a2fSth #include <nsswitch.h> 50e1dd0a2fSth #include <nss_dbdefs.h> 51e1dd0a2fSth #include <nss.h> 52e1dd0a2fSth 53e1dd0a2fSth #include "ns_cache_door.h" 54e1dd0a2fSth #include "ns_internal.h" 55ca190d8dSmichen #include "ns_connmgmt.h" 56e1dd0a2fSth 57e1dd0a2fSth typedef enum { 58e1dd0a2fSth INFO_SERVER_JUST_INITED = -1, 59e1dd0a2fSth INFO_SERVER_UNKNOWN = 0, 60e1dd0a2fSth INFO_SERVER_CONNECTING = 1, 61e1dd0a2fSth INFO_SERVER_UP = 2, 62e1dd0a2fSth INFO_SERVER_ERROR = 3, 63e1dd0a2fSth INFO_SERVER_REMOVED = 4 64e1dd0a2fSth } dir_server_status_t; 65e1dd0a2fSth 66e1dd0a2fSth typedef enum { 67e1dd0a2fSth INFO_STATUS_NEW = 2, 68e1dd0a2fSth INFO_STATUS_OLD = 3 69e1dd0a2fSth } dir_server_info_t; 70e1dd0a2fSth 71e1dd0a2fSth typedef struct dir_server { 72e1dd0a2fSth char *ip; 73e1dd0a2fSth char **controls; 74e1dd0a2fSth char **saslMech; 75e1dd0a2fSth dir_server_status_t status; 76e1dd0a2fSth mutex_t updateStatus; 77e1dd0a2fSth dir_server_info_t info; 78e1dd0a2fSth } dir_server_t; 79e1dd0a2fSth 80e1dd0a2fSth typedef struct dir_server_list { 81e1dd0a2fSth dir_server_t **nsServers; 82e1dd0a2fSth 83e1dd0a2fSth rwlock_t listDestroyLock; 84e1dd0a2fSth } dir_server_list_t; 85e1dd0a2fSth 86e1dd0a2fSth struct { 87e1dd0a2fSth /* The local list of the directory servers' root DSEs. */ 88e1dd0a2fSth dir_server_list_t *list; 89e1dd0a2fSth /* The flag indicating if libsldap is in the 'Standalone' mode. */ 90e1dd0a2fSth int standalone; 91e1dd0a2fSth /* 92e1dd0a2fSth * The mutex ensuring that only one thread performs 93e1dd0a2fSth * the initialization of the list. 94e1dd0a2fSth */ 95e1dd0a2fSth mutex_t listReplaceLock; 96e1dd0a2fSth /* 97e1dd0a2fSth * A flag indicating that a particular thread is 98e1dd0a2fSth * in the 'ldap_cachemgr' mode. It is stored by thread as 99e1dd0a2fSth * a thread specific data. 100e1dd0a2fSth */ 101e1dd0a2fSth const int initFlag; 102e1dd0a2fSth /* 103e1dd0a2fSth * A thread specific key storing 104e1dd0a2fSth * the the 'ldap_cachemgr' mode indicator. 105e1dd0a2fSth */ 106e1dd0a2fSth thread_key_t standaloneInitKey; 107e1dd0a2fSth } dir_servers = {NULL, 0, DEFAULTMUTEX, '1'}; 108e1dd0a2fSth 109e1dd0a2fSth typedef struct switchDatabase { 110e1dd0a2fSth char *conf; 111e1dd0a2fSth uint32_t alloced; 112e1dd0a2fSth } switch_database_t; 113e1dd0a2fSth 114e1dd0a2fSth static thread_key_t switchConfigKey; 115e1dd0a2fSth 116e1dd0a2fSth #pragma init(createStandaloneKey) 117e1dd0a2fSth 118e1dd0a2fSth #define DONT_INCLUDE_ATTR_NAMES 0 119e1dd0a2fSth #define INCLUDE_ATTR_NAMES 1 120e1dd0a2fSth #define IS_PROFILE 1 121e1dd0a2fSth #define NOT_PROFILE 0 122e1dd0a2fSth /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */ 123e1dd0a2fSth #define MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12) 124e1dd0a2fSth 125e1dd0a2fSth static 126e1dd0a2fSth void 127e1dd0a2fSth switch_conf_disposer(void *data) 128e1dd0a2fSth { 129e1dd0a2fSth switch_database_t *localData = (switch_database_t *)data; 130e1dd0a2fSth 131e1dd0a2fSth free(localData->conf); 132e1dd0a2fSth free(localData); 133e1dd0a2fSth } 134e1dd0a2fSth 135e1dd0a2fSth /* 136e1dd0a2fSth * This function initializes an indication that a thread obtaining a root DSE 137e1dd0a2fSth * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap 138e1dd0a2fSth * will not invoke the __s_api_requestServer function. Instead, the library 139e1dd0a2fSth * will establish a connection to the server specified by 140e1dd0a2fSth * the __ns_ldap_getRootDSE function. 141e1dd0a2fSth * Since ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time 142e1dd0a2fSth * and we do not want to affect a thread obtaining a DUAProfile, 143e1dd0a2fSth * the 'ldap_cachemgr' mode is thread private. 144e1dd0a2fSth * In addition, this function creates a key holding temporary configuration 145e1dd0a2fSth * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB" 146e1dd0a2fSth * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()). 147e1dd0a2fSth */ 148e1dd0a2fSth static 149e1dd0a2fSth void 150e1dd0a2fSth createStandaloneKey() 151e1dd0a2fSth { 152e1dd0a2fSth if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) { 153e1dd0a2fSth syslog(LOG_ERR, gettext("libsldap: unable to create a thread " 154e1dd0a2fSth "key needed for sharing ldap connections")); 155e1dd0a2fSth } 156e1dd0a2fSth if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) { 157e1dd0a2fSth syslog(LOG_ERR, gettext("libsldap: unable to create a thread " 158e1dd0a2fSth "key containing current nsswitch configuration")); 159e1dd0a2fSth } 160e1dd0a2fSth } 161e1dd0a2fSth 162e1dd0a2fSth /* 163e1dd0a2fSth * This function sets the 'ldap_cachemgr' mode indication. 164e1dd0a2fSth */ 165e1dd0a2fSth void 166e1dd0a2fSth __s_api_setInitMode() 167e1dd0a2fSth { 168e1dd0a2fSth (void) thr_setspecific(dir_servers.standaloneInitKey, 169e1dd0a2fSth (void *) &dir_servers.initFlag); 170e1dd0a2fSth } 171e1dd0a2fSth 172e1dd0a2fSth /* 173e1dd0a2fSth * This function unset the 'ldap_cachemgr' mode indication. 174e1dd0a2fSth */ 175e1dd0a2fSth void 176e1dd0a2fSth __s_api_unsetInitMode() 177e1dd0a2fSth { 178e1dd0a2fSth (void) thr_setspecific(dir_servers.standaloneInitKey, NULL); 179e1dd0a2fSth } 180e1dd0a2fSth 181e1dd0a2fSth /* 182e1dd0a2fSth * This function checks if the 'ldap_cachemgr' mode indication is set. 183e1dd0a2fSth */ 184e1dd0a2fSth int 185e1dd0a2fSth __s_api_isInitializing() { 186e1dd0a2fSth int *flag = NULL; 187e1dd0a2fSth 188e1dd0a2fSth (void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag); 189e1dd0a2fSth 190e1dd0a2fSth return (flag != NULL && *flag == dir_servers.initFlag); 191e1dd0a2fSth } 192e1dd0a2fSth 193e1dd0a2fSth /* 194e1dd0a2fSth * This function checks if the process runs in the 'Standalone' mode. 195e1dd0a2fSth * In this mode libsldap will check the local, process private list of root DSEs 196e1dd0a2fSth * instead of requesting them via a door call to ldap_cachemgr. 197e1dd0a2fSth */ 198e1dd0a2fSth int 199e1dd0a2fSth __s_api_isStandalone() 200e1dd0a2fSth { 201e1dd0a2fSth int mode; 202e1dd0a2fSth 203e1dd0a2fSth (void) mutex_lock(&dir_servers.listReplaceLock); 204e1dd0a2fSth mode = dir_servers.standalone; 205e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 206e1dd0a2fSth 207e1dd0a2fSth return (mode); 208e1dd0a2fSth } 209e1dd0a2fSth 210e1dd0a2fSth 211e1dd0a2fSth static 212e1dd0a2fSth int 213e1dd0a2fSth remove_ldap(char *dst, char *src, int dst_buf_len) 214e1dd0a2fSth { 215e1dd0a2fSth int i = 0; 216e1dd0a2fSth 217e1dd0a2fSth if (strlen(src) >= dst_buf_len) 218e1dd0a2fSth return (0); 219e1dd0a2fSth 220e1dd0a2fSth while (*src != '\0') { 221e1dd0a2fSth /* Copy up to one space from source. */ 222e1dd0a2fSth if (isspace(*src)) { 223e1dd0a2fSth dst[i++] = *src; 224e1dd0a2fSth while (isspace(*src)) 225e1dd0a2fSth src++; 226e1dd0a2fSth } 227e1dd0a2fSth 228e1dd0a2fSth /* If not "ldap", just copy. */ 229e1dd0a2fSth if (strncmp(src, "ldap", 4) != 0) { 230e1dd0a2fSth while (!isspace(*src)) { 231e1dd0a2fSth dst[i++] = *src++; 232e1dd0a2fSth /* At the end of string? */ 233e1dd0a2fSth if (dst[i-1] == '\0') 234e1dd0a2fSth return (1); 235e1dd0a2fSth } 236e1dd0a2fSth /* Copy up to one space from source. */ 237e1dd0a2fSth if (isspace(*src)) { 238e1dd0a2fSth dst[i++] = *src; 239e1dd0a2fSth while (isspace(*src)) 240e1dd0a2fSth src++; 241e1dd0a2fSth } 242e1dd0a2fSth /* Copy also the criteria section */ 243e1dd0a2fSth if (*src == '[') 244e1dd0a2fSth while (*src != ']') { 245e1dd0a2fSth dst[i++] = *src++; 246e1dd0a2fSth /* Shouln't happen if format is right */ 247e1dd0a2fSth if (dst[i-1] == '\0') 248e1dd0a2fSth return (1); 249e1dd0a2fSth } 250e1dd0a2fSth } 251e1dd0a2fSth 252e1dd0a2fSth /* If next part is ldap, skip over it ... */ 253e1dd0a2fSth if (strncmp(src, "ldap", 4) == 0) { 254e1dd0a2fSth if (isspace(*(src+4)) || *(src+4) == '\0') { 255e1dd0a2fSth src += 4; 256e1dd0a2fSth while (isspace(*src)) 257e1dd0a2fSth src++; 258e1dd0a2fSth if (*src == '[') { 259e1dd0a2fSth while (*src++ != ']') { 260e1dd0a2fSth /* 261e1dd0a2fSth * See comment above about 262e1dd0a2fSth * correct format. 263e1dd0a2fSth */ 264e1dd0a2fSth if (*src == '\0') { 265e1dd0a2fSth dst[i++] = '\0'; 266e1dd0a2fSth return (1); 267e1dd0a2fSth } 268e1dd0a2fSth } 269e1dd0a2fSth } 270e1dd0a2fSth while (isspace(*src)) 271e1dd0a2fSth src++; 272e1dd0a2fSth } 273e1dd0a2fSth } 274e1dd0a2fSth if (*src == '\0') 275e1dd0a2fSth dst[i++] = '\0'; 276e1dd0a2fSth } 277e1dd0a2fSth 278e1dd0a2fSth return (1); 279e1dd0a2fSth } 280e1dd0a2fSth 281e1dd0a2fSth static 282e1dd0a2fSth char * 283e1dd0a2fSth get_db(const char *db_name) 284e1dd0a2fSth { 285e1dd0a2fSth char *ptr; 286e1dd0a2fSth switch_database_t *hostService = NULL; 287e1dd0a2fSth FILE *fp = fopen(__NSW_CONFIG_FILE, "rF"); 288e1dd0a2fSth char *linep, line[NSS_BUFSIZ]; 289e1dd0a2fSth 290e1dd0a2fSth if (fp == NULL) { 291e1dd0a2fSth syslog(LOG_WARNING, gettext("libsldap: can not read %s"), 292e1dd0a2fSth __NSW_CONFIG_FILE); 293e1dd0a2fSth return (NULL); 294e1dd0a2fSth } 295e1dd0a2fSth 296e1dd0a2fSth while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) { 297e1dd0a2fSth while (isspace(*linep)) { 298e1dd0a2fSth ++linep; 299e1dd0a2fSth } 300e1dd0a2fSth if (*linep == '#') { 301e1dd0a2fSth continue; 302e1dd0a2fSth } 303e1dd0a2fSth if (strncmp(linep, db_name, strlen(db_name)) != 0) { 304e1dd0a2fSth continue; 305e1dd0a2fSth } 306e1dd0a2fSth if ((linep = strchr(linep, ':')) != NULL) { 307e1dd0a2fSth if (linep[strlen(linep) - 1] == '\n') { 308e1dd0a2fSth linep[strlen(linep) - 1] = '\0'; 309e1dd0a2fSth } 310e1dd0a2fSth 311e1dd0a2fSth while (isspace(*++linep)) 312e1dd0a2fSth ; 313e1dd0a2fSth 314e1dd0a2fSth if ((ptr = strchr(linep, '#')) != NULL) { 315e1dd0a2fSth while (--ptr >= linep && isspace(*ptr)) 316e1dd0a2fSth ; 317e1dd0a2fSth *(ptr + 1) = '\0'; 318e1dd0a2fSth } 319e1dd0a2fSth 320e1dd0a2fSth if (strlen(linep) == 0) { 321e1dd0a2fSth continue; 322e1dd0a2fSth } 323e1dd0a2fSth break; 324e1dd0a2fSth } 325e1dd0a2fSth } 326e1dd0a2fSth 327e1dd0a2fSth (void) fclose(fp); 328e1dd0a2fSth 329e1dd0a2fSth if (linep == NULL) { 330e1dd0a2fSth syslog(LOG_WARNING, 331e1dd0a2fSth gettext("libsldap: the %s database " 332e1dd0a2fSth "is missing from %s"), 333e1dd0a2fSth db_name, 334e1dd0a2fSth __NSW_CONFIG_FILE); 335e1dd0a2fSth return (NULL); 336e1dd0a2fSth } 337e1dd0a2fSth 338e1dd0a2fSth (void) thr_getspecific(switchConfigKey, (void **) &hostService); 339e1dd0a2fSth if (hostService == NULL) { 340e1dd0a2fSth hostService = calloc(1, sizeof (switch_database_t)); 341e1dd0a2fSth if (hostService == NULL) { 342e1dd0a2fSth return (NULL); 343e1dd0a2fSth } 344e1dd0a2fSth (void) thr_setspecific(switchConfigKey, hostService); 345e1dd0a2fSth } 346e1dd0a2fSth 347e1dd0a2fSth /* 348e1dd0a2fSth * In a long-living process threads can perform several 349e1dd0a2fSth * getXbyY requests. And the windows between those requests 350e1dd0a2fSth * can be long. The nsswitch configuration can change from time 351e1dd0a2fSth * to time. So instead of allocating/freeing memory every time 352e1dd0a2fSth * the API is called, reallocate memory only when the current 353e1dd0a2fSth * configuration for the database being used is longer than 354e1dd0a2fSth * the previous one. 355e1dd0a2fSth */ 356e1dd0a2fSth if (strlen(linep) >= hostService->alloced) { 357e1dd0a2fSth ptr = (char *)realloc((void *)hostService->conf, 358e1dd0a2fSth strlen(linep) + 1); 359e1dd0a2fSth if (ptr == NULL) { 360e1dd0a2fSth free((void *)hostService->conf); 361e1dd0a2fSth hostService->conf = NULL; 362e1dd0a2fSth hostService->alloced = 0; 363e1dd0a2fSth return (NULL); 364e1dd0a2fSth } 365e1dd0a2fSth bzero(ptr, strlen(linep) + 1); 366e1dd0a2fSth hostService->conf = ptr; 367e1dd0a2fSth hostService->alloced = strlen(linep) + 1; 368e1dd0a2fSth } 369e1dd0a2fSth 370e1dd0a2fSth if (remove_ldap(hostService->conf, linep, hostService->alloced)) 371e1dd0a2fSth return (hostService->conf); 372e1dd0a2fSth else 373e1dd0a2fSth return (NULL); 374e1dd0a2fSth } 375e1dd0a2fSth 376e1dd0a2fSth static 377e1dd0a2fSth void 378e1dd0a2fSth _initf_ipnodes(nss_db_params_t *p) 379e1dd0a2fSth { 380e1dd0a2fSth char *services = get_db("ipnodes"); 381e1dd0a2fSth 382e1dd0a2fSth p->name = NSS_DBNAM_IPNODES; 383e1dd0a2fSth p->flags |= NSS_USE_DEFAULT_CONFIG; 384e1dd0a2fSth p->default_config = services == NULL ? "" : services; 385e1dd0a2fSth } 386e1dd0a2fSth 387e1dd0a2fSth static 388e1dd0a2fSth void 389e1dd0a2fSth _initf_hosts(nss_db_params_t *p) 390e1dd0a2fSth { 391e1dd0a2fSth char *services = get_db("hosts"); 392e1dd0a2fSth 393e1dd0a2fSth p->name = NSS_DBNAM_HOSTS; 394e1dd0a2fSth p->flags |= NSS_USE_DEFAULT_CONFIG; 395e1dd0a2fSth p->default_config = services == NULL ? "" : services; 396e1dd0a2fSth } 397e1dd0a2fSth 398e1dd0a2fSth /* 399e1dd0a2fSth * This function is an analog of the standard gethostbyaddr_r() 400e1dd0a2fSth * function with an exception that it removes the 'ldap' back-end 401e1dd0a2fSth * (if any) from the host/ipnodes nsswitch's databases and then 402e1dd0a2fSth * looks up using remaining back-ends. 403e1dd0a2fSth */ 404e1dd0a2fSth static 405e1dd0a2fSth struct hostent * 406e1dd0a2fSth _filter_gethostbyaddr_r(const char *addr, int len, int type, 407e1dd0a2fSth struct hostent *result, char *buffer, int buflen, 408e1dd0a2fSth int *h_errnop) 409e1dd0a2fSth { 410e1dd0a2fSth DEFINE_NSS_DB_ROOT(db_root_hosts); 411e1dd0a2fSth DEFINE_NSS_DB_ROOT(db_root_ipnodes); 412e1dd0a2fSth nss_XbyY_args_t arg; 413e1dd0a2fSth nss_status_t res; 414e1dd0a2fSth int (*str2ent)(); 415e1dd0a2fSth void (*nss_initf)(); 416e1dd0a2fSth nss_db_root_t *nss_db_root; 417e1dd0a2fSth int dbop; 418e1dd0a2fSth 419e1dd0a2fSth switch (type) { 420e1dd0a2fSth case AF_INET: 421e1dd0a2fSth str2ent = str2hostent; 422e1dd0a2fSth nss_initf = _initf_hosts; 423e1dd0a2fSth nss_db_root = &db_root_hosts; 424e1dd0a2fSth dbop = NSS_DBOP_HOSTS_BYADDR; 425e1dd0a2fSth break; 426e1dd0a2fSth case AF_INET6: 427e1dd0a2fSth str2ent = str2hostent6; 428e1dd0a2fSth nss_initf = _initf_ipnodes; 429e1dd0a2fSth nss_db_root = &db_root_ipnodes; 430e1dd0a2fSth dbop = NSS_DBOP_IPNODES_BYADDR; 431e1dd0a2fSth default: 432e1dd0a2fSth return (NULL); 433e1dd0a2fSth } 434e1dd0a2fSth 435e1dd0a2fSth NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent); 436e1dd0a2fSth 437e1dd0a2fSth arg.key.hostaddr.addr = addr; 438e1dd0a2fSth arg.key.hostaddr.len = len; 439e1dd0a2fSth arg.key.hostaddr.type = type; 440e1dd0a2fSth arg.stayopen = 0; 441e1dd0a2fSth arg.h_errno = NETDB_SUCCESS; 442e1dd0a2fSth 443e1dd0a2fSth res = nss_search(nss_db_root, nss_initf, dbop, &arg); 444e1dd0a2fSth arg.status = res; 445e1dd0a2fSth *h_errnop = arg.h_errno; 446e1dd0a2fSth return (struct hostent *)NSS_XbyY_FINI(&arg); 447e1dd0a2fSth } 448e1dd0a2fSth 449e1dd0a2fSth /* 450e1dd0a2fSth * This routine is an analog of gethostbyaddr_r(). 451e1dd0a2fSth * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity 452e1dd0a2fSth * prior to querying the name services. 453e1dd0a2fSth * If the buffer is not big enough to accommodate a returning data, 454e1dd0a2fSth * NULL is returned and h_errnop is set to TRY_AGAIN. 455e1dd0a2fSth */ 456e1dd0a2fSth struct hostent * 457e1dd0a2fSth __s_api_hostname2ip(const char *name, 458e1dd0a2fSth struct hostent *result, char *buffer, int buflen, 459e1dd0a2fSth int *h_errnop) 460e1dd0a2fSth { 461e1dd0a2fSth DEFINE_NSS_DB_ROOT(db_root_ipnodes); 462e1dd0a2fSth DEFINE_NSS_DB_ROOT(db_root_hosts); 463e1dd0a2fSth nss_XbyY_args_t arg; 464e1dd0a2fSth nss_status_t res; 465e1dd0a2fSth struct in_addr addr; 466e1dd0a2fSth struct in6_addr addr6; 467e1dd0a2fSth 468e1dd0a2fSth if (inet_pton(AF_INET, name, &addr) > 0) { 469e1dd0a2fSth if (buflen < strlen(name) + 1 + 470e1dd0a2fSth sizeof (char *) * 2 + /* The h_aliases member */ 471e1dd0a2fSth sizeof (struct in_addr) + 472e1dd0a2fSth sizeof (struct in_addr *) * 2) { 473e1dd0a2fSth *h_errnop = TRY_AGAIN; 474e1dd0a2fSth return (NULL); 475e1dd0a2fSth } 476e1dd0a2fSth 477e1dd0a2fSth result->h_addrtype = AF_INET; 478e1dd0a2fSth result->h_length = sizeof (struct in_addr); 479e1dd0a2fSth (void) strncpy(buffer, name, buflen); 480e1dd0a2fSth 481e1dd0a2fSth result->h_addr_list = (char **)ROUND_UP( 482e1dd0a2fSth buffer + strlen(name) + 1, 483e1dd0a2fSth sizeof (char *)); 484e1dd0a2fSth result->h_aliases = (char **)ROUND_UP(result->h_addr_list, 485e1dd0a2fSth sizeof (char *)); 486e1dd0a2fSth result->h_aliases[0] = buffer; 487e1dd0a2fSth result->h_aliases[1] = NULL; 488e1dd0a2fSth bcopy(&addr, 489e1dd0a2fSth buffer + buflen - sizeof (struct in_addr), 490e1dd0a2fSth sizeof (struct in_addr)); 491e1dd0a2fSth result->h_addr_list[0] = buffer + buflen - 492e1dd0a2fSth sizeof (struct in_addr); 493e1dd0a2fSth result->h_addr_list[1] = NULL; 494e1dd0a2fSth result->h_aliases = result->h_addr_list; 495e1dd0a2fSth result->h_name = buffer; 496e1dd0a2fSth 497e1dd0a2fSth *h_errnop = NETDB_SUCCESS; 498e1dd0a2fSth return (result); 499e1dd0a2fSth } 500e1dd0a2fSth if (inet_pton(AF_INET6, name, &addr6) > 0) { 501e1dd0a2fSth if (buflen < strlen(name) + 1 + 502e1dd0a2fSth sizeof (char *) * 2 + /* The h_aliases member */ 503e1dd0a2fSth sizeof (struct in6_addr) + 504e1dd0a2fSth sizeof (struct in6_addr *) * 2) { 505e1dd0a2fSth *h_errnop = TRY_AGAIN; 506e1dd0a2fSth return (NULL); 507e1dd0a2fSth } 508e1dd0a2fSth 509e1dd0a2fSth result->h_addrtype = AF_INET6; 510e1dd0a2fSth result->h_length = sizeof (struct in6_addr); 511e1dd0a2fSth (void) strncpy(buffer, name, buflen); 512e1dd0a2fSth 513e1dd0a2fSth result->h_addr_list = (char **)ROUND_UP( 514e1dd0a2fSth buffer + strlen(name) + 1, 515e1dd0a2fSth sizeof (char *)); 516e1dd0a2fSth result->h_aliases = (char **)ROUND_UP(result->h_addr_list, 517e1dd0a2fSth sizeof (char *)); 518e1dd0a2fSth result->h_aliases[0] = buffer; 519e1dd0a2fSth result->h_aliases[1] = NULL; 520e1dd0a2fSth bcopy(&addr6, 521e1dd0a2fSth buffer + buflen - sizeof (struct in6_addr), 522e1dd0a2fSth sizeof (struct in6_addr)); 523e1dd0a2fSth result->h_addr_list[0] = buffer + buflen - 524e1dd0a2fSth sizeof (struct in6_addr); 525e1dd0a2fSth result->h_addr_list[1] = NULL; 526e1dd0a2fSth result->h_aliases = result->h_addr_list; 527e1dd0a2fSth result->h_name = buffer; 528e1dd0a2fSth 529e1dd0a2fSth *h_errnop = NETDB_SUCCESS; 530e1dd0a2fSth return (result); 531e1dd0a2fSth } 532e1dd0a2fSth 533e1dd0a2fSth NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 534e1dd0a2fSth 535e1dd0a2fSth arg.key.name = name; 536e1dd0a2fSth arg.stayopen = 0; 537e1dd0a2fSth arg.h_errno = NETDB_SUCCESS; 538e1dd0a2fSth 539e1dd0a2fSth res = nss_search(&db_root_ipnodes, _initf_ipnodes, 540e1dd0a2fSth NSS_DBOP_IPNODES_BYNAME, &arg); 541e1dd0a2fSth if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) { 542e1dd0a2fSth arg.h_errno = NETDB_SUCCESS; 543e1dd0a2fSth res = nss_search(&db_root_hosts, _initf_hosts, 544e1dd0a2fSth NSS_DBOP_HOSTS_BYNAME, &arg); 545e1dd0a2fSth } 546e1dd0a2fSth arg.status = res; 547e1dd0a2fSth *h_errnop = arg.h_errno; 548e1dd0a2fSth return ((struct hostent *)NSS_XbyY_FINI(&arg)); 549e1dd0a2fSth } 550e1dd0a2fSth 551e1dd0a2fSth /* 552e1dd0a2fSth * Convert an IP to a host name. 553e1dd0a2fSth */ 554e1dd0a2fSth ns_ldap_return_code 555e1dd0a2fSth __s_api_ip2hostname(char *ipaddr, char **hostname) { 556e1dd0a2fSth struct in_addr in; 557e1dd0a2fSth struct in6_addr in6; 558e1dd0a2fSth struct hostent *hp = NULL, hostEnt; 559e1dd0a2fSth char buffer[NSS_BUFLEN_HOSTS]; 560e1dd0a2fSth int buflen = NSS_BUFLEN_HOSTS; 561e1dd0a2fSth char *start = NULL, 562e1dd0a2fSth *end = NULL, 563e1dd0a2fSth delim = '\0'; 564e1dd0a2fSth char *port = NULL, 565e1dd0a2fSth *addr = NULL; 566e1dd0a2fSth int errorNum = 0, 567e1dd0a2fSth len = 0; 568e1dd0a2fSth 569e1dd0a2fSth if (ipaddr == NULL || hostname == NULL) 570e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 571e1dd0a2fSth *hostname = NULL; 572e1dd0a2fSth if ((addr = strdup(ipaddr)) == NULL) 573e1dd0a2fSth return (NS_LDAP_MEMORY); 574e1dd0a2fSth 575e1dd0a2fSth if (addr[0] == '[') { 576e1dd0a2fSth /* 577e1dd0a2fSth * Assume it's [ipv6]:port 578e1dd0a2fSth * Extract ipv6 IP 579e1dd0a2fSth */ 580e1dd0a2fSth start = &addr[1]; 581e1dd0a2fSth if ((end = strchr(addr, ']')) != NULL) { 582e1dd0a2fSth *end = '\0'; 583e1dd0a2fSth delim = ']'; 584e1dd0a2fSth if (*(end + 1) == ':') 585e1dd0a2fSth /* extract port */ 586e1dd0a2fSth port = end + 2; 587e1dd0a2fSth } else { 588e1dd0a2fSth free(addr); 589e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 590e1dd0a2fSth } 591e1dd0a2fSth } else if ((end = strchr(addr, ':')) != NULL) { 592e1dd0a2fSth /* assume it's ipv4:port */ 593e1dd0a2fSth *end = '\0'; 594e1dd0a2fSth delim = ':'; 595e1dd0a2fSth start = addr; 596e1dd0a2fSth port = end + 1; 597e1dd0a2fSth } else 598e1dd0a2fSth /* No port */ 599e1dd0a2fSth start = addr; 600e1dd0a2fSth 601e1dd0a2fSth 602e1dd0a2fSth if (inet_pton(AF_INET, start, &in) == 1) { 603e1dd0a2fSth /* IPv4 */ 604e1dd0a2fSth hp = _filter_gethostbyaddr_r((char *)&in, 605e1dd0a2fSth sizeof (in.s_addr), 606e1dd0a2fSth AF_INET, 607e1dd0a2fSth &hostEnt, 608e1dd0a2fSth buffer, 609e1dd0a2fSth buflen, 610e1dd0a2fSth &errorNum); 611e1dd0a2fSth if (hp && hp->h_name) { 612e1dd0a2fSth /* hostname + '\0' */ 613e1dd0a2fSth len = strlen(hp->h_name) + 1; 614e1dd0a2fSth if (port) 615e1dd0a2fSth /* ':' + port */ 616e1dd0a2fSth len += strlen(port) + 1; 617e1dd0a2fSth if ((*hostname = malloc(len)) == NULL) { 618e1dd0a2fSth free(addr); 619e1dd0a2fSth return (NS_LDAP_MEMORY); 620e1dd0a2fSth } 621e1dd0a2fSth 622e1dd0a2fSth if (port) 623e1dd0a2fSth (void) snprintf(*hostname, len, "%s:%s", 624e1dd0a2fSth hp->h_name, port); 625e1dd0a2fSth else 626e1dd0a2fSth (void) strlcpy(*hostname, hp->h_name, len); 627e1dd0a2fSth 628e1dd0a2fSth free(addr); 629e1dd0a2fSth return (NS_LDAP_SUCCESS); 630e1dd0a2fSth } else { 631e1dd0a2fSth free(addr); 632e1dd0a2fSth return (NS_LDAP_NOTFOUND); 633e1dd0a2fSth } 634e1dd0a2fSth } else if (inet_pton(AF_INET6, start, &in6) == 1) { 635e1dd0a2fSth /* IPv6 */ 636e1dd0a2fSth hp = _filter_gethostbyaddr_r((char *)&in6, 637e1dd0a2fSth sizeof (in6.s6_addr), 638e1dd0a2fSth AF_INET6, 639e1dd0a2fSth &hostEnt, 640e1dd0a2fSth buffer, 641e1dd0a2fSth buflen, 642e1dd0a2fSth &errorNum); 643e1dd0a2fSth if (hp && hp->h_name) { 644e1dd0a2fSth /* hostname + '\0' */ 645e1dd0a2fSth len = strlen(hp->h_name) + 1; 646e1dd0a2fSth if (port) 647e1dd0a2fSth /* ':' + port */ 648e1dd0a2fSth len += strlen(port) + 1; 649e1dd0a2fSth if ((*hostname = malloc(len)) == NULL) { 650e1dd0a2fSth free(addr); 651e1dd0a2fSth return (NS_LDAP_MEMORY); 652e1dd0a2fSth } 653e1dd0a2fSth 654e1dd0a2fSth if (port) 655e1dd0a2fSth (void) snprintf(*hostname, len, "%s:%s", 656e1dd0a2fSth hp->h_name, port); 657e1dd0a2fSth else 658e1dd0a2fSth (void) strlcpy(*hostname, hp->h_name, len); 659e1dd0a2fSth 660e1dd0a2fSth free(addr); 661e1dd0a2fSth return (NS_LDAP_SUCCESS); 662e1dd0a2fSth } else { 663e1dd0a2fSth free(addr); 664e1dd0a2fSth return (NS_LDAP_NOTFOUND); 665e1dd0a2fSth } 666e1dd0a2fSth } else { 667e1dd0a2fSth /* 668e1dd0a2fSth * A hostname 669e1dd0a2fSth * Return it as is 670e1dd0a2fSth */ 671e1dd0a2fSth if (end) 672e1dd0a2fSth *end = delim; 673e1dd0a2fSth *hostname = addr; 674e1dd0a2fSth return (NS_LDAP_SUCCESS); 675e1dd0a2fSth } 676e1dd0a2fSth } 677e1dd0a2fSth 678e1dd0a2fSth /* 679e1dd0a2fSth * This function obtains data returned by an LDAP search request and puts it 680e1dd0a2fSth * in a string in the ldap_cachmgr(1) door call format. 681e1dd0a2fSth * 682e1dd0a2fSth * INPUT: 683e1dd0a2fSth * ld - a pointer to an LDAP structure used for a search operation, 684e1dd0a2fSth * result_msg - a pointer to an LDAPMessage returned by the search, 685e1dd0a2fSth * include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will 686e1dd0a2fSth * contain attribute names. 687e1dd0a2fSth * Otherwise, only values will be return. 688e1dd0a2fSth * 689e1dd0a2fSth * OUTPUT: 690e1dd0a2fSth * a buffer containing server info in the following format: 691e1dd0a2fSth * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...] 692e1dd0a2fSth * Should be free'ed by the caller. 693e1dd0a2fSth */ 694e1dd0a2fSth static 695e1dd0a2fSth ns_ldap_return_code 696e1dd0a2fSth convert_to_door_line(LDAP* ld, 697e1dd0a2fSth LDAPMessage *result_msg, 698e1dd0a2fSth int include_names, 699e1dd0a2fSth int is_profile, 700e1dd0a2fSth char **door_line) 701e1dd0a2fSth { 702e1dd0a2fSth uint32_t total_length = 0, attr_len = 0, i; 703e1dd0a2fSth LDAPMessage *e; 704e1dd0a2fSth char *a, **vals; 705e1dd0a2fSth BerElement *ber; 706e1dd0a2fSth int seen_objectclass = 0, rewind = 0; 707e1dd0a2fSth 708e1dd0a2fSth if (!door_line) { 709e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 710e1dd0a2fSth } 711e1dd0a2fSth *door_line = NULL; 712e1dd0a2fSth 713e1dd0a2fSth if ((e = ldap_first_entry(ld, result_msg)) == NULL) { 714e1dd0a2fSth return (NS_LDAP_NOTFOUND); 715e1dd0a2fSth } 716e1dd0a2fSth 717e1dd0a2fSth /* calculate length of received data */ 718e1dd0a2fSth for (a = ldap_first_attribute(ld, e, &ber); 719e1dd0a2fSth a != NULL; 720e1dd0a2fSth a = ldap_next_attribute(ld, e, ber)) { 721e1dd0a2fSth 722e1dd0a2fSth if ((vals = ldap_get_values(ld, e, a)) != NULL) { 723e1dd0a2fSth for (i = 0; vals[i] != NULL; i++) { 724e1dd0a2fSth total_length += (include_names ? 725e1dd0a2fSth strlen(a) : 0) + 726e1dd0a2fSth strlen(vals[i]) + 727e1dd0a2fSth strlen(DOORLINESEP) +1; 728e1dd0a2fSth } 729e1dd0a2fSth ldap_value_free(vals); 730e1dd0a2fSth } 731e1dd0a2fSth ldap_memfree(a); 732e1dd0a2fSth } 733e1dd0a2fSth if (ber != NULL) { 734e1dd0a2fSth ber_free(ber, 0); 735e1dd0a2fSth } 736e1dd0a2fSth 737e1dd0a2fSth if (total_length == 0) { 738e1dd0a2fSth return (NS_LDAP_NOTFOUND); 739e1dd0a2fSth } 740e1dd0a2fSth 741e1dd0a2fSth /* copy the data */ 742e1dd0a2fSth /* add 1 for the last '\0' */ 743e1dd0a2fSth *door_line = (char *)malloc(total_length + 1); 744e1dd0a2fSth if (*door_line == NULL) { 745e1dd0a2fSth return (NS_LDAP_MEMORY); 746e1dd0a2fSth } 747e1dd0a2fSth 748e1dd0a2fSth /* make it an empty string first */ 749e1dd0a2fSth **door_line = '\0'; 750e1dd0a2fSth a = ldap_first_attribute(ld, e, &ber); 751e1dd0a2fSth while (a != NULL) { 752e1dd0a2fSth if (is_profile) { 753e1dd0a2fSth /* 754e1dd0a2fSth * If we're processing DUAConfigProfile, we need to make 755e1dd0a2fSth * sure we put objectclass attribute first. 756e1dd0a2fSth * __s_api_create_config_door_str depends on that. 757e1dd0a2fSth */ 758e1dd0a2fSth if (seen_objectclass) { 759e1dd0a2fSth if (strcasecmp(a, "objectclass") == 0) { 760e1dd0a2fSth /* Skip objectclass now. */ 761e1dd0a2fSth a = ldap_next_attribute(ld, e, ber); 762e1dd0a2fSth continue; 763e1dd0a2fSth } 764e1dd0a2fSth } else { 765e1dd0a2fSth if (strcasecmp(a, "objectclass") == 0) { 766e1dd0a2fSth seen_objectclass = 1; 767e1dd0a2fSth rewind = 1; 768e1dd0a2fSth } else { 769e1dd0a2fSth /* Skip all but objectclass first. */ 770e1dd0a2fSth a = ldap_next_attribute(ld, e, ber); 771e1dd0a2fSth continue; 772e1dd0a2fSth } 773e1dd0a2fSth } 774e1dd0a2fSth } 775e1dd0a2fSth 776e1dd0a2fSth if ((vals = ldap_get_values(ld, e, a)) != NULL) { 777e1dd0a2fSth for (i = 0; vals[i] != NULL; i++) { 778e1dd0a2fSth if (include_names) { 779e1dd0a2fSth attr_len += strlen(a); 780e1dd0a2fSth } 781e1dd0a2fSth attr_len += strlen(vals[i]) + 782e1dd0a2fSth strlen(DOORLINESEP) + 2; 783e1dd0a2fSth if (include_names) { 784e1dd0a2fSth (void) snprintf(*door_line + 785e1dd0a2fSth strlen(*door_line), 786e1dd0a2fSth attr_len, 787e1dd0a2fSth "%s=%s%s", 788e1dd0a2fSth a, vals[i], 789e1dd0a2fSth DOORLINESEP); 790e1dd0a2fSth } else { 791e1dd0a2fSth (void) snprintf(*door_line + 792e1dd0a2fSth strlen(*door_line), 793e1dd0a2fSth attr_len, 794e1dd0a2fSth "%s%s", 795e1dd0a2fSth vals[i], 796e1dd0a2fSth DOORLINESEP); 797e1dd0a2fSth } 798e1dd0a2fSth } 799e1dd0a2fSth ldap_value_free(vals); 800e1dd0a2fSth } 801e1dd0a2fSth ldap_memfree(a); 802e1dd0a2fSth 803e1dd0a2fSth /* Rewind */ 804e1dd0a2fSth if (rewind) { 805e1dd0a2fSth if (ber != NULL) { 806e1dd0a2fSth ber_free(ber, 0); 807e1dd0a2fSth } 808e1dd0a2fSth a = ldap_first_attribute(ld, e, &ber); 809e1dd0a2fSth rewind = 0; 810e1dd0a2fSth } else { 811e1dd0a2fSth a = ldap_next_attribute(ld, e, ber); 812e1dd0a2fSth } 813e1dd0a2fSth } 814e1dd0a2fSth if (ber != NULL) { 815e1dd0a2fSth ber_free(ber, 0); 816e1dd0a2fSth } 817e1dd0a2fSth 818e1dd0a2fSth if (e != result_msg) { 819e1dd0a2fSth (void) ldap_msgfree(e); 820e1dd0a2fSth } 821e1dd0a2fSth 822e1dd0a2fSth return (NS_LDAP_SUCCESS); 823e1dd0a2fSth } 824e1dd0a2fSth 825e1dd0a2fSth /* 826e1dd0a2fSth * This function looks up the base DN of a directory serving 827e1dd0a2fSth * a specified domain name. 828e1dd0a2fSth * 829e1dd0a2fSth * INPUT: 830e1dd0a2fSth * ld - a pointer to an LDAP structure used for the search operation, 831e1dd0a2fSth * domain_name - the name of a domain. 832e1dd0a2fSth * 833e1dd0a2fSth * OUTPUT: 834e1dd0a2fSth * a buffer containing a directory's base DN found. 835e1dd0a2fSth * Should be free'ed by the caller. 836e1dd0a2fSth */ 837e1dd0a2fSth static 838e1dd0a2fSth ns_ldap_return_code 839e1dd0a2fSth getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn) 840e1dd0a2fSth { 841e1dd0a2fSth struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0}; 842e1dd0a2fSth char *attrs[2], *DNlist, *rest, *ptr; 843e1dd0a2fSth char filter[BUFSIZ], *a = NULL; 844e1dd0a2fSth int ldap_rc; 845e1dd0a2fSth LDAPMessage *resultMsg = NULL; 846e1dd0a2fSth ns_ldap_return_code ret_code; 847e1dd0a2fSth 848e1dd0a2fSth /* Get the whole list of naming contexts residing on the server */ 849e1dd0a2fSth attrs[0] = "namingcontexts"; 850e1dd0a2fSth attrs[1] = NULL; 851e1dd0a2fSth ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", 852e1dd0a2fSth attrs, 0, NULL, NULL, &tv, 0, &resultMsg); 853e1dd0a2fSth switch (ldap_rc) { 854e1dd0a2fSth /* If successful, the root DSE was found. */ 855e1dd0a2fSth case LDAP_SUCCESS: 856e1dd0a2fSth break; 857e1dd0a2fSth /* 858e1dd0a2fSth * If the root DSE was not found, the server does 859e1dd0a2fSth * not comply with the LDAP v3 protocol. 860e1dd0a2fSth */ 861e1dd0a2fSth default: 862e1dd0a2fSth if (resultMsg) { 863e1dd0a2fSth (void) ldap_msgfree(resultMsg); 864e1dd0a2fSth resultMsg = NULL; 865e1dd0a2fSth } 866e1dd0a2fSth 867e1dd0a2fSth return (NS_LDAP_OP_FAILED); 868e1dd0a2fSth break; 869e1dd0a2fSth } 870e1dd0a2fSth 871e1dd0a2fSth if ((ret_code = convert_to_door_line(ld, 872e1dd0a2fSth resultMsg, 873e1dd0a2fSth DONT_INCLUDE_ATTR_NAMES, 874e1dd0a2fSth NOT_PROFILE, 875e1dd0a2fSth &DNlist)) != NS_LDAP_SUCCESS) { 876e1dd0a2fSth if (resultMsg) { 877e1dd0a2fSth (void) ldap_msgfree(resultMsg); 878e1dd0a2fSth resultMsg = NULL; 879e1dd0a2fSth } 880e1dd0a2fSth return (ret_code); 881e1dd0a2fSth } 882e1dd0a2fSth 883e1dd0a2fSth if (resultMsg) { 884e1dd0a2fSth (void) ldap_msgfree(resultMsg); 885e1dd0a2fSth resultMsg = NULL; 886e1dd0a2fSth } 887e1dd0a2fSth 888e1dd0a2fSth if (DNlist == NULL || 889e1dd0a2fSth (ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) { 890e1dd0a2fSth return (NS_LDAP_NOTFOUND); 891e1dd0a2fSth } 892e1dd0a2fSth attrs[0] = "dn"; 893e1dd0a2fSth do { 894e1dd0a2fSth /* 895e1dd0a2fSth * For each context try to find a NIS domain object 896e1dd0a2fSth * which 'nisdomain' attribute's value matches the domain name 897e1dd0a2fSth */ 898e1dd0a2fSth (void) snprintf(filter, 899e1dd0a2fSth BUFSIZ, 900e1dd0a2fSth "(&(objectclass=nisDomainObject)" 901e1dd0a2fSth "(nisdomain=%s))", 902e1dd0a2fSth domain_name); 903e1dd0a2fSth ldap_rc = ldap_search_ext_s(ld, 904e1dd0a2fSth ptr, 905e1dd0a2fSth LDAP_SCOPE_SUBTREE, 906e1dd0a2fSth filter, 907e1dd0a2fSth attrs, 908e1dd0a2fSth 0, 909e1dd0a2fSth NULL, 910e1dd0a2fSth NULL, 911e1dd0a2fSth &tv, 912e1dd0a2fSth 0, 913e1dd0a2fSth &resultMsg); 914e1dd0a2fSth if (ldap_rc != LDAP_SUCCESS) { 915e1dd0a2fSth if (resultMsg) { 916e1dd0a2fSth (void) ldap_msgfree(resultMsg); 917e1dd0a2fSth resultMsg = NULL; 918e1dd0a2fSth } 919e1dd0a2fSth continue; 920e1dd0a2fSth } 921e1dd0a2fSth if ((a = ldap_get_dn(ld, resultMsg)) != NULL) { 922e1dd0a2fSth *dir_base_dn = strdup(a); 923e1dd0a2fSth ldap_memfree(a); 924e1dd0a2fSth 925e1dd0a2fSth if (resultMsg) { 926e1dd0a2fSth (void) ldap_msgfree(resultMsg); 927e1dd0a2fSth resultMsg = NULL; 928e1dd0a2fSth } 929e1dd0a2fSth 930e1dd0a2fSth if (!*dir_base_dn) { 931e1dd0a2fSth free(DNlist); 932e1dd0a2fSth return (NS_LDAP_MEMORY); 933e1dd0a2fSth } 934e1dd0a2fSth break; 935e1dd0a2fSth } 936e1dd0a2fSth 937e1dd0a2fSth if (resultMsg) { 938e1dd0a2fSth (void) ldap_msgfree(resultMsg); 939e1dd0a2fSth resultMsg = NULL; 940e1dd0a2fSth } 941e1dd0a2fSth } while (ptr = strtok_r(NULL, DOORLINESEP, &rest)); 942e1dd0a2fSth 943e1dd0a2fSth free(DNlist); 944e1dd0a2fSth 945e1dd0a2fSth if (!*dir_base_dn) { 946e1dd0a2fSth return (NS_LDAP_NOTFOUND); 947e1dd0a2fSth } 948e1dd0a2fSth 949e1dd0a2fSth return (NS_LDAP_SUCCESS); 950e1dd0a2fSth } 951e1dd0a2fSth 952e1dd0a2fSth /* 953e1dd0a2fSth * This function parses the results of a search operation 954e1dd0a2fSth * requesting a DUAProfile. 955e1dd0a2fSth * 956e1dd0a2fSth * INPUT: 957e1dd0a2fSth * ld - a pointer to an LDAP structure used for the search operation, 958e1dd0a2fSth * dir_base_dn - the name of a directory's base DN, 959e1dd0a2fSth * profile_name - the name of a DUAProfile to be obtained. 960e1dd0a2fSth * 961e1dd0a2fSth * OUTPUT: 962e1dd0a2fSth * a buffer containing the DUAProfile in the following format: 963e1dd0a2fSth * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...] 964e1dd0a2fSth * Should be free'ed by the caller. 965e1dd0a2fSth */ 966e1dd0a2fSth static 967e1dd0a2fSth ns_ldap_return_code 968e1dd0a2fSth getDUAProfile(LDAP *ld, 969e1dd0a2fSth const char *dir_base_dn, 970e1dd0a2fSth const char *profile_name, 971e1dd0a2fSth char **profile) 972e1dd0a2fSth { 973e1dd0a2fSth char searchBaseDN[BUFSIZ], filter[BUFSIZ]; 974e1dd0a2fSth LDAPMessage *resultMsg = NULL; 975e1dd0a2fSth struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0}; 976e1dd0a2fSth int ldap_rc; 977e1dd0a2fSth ns_ldap_return_code ret_code; 978e1dd0a2fSth 979e1dd0a2fSth (void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn); 980e1dd0a2fSth (void) snprintf(filter, 981e1dd0a2fSth BUFSIZ, 982e1dd0a2fSth _PROFILE_FILTER, 983e1dd0a2fSth _PROFILE1_OBJECTCLASS, 984e1dd0a2fSth _PROFILE2_OBJECTCLASS, 985e1dd0a2fSth profile_name); 986e1dd0a2fSth ldap_rc = ldap_search_ext_s(ld, 987e1dd0a2fSth searchBaseDN, 988e1dd0a2fSth LDAP_SCOPE_SUBTREE, 989e1dd0a2fSth filter, 990e1dd0a2fSth NULL, 991e1dd0a2fSth 0, 992e1dd0a2fSth NULL, 993e1dd0a2fSth NULL, 994e1dd0a2fSth &tv, 995e1dd0a2fSth 0, 996e1dd0a2fSth &resultMsg); 997e1dd0a2fSth 998e1dd0a2fSth switch (ldap_rc) { 999e1dd0a2fSth /* If successful, the DUA profile was found. */ 1000e1dd0a2fSth case LDAP_SUCCESS: 1001e1dd0a2fSth break; 1002e1dd0a2fSth /* 1003e1dd0a2fSth * If the root DSE was not found, the server does 1004e1dd0a2fSth * not comply with the LDAP v3 protocol. 1005e1dd0a2fSth */ 1006e1dd0a2fSth default: 1007e1dd0a2fSth if (resultMsg) { 1008e1dd0a2fSth (void) ldap_msgfree(resultMsg); 1009e1dd0a2fSth resultMsg = NULL; 1010e1dd0a2fSth } 1011e1dd0a2fSth 1012e1dd0a2fSth return (NS_LDAP_OP_FAILED); 1013e1dd0a2fSth break; 1014e1dd0a2fSth } 1015e1dd0a2fSth 1016e1dd0a2fSth ret_code = convert_to_door_line(ld, 1017e1dd0a2fSth resultMsg, 1018e1dd0a2fSth INCLUDE_ATTR_NAMES, 1019e1dd0a2fSth IS_PROFILE, 1020e1dd0a2fSth profile); 1021e1dd0a2fSth if (resultMsg) { 1022e1dd0a2fSth (void) ldap_msgfree(resultMsg); 1023e1dd0a2fSth resultMsg = NULL; 1024e1dd0a2fSth } 1025e1dd0a2fSth return (ret_code); 1026e1dd0a2fSth } 1027e1dd0a2fSth 1028e1dd0a2fSth /* 1029e1dd0a2fSth * This function derives the directory's base DN from a provided domain name. 1030e1dd0a2fSth * 1031e1dd0a2fSth * INPUT: 1032e1dd0a2fSth * domain_name - the name of a domain to be converted into a base DN, 1033e1dd0a2fSth * buffer - contains the derived base DN, 1034e1dd0a2fSth * buf_len - the length of the buffer. 1035e1dd0a2fSth * 1036e1dd0a2fSth * OUTPUT: 1037e1dd0a2fSth * The function returns the address of the buffer or NULL. 1038e1dd0a2fSth */ 1039e1dd0a2fSth static 1040e1dd0a2fSth char * 1041e1dd0a2fSth domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len) 1042e1dd0a2fSth { 1043e1dd0a2fSth char *nextDC, *chr; 1044e1dd0a2fSth uint16_t i, length; 1045e1dd0a2fSth 1046e1dd0a2fSth if (!domain_name || !buffer || buf_len == 0) { 1047e1dd0a2fSth return (NULL); 1048e1dd0a2fSth } 1049e1dd0a2fSth 1050e1dd0a2fSth buffer[0] = '\0'; 1051e1dd0a2fSth nextDC = chr = domain_name; 1052e1dd0a2fSth length = strlen(domain_name); 1053e1dd0a2fSth for (i = 0; i < length + 1; ++i, ++chr) { 1054e1dd0a2fSth /* Simply replace dots with "dc=" */ 1055e1dd0a2fSth if (*chr != '.' && *chr != '\0') { 1056e1dd0a2fSth continue; 1057e1dd0a2fSth } 1058e1dd0a2fSth *chr = '\0'; 1059e1dd0a2fSth if (strlcat(buffer, "dc=", buf_len) >= buf_len) 1060e1dd0a2fSth return (NULL); 1061e1dd0a2fSth if (strlcat(buffer, nextDC, buf_len) >= buf_len) 1062e1dd0a2fSth return (NULL); 1063e1dd0a2fSth if (i < length) { 1064e1dd0a2fSth /* 1065e1dd0a2fSth * The end of the domain name 1066e1dd0a2fSth * has not been reached yet 1067e1dd0a2fSth */ 1068e1dd0a2fSth if (strlcat(buffer, ",", buf_len) >= buf_len) 1069e1dd0a2fSth return (NULL); 1070e1dd0a2fSth nextDC = chr + 1; 1071e1dd0a2fSth *chr = '.'; 1072e1dd0a2fSth } 1073e1dd0a2fSth } 1074e1dd0a2fSth 1075e1dd0a2fSth return (buffer); 1076e1dd0a2fSth } 1077e1dd0a2fSth 1078e1dd0a2fSth /* 1079e1dd0a2fSth * This function obtains the directory's base DN and a DUAProfile 1080e1dd0a2fSth * from a specified server. 1081e1dd0a2fSth * 1082e1dd0a2fSth * INPUT: 1083e1dd0a2fSth * server - a structure describing a server to connect to and 1084e1dd0a2fSth * a DUAProfile to be obtained from the server, 1085e1dd0a2fSth * cred - credentials to be used during establishing connections to 1086e1dd0a2fSth * the server. 1087e1dd0a2fSth * 1088e1dd0a2fSth * OUTPUT: 1089e1dd0a2fSth * dua_profile - a buffer containing the DUAProfile in the following format: 1090e1dd0a2fSth * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...] 1091e1dd0a2fSth * dir_base_dn - a buffer containing the base DN, 1092e1dd0a2fSth * errorp - an error object describing an error, if any. 1093e1dd0a2fSth * 1094e1dd0a2fSth * All the output data structures should be free'ed by the caller. 1095e1dd0a2fSth */ 1096e1dd0a2fSth ns_ldap_return_code 1097e1dd0a2fSth __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server, 1098e1dd0a2fSth const ns_cred_t *cred, 1099e1dd0a2fSth char **dua_profile, 1100e1dd0a2fSth char **dir_base_dn, 1101e1dd0a2fSth ns_ldap_error_t **errorp) 1102e1dd0a2fSth { 1103e1dd0a2fSth char serverAddr[MAX_HOSTADDR_LEN]; 1104e1dd0a2fSth char *dirBaseDN = NULL, *duaProfile = NULL; 1105e1dd0a2fSth ns_cred_t default_cred; 1106e1dd0a2fSth ns_ldap_return_code ret_code; 1107e1dd0a2fSth 1108e1dd0a2fSth ns_config_t *config_struct = __s_api_create_config(); 1109e1dd0a2fSth ConnectionID sessionId = 0; 1110e1dd0a2fSth Connection *session = NULL; 1111e1dd0a2fSth char errmsg[MAXERROR]; 1112e1dd0a2fSth char buffer[NSS_BUFLEN_HOSTS]; 111329836b19Smichen ns_conn_user_t *cu = NULL; 1114e1dd0a2fSth 1115e1dd0a2fSth if (errorp == NULL) { 1116e1dd0a2fSth __s_api_destroy_config(config_struct); 1117e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1118e1dd0a2fSth } 1119e1dd0a2fSth 1120e1dd0a2fSth *errorp = NULL; 1121e1dd0a2fSth 1122e1dd0a2fSth if (server == NULL) { 1123e1dd0a2fSth __s_api_destroy_config(config_struct); 1124e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1125e1dd0a2fSth } 1126e1dd0a2fSth 1127e1dd0a2fSth if (config_struct == NULL) { 1128e1dd0a2fSth return (NS_LDAP_MEMORY); 1129e1dd0a2fSth } 1130e1dd0a2fSth 1131e1dd0a2fSth /* 1132e1dd0a2fSth * If no credentials are specified, try to establish a connection 1133e1dd0a2fSth * as anonymous. 1134e1dd0a2fSth */ 1135e1dd0a2fSth if (!cred) { 1136e1dd0a2fSth default_cred.cred.unix_cred.passwd = NULL; 1137e1dd0a2fSth default_cred.cred.unix_cred.userID = NULL; 1138e1dd0a2fSth default_cred.auth.type = NS_LDAP_AUTH_NONE; 1139e1dd0a2fSth } 1140e1dd0a2fSth 1141e1dd0a2fSth /* Now create a default LDAP configuration */ 1142e1dd0a2fSth 1143e1dd0a2fSth (void) strncpy(buffer, server->server, sizeof (buffer)); 1144e1dd0a2fSth if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer, 1145e1dd0a2fSth errorp) != NS_LDAP_SUCCESS) { 1146e1dd0a2fSth __s_api_destroy_config(config_struct); 1147e1dd0a2fSth return (NS_LDAP_CONFIG); 1148e1dd0a2fSth } 1149e1dd0a2fSth 1150e1dd0a2fSth /* Put together the address and the port specified by the user app. */ 1151e1dd0a2fSth if (server->port > 0) { 1152e1dd0a2fSth (void) snprintf(serverAddr, 1153e1dd0a2fSth sizeof (serverAddr), 1154e1dd0a2fSth "%s:%hu", 1155e1dd0a2fSth buffer, 1156e1dd0a2fSth server->port); 1157e1dd0a2fSth } else { 1158e1dd0a2fSth (void) strncpy(serverAddr, buffer, sizeof (serverAddr)); 1159e1dd0a2fSth } 1160e1dd0a2fSth 1161e1dd0a2fSth /* 1162e1dd0a2fSth * There is no default value for the 'Default Search Base DN' attribute. 1163e1dd0a2fSth * Derive one from the domain name to make __s_api_crosscheck() happy. 1164e1dd0a2fSth */ 1165e1dd0a2fSth if (domainname2baseDN(server->domainName ? 1166e1dd0a2fSth server->domainName : config_struct->domainName, 1167e1dd0a2fSth buffer, NSS_BUFLEN_HOSTS) == NULL) { 1168e1dd0a2fSth (void) snprintf(errmsg, 1169e1dd0a2fSth sizeof (errmsg), 1170e1dd0a2fSth gettext("Can not convert %s into a base DN name"), 1171e1dd0a2fSth server->domainName ? 1172e1dd0a2fSth server->domainName : config_struct->domainName); 1173e1dd0a2fSth MKERROR(LOG_ERR, 1174e1dd0a2fSth *errorp, 1175e1dd0a2fSth NS_LDAP_INTERNAL, 1176e1dd0a2fSth strdup(errmsg), 1177e1dd0a2fSth NS_LDAP_MEMORY); 1178e1dd0a2fSth __s_api_destroy_config(config_struct); 1179e1dd0a2fSth return (NS_LDAP_INTERNAL); 1180e1dd0a2fSth } 1181e1dd0a2fSth if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P, 1182e1dd0a2fSth buffer, errorp) != NS_LDAP_SUCCESS) { 1183e1dd0a2fSth __s_api_destroy_config(config_struct); 1184e1dd0a2fSth return (NS_LDAP_CONFIG); 1185e1dd0a2fSth } 1186e1dd0a2fSth 1187e1dd0a2fSth if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) { 1188e1dd0a2fSth __s_api_destroy_config(config_struct); 1189e1dd0a2fSth return (NS_LDAP_CONFIG); 1190e1dd0a2fSth } 1191e1dd0a2fSth 1192e1dd0a2fSth __s_api_init_config(config_struct); 1193e1dd0a2fSth 1194e1dd0a2fSth __s_api_setInitMode(); 1195e1dd0a2fSth 119629836b19Smichen cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE); 119729836b19Smichen if (cu == NULL) { 119829836b19Smichen return (NS_LDAP_INTERNAL); 119929836b19Smichen } 120029836b19Smichen 1201e1dd0a2fSth if ((ret_code = __s_api_getConnection(serverAddr, 1202e1dd0a2fSth NS_LDAP_NEW_CONN, 1203e1dd0a2fSth cred ? cred : &default_cred, 1204e1dd0a2fSth &sessionId, 1205e1dd0a2fSth &session, 1206e1dd0a2fSth errorp, 1207e1dd0a2fSth 0, 1208e1dd0a2fSth 0, 120929836b19Smichen cu)) != NS_LDAP_SUCCESS) { 121029836b19Smichen __s_api_conn_user_free(cu); 1211e1dd0a2fSth __s_api_unsetInitMode(); 1212e1dd0a2fSth return (ret_code); 1213e1dd0a2fSth } 1214e1dd0a2fSth 1215e1dd0a2fSth __s_api_unsetInitMode(); 1216e1dd0a2fSth 1217e1dd0a2fSth if ((ret_code = getDirBaseDN(session->ld, 1218e1dd0a2fSth server->domainName ? 1219e1dd0a2fSth server->domainName : 1220e1dd0a2fSth config_struct->domainName, 1221e1dd0a2fSth &dirBaseDN)) != NS_LDAP_SUCCESS) { 1222e1dd0a2fSth (void) snprintf(errmsg, 1223e1dd0a2fSth sizeof (errmsg), 1224e1dd0a2fSth gettext("Can not find the " 1225e1dd0a2fSth "nisDomainObject for domain %s\n"), 1226e1dd0a2fSth server->domainName ? 1227e1dd0a2fSth server->domainName : config_struct->domainName); 1228e1dd0a2fSth MKERROR(LOG_ERR, 1229e1dd0a2fSth *errorp, 1230e1dd0a2fSth ret_code, 1231e1dd0a2fSth strdup(errmsg), 1232e1dd0a2fSth NS_LDAP_MEMORY); 123329836b19Smichen __s_api_conn_user_free(cu); 1234e1dd0a2fSth DropConnection(sessionId, NS_LDAP_NEW_CONN); 1235e1dd0a2fSth return (ret_code); 1236e1dd0a2fSth } 1237e1dd0a2fSth 1238e1dd0a2fSth /* 1239e1dd0a2fSth * And here obtain a DUAProfile which will be used 1240e1dd0a2fSth * as a real configuration. 1241e1dd0a2fSth */ 1242e1dd0a2fSth if ((ret_code = getDUAProfile(session->ld, 1243e1dd0a2fSth dirBaseDN, 1244e1dd0a2fSth server->profileName ? 1245e1dd0a2fSth server->profileName : "default", 1246e1dd0a2fSth &duaProfile)) != NS_LDAP_SUCCESS) { 1247e1dd0a2fSth (void) snprintf(errmsg, 1248e1dd0a2fSth sizeof (errmsg), 1249e1dd0a2fSth gettext("Can not find the " 1250e1dd0a2fSth "%s DUAProfile\n"), 1251e1dd0a2fSth server->profileName ? 1252e1dd0a2fSth server->profileName : "default"); 1253e1dd0a2fSth MKERROR(LOG_ERR, 1254e1dd0a2fSth *errorp, 1255e1dd0a2fSth ret_code, 1256e1dd0a2fSth strdup(errmsg), 1257e1dd0a2fSth NS_LDAP_MEMORY); 125829836b19Smichen __s_api_conn_user_free(cu); 1259e1dd0a2fSth DropConnection(sessionId, NS_LDAP_NEW_CONN); 1260e1dd0a2fSth return (ret_code); 1261e1dd0a2fSth } 1262e1dd0a2fSth 1263e1dd0a2fSth if (dir_base_dn) { 1264e1dd0a2fSth *dir_base_dn = dirBaseDN; 1265e1dd0a2fSth } else { 1266e1dd0a2fSth free(dirBaseDN); 1267e1dd0a2fSth } 1268e1dd0a2fSth 1269e1dd0a2fSth if (dua_profile) { 1270e1dd0a2fSth *dua_profile = duaProfile; 1271e1dd0a2fSth } else { 1272e1dd0a2fSth free(duaProfile); 1273e1dd0a2fSth } 1274e1dd0a2fSth 127529836b19Smichen __s_api_conn_user_free(cu); 1276e1dd0a2fSth DropConnection(sessionId, NS_LDAP_NEW_CONN); 1277e1dd0a2fSth 1278e1dd0a2fSth return (NS_LDAP_SUCCESS); 1279e1dd0a2fSth } 1280e1dd0a2fSth 1281e1dd0a2fSth /* 1282e1dd0a2fSth * This function obtains the root DSE from a specified server. 1283e1dd0a2fSth * 1284e1dd0a2fSth * INPUT: 1285e1dd0a2fSth * server_addr - an adress of a server to be connected to. 1286e1dd0a2fSth * 1287e1dd0a2fSth * OUTPUT: 1288e1dd0a2fSth * root_dse - a buffer containing the root DSE in the following format: 1289e1dd0a2fSth * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...] 1290e1dd0a2fSth * For example: ( here | used as DOORLINESEP for visual purposes) 1291e1dd0a2fSth * supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL 1292e1dd0a2fSth * Should be free'ed by the caller. 1293e1dd0a2fSth */ 1294e1dd0a2fSth ns_ldap_return_code 1295e1dd0a2fSth __ns_ldap_getRootDSE(const char *server_addr, 1296e1dd0a2fSth char **root_dse, 1297e1dd0a2fSth ns_ldap_error_t **errorp, 1298e1dd0a2fSth int anon_fallback) 1299e1dd0a2fSth { 1300e1dd0a2fSth char errmsg[MAXERROR]; 1301e1dd0a2fSth ns_ldap_return_code ret_code; 1302e1dd0a2fSth 1303e1dd0a2fSth ConnectionID sessionId = 0; 1304e1dd0a2fSth Connection *session = NULL; 1305e1dd0a2fSth 1306e1dd0a2fSth struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0}; 1307e1dd0a2fSth char *attrs[3]; 1308e1dd0a2fSth int ldap_rc, ldaperrno = 0; 1309e1dd0a2fSth LDAPMessage *resultMsg = NULL; 1310e1dd0a2fSth void **paramVal = NULL; 1311e1dd0a2fSth 1312e1dd0a2fSth ns_cred_t anon; 131329836b19Smichen ns_conn_user_t *cu = NULL; 1314e1dd0a2fSth 1315e1dd0a2fSth if (errorp == NULL) { 1316e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1317e1dd0a2fSth } 1318e1dd0a2fSth 1319e1dd0a2fSth *errorp = NULL; 1320e1dd0a2fSth 1321e1dd0a2fSth if (!root_dse) { 1322e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1323e1dd0a2fSth } 1324e1dd0a2fSth 1325e1dd0a2fSth if (!server_addr) { 1326e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1327e1dd0a2fSth } 1328e1dd0a2fSth 1329e1dd0a2fSth __s_api_setInitMode(); 1330e1dd0a2fSth 133129836b19Smichen cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE); 133229836b19Smichen if (cu == NULL) { 133329836b19Smichen return (NS_LDAP_INTERNAL); 133429836b19Smichen } 133529836b19Smichen 1336e1dd0a2fSth /* 1337e1dd0a2fSth * All the credentials will be taken from the current 1338e1dd0a2fSth * libsldap configuration. 1339e1dd0a2fSth */ 1340e1dd0a2fSth if ((ret_code = __s_api_getConnection(server_addr, 1341e1dd0a2fSth NS_LDAP_NEW_CONN, 1342e1dd0a2fSth NULL, 1343e1dd0a2fSth &sessionId, 1344e1dd0a2fSth &session, 1345e1dd0a2fSth errorp, 1346e1dd0a2fSth 0, 1347e1dd0a2fSth 0, 134829836b19Smichen cu)) != NS_LDAP_SUCCESS) { 1349e1dd0a2fSth /* Fallback to anonymous mode is disabled. Stop. */ 1350e1dd0a2fSth if (anon_fallback == 0) { 1351e1dd0a2fSth syslog(LOG_WARNING, 1352e1dd0a2fSth gettext("libsldap: can not get the root DSE from " 1353e1dd0a2fSth " the %s server: %s. " 1354e1dd0a2fSth "Falling back to anonymous disabled.\n"), 1355e1dd0a2fSth server_addr, 1356e1dd0a2fSth errorp && *errorp && (*errorp)->message ? 1357e1dd0a2fSth (*errorp)->message : ""); 1358e1dd0a2fSth if (errorp != NULL && *errorp != NULL) { 1359e1dd0a2fSth (void) __ns_ldap_freeError(errorp); 1360e1dd0a2fSth } 1361e1dd0a2fSth __s_api_unsetInitMode(); 1362e1dd0a2fSth return (ret_code); 1363e1dd0a2fSth } 1364e1dd0a2fSth 1365e1dd0a2fSth /* 1366e1dd0a2fSth * Fallback to anonymous, non-SSL mode for backward 1367e1dd0a2fSth * compatibility reasons. This mode should only be used when 1368e1dd0a2fSth * this function (__ns_ldap_getRootDSE) is called from 1369e1dd0a2fSth * ldap_cachemgr(1M). 1370e1dd0a2fSth */ 1371e1dd0a2fSth syslog(LOG_WARNING, 1372e1dd0a2fSth gettext("libsldap: Falling back to anonymous, non-SSL" 1373e1dd0a2fSth " mode for __ns_ldap_getRootDSE. %s\n"), 1374e1dd0a2fSth errorp && *errorp && (*errorp)->message ? 1375e1dd0a2fSth (*errorp)->message : ""); 1376e1dd0a2fSth 1377e1dd0a2fSth /* Setup the anon credential for anonymous connection. */ 1378e1dd0a2fSth (void) memset(&anon, 0, sizeof (ns_cred_t)); 1379e1dd0a2fSth anon.auth.type = NS_LDAP_AUTH_NONE; 1380e1dd0a2fSth 1381e1dd0a2fSth if (*errorp != NULL) { 1382e1dd0a2fSth (void) __ns_ldap_freeError(errorp); 1383e1dd0a2fSth } 1384e1dd0a2fSth *errorp = NULL; 1385e1dd0a2fSth 1386e1dd0a2fSth ret_code = __s_api_getConnection(server_addr, 1387e1dd0a2fSth NS_LDAP_NEW_CONN, 1388e1dd0a2fSth &anon, 1389e1dd0a2fSth &sessionId, 1390e1dd0a2fSth &session, 1391e1dd0a2fSth errorp, 1392e1dd0a2fSth 0, 1393e1dd0a2fSth 0, 139429836b19Smichen cu); 1395e1dd0a2fSth 1396e1dd0a2fSth if (ret_code != NS_LDAP_SUCCESS) { 139729836b19Smichen __s_api_conn_user_free(cu); 1398e1dd0a2fSth __s_api_unsetInitMode(); 1399e1dd0a2fSth return (ret_code); 1400e1dd0a2fSth } 1401e1dd0a2fSth } 1402e1dd0a2fSth 1403e1dd0a2fSth __s_api_unsetInitMode(); 1404e1dd0a2fSth 1405e1dd0a2fSth /* get search timeout value */ 1406e1dd0a2fSth (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, ¶mVal, errorp); 1407e1dd0a2fSth if (paramVal != NULL && *paramVal != NULL) { 1408e1dd0a2fSth tv.tv_sec = **((int **)paramVal); 1409e1dd0a2fSth (void) __ns_ldap_freeParam(¶mVal); 1410e1dd0a2fSth } 1411e1dd0a2fSth if (*errorp != NULL) { 1412e1dd0a2fSth (void) __ns_ldap_freeError(errorp); 1413e1dd0a2fSth } 1414e1dd0a2fSth 1415e1dd0a2fSth /* Get root DSE from the server specified by the caller. */ 1416e1dd0a2fSth attrs[0] = "supportedControl"; 1417e1dd0a2fSth attrs[1] = "supportedsaslmechanisms"; 1418e1dd0a2fSth attrs[2] = NULL; 1419e1dd0a2fSth ldap_rc = ldap_search_ext_s(session->ld, 1420e1dd0a2fSth "", 1421e1dd0a2fSth LDAP_SCOPE_BASE, 1422e1dd0a2fSth "(objectclass=*)", 1423e1dd0a2fSth attrs, 1424e1dd0a2fSth 0, 1425e1dd0a2fSth NULL, 1426e1dd0a2fSth NULL, 1427e1dd0a2fSth &tv, 1428e1dd0a2fSth 0, 1429e1dd0a2fSth &resultMsg); 1430e1dd0a2fSth 1431e1dd0a2fSth if (ldap_rc != LDAP_SUCCESS) { 1432e1dd0a2fSth /* 1433e1dd0a2fSth * If the root DSE was not found, the server does 1434e1dd0a2fSth * not comply with the LDAP v3 protocol. 1435e1dd0a2fSth */ 1436e1dd0a2fSth (void) ldap_get_option(session->ld, 1437e1dd0a2fSth LDAP_OPT_ERROR_NUMBER, 1438e1dd0a2fSth &ldaperrno); 1439e1dd0a2fSth (void) snprintf(errmsg, 1440e1dd0a2fSth sizeof (errmsg), 1441e1dd0a2fSth gettext(ldap_err2string(ldaperrno))); 1442e1dd0a2fSth MKERROR(LOG_ERR, 1443e1dd0a2fSth *errorp, 1444e1dd0a2fSth NS_LDAP_OP_FAILED, 1445e1dd0a2fSth strdup(errmsg), 1446e1dd0a2fSth NS_LDAP_MEMORY); 1447e1dd0a2fSth 1448e1dd0a2fSth if (resultMsg) { 1449e1dd0a2fSth (void) ldap_msgfree(resultMsg); 1450e1dd0a2fSth resultMsg = NULL; 1451e1dd0a2fSth } 1452e1dd0a2fSth 145329836b19Smichen __s_api_conn_user_free(cu); 1454e1dd0a2fSth return (NS_LDAP_OP_FAILED); 1455e1dd0a2fSth } 145629836b19Smichen __s_api_conn_user_free(cu); 1457e1dd0a2fSth 1458e1dd0a2fSth ret_code = convert_to_door_line(session->ld, 1459e1dd0a2fSth resultMsg, 1460e1dd0a2fSth INCLUDE_ATTR_NAMES, 1461e1dd0a2fSth NOT_PROFILE, 1462e1dd0a2fSth root_dse); 1463e1dd0a2fSth if (ret_code == NS_LDAP_NOTFOUND) { 1464e1dd0a2fSth (void) snprintf(errmsg, 1465e1dd0a2fSth sizeof (errmsg), 1466e1dd0a2fSth gettext("No root DSE data " 1467e1dd0a2fSth "for server %s returned."), 1468e1dd0a2fSth server_addr); 1469e1dd0a2fSth MKERROR(LOG_ERR, 1470e1dd0a2fSth *errorp, 1471e1dd0a2fSth NS_LDAP_NOTFOUND, 1472e1dd0a2fSth strdup(errmsg), 1473e1dd0a2fSth NS_LDAP_MEMORY); 1474e1dd0a2fSth } 1475e1dd0a2fSth 1476e1dd0a2fSth if (resultMsg) { 1477e1dd0a2fSth (void) ldap_msgfree(resultMsg); 1478e1dd0a2fSth resultMsg = NULL; 1479e1dd0a2fSth } 1480e1dd0a2fSth 1481e1dd0a2fSth DropConnection(sessionId, NS_LDAP_NEW_CONN); 1482e1dd0a2fSth 1483e1dd0a2fSth return (ret_code); 1484e1dd0a2fSth } 1485e1dd0a2fSth 1486e1dd0a2fSth /* 1487e1dd0a2fSth * This function destroys the local list of root DSEs. The input parameter is 1488e1dd0a2fSth * a pointer to the list to be erased. 1489e1dd0a2fSth * The type of the pointer passed to this function should be 1490e1dd0a2fSth * (dir_server_list_t *). 1491e1dd0a2fSth */ 1492e1dd0a2fSth static 1493e1dd0a2fSth void * 1494e1dd0a2fSth disposeOfOldList(void *param) 1495e1dd0a2fSth { 1496e1dd0a2fSth dir_server_list_t *old_list = (dir_server_list_t *)param; 1497e1dd0a2fSth long i = 0, j; 1498e1dd0a2fSth 1499e1dd0a2fSth (void) rw_wrlock(&old_list->listDestroyLock); 1500e1dd0a2fSth /* Destroy the old list */ 1501e1dd0a2fSth while (old_list->nsServers[i]) { 1502e1dd0a2fSth free(old_list->nsServers[i]->ip); 1503e1dd0a2fSth j = 0; 1504e1dd0a2fSth while (old_list->nsServers[i]->controls && 1505e1dd0a2fSth old_list->nsServers[i]->controls[j]) { 1506e1dd0a2fSth free(old_list->nsServers[i]->controls[j]); 1507e1dd0a2fSth ++j; 1508e1dd0a2fSth } 1509e1dd0a2fSth free(old_list->nsServers[i]->controls); 1510e1dd0a2fSth j = 0; 1511e1dd0a2fSth while (old_list->nsServers[i]->saslMech && 1512e1dd0a2fSth old_list->nsServers[i]->saslMech[j]) { 1513e1dd0a2fSth free(old_list->nsServers[i]->saslMech[j]); 1514e1dd0a2fSth ++j; 1515e1dd0a2fSth } 1516e1dd0a2fSth free(old_list->nsServers[i]->saslMech); 1517e1dd0a2fSth ++i; 1518e1dd0a2fSth } 1519e1dd0a2fSth /* 1520e1dd0a2fSth * All the structures pointed by old_list->nsServers were allocated 1521e1dd0a2fSth * in one chunck. The nsServers[0] pointer points to the beginning 1522e1dd0a2fSth * of that chunck. 1523e1dd0a2fSth */ 1524e1dd0a2fSth free(old_list->nsServers[0]); 1525e1dd0a2fSth free(old_list->nsServers); 1526e1dd0a2fSth (void) rw_unlock(&old_list->listDestroyLock); 1527e1dd0a2fSth (void) rwlock_destroy(&old_list->listDestroyLock); 1528e1dd0a2fSth free(old_list); 1529e1dd0a2fSth 1530e1dd0a2fSth return (NULL); 1531e1dd0a2fSth } 1532e1dd0a2fSth 1533e1dd0a2fSth /* 1534e1dd0a2fSth * This function cancels the Standalone mode and destroys the list of root DSEs. 1535e1dd0a2fSth */ 1536e1dd0a2fSth void 1537e1dd0a2fSth __ns_ldap_cancelStandalone(void) 1538e1dd0a2fSth { 1539e1dd0a2fSth dir_server_list_t *old_list; 1540e1dd0a2fSth 1541e1dd0a2fSth (void) mutex_lock(&dir_servers.listReplaceLock); 1542e1dd0a2fSth dir_servers.standalone = 0; 1543e1dd0a2fSth if (!dir_servers.list) { 1544e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 1545e1dd0a2fSth return; 1546e1dd0a2fSth } 1547e1dd0a2fSth old_list = dir_servers.list; 1548e1dd0a2fSth dir_servers.list = NULL; 1549e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 1550e1dd0a2fSth 1551e1dd0a2fSth (void) disposeOfOldList(old_list); 1552e1dd0a2fSth } 1553e1dd0a2fSth 1554e1dd0a2fSth 1555e1dd0a2fSth static 1556e1dd0a2fSth void* 1557e1dd0a2fSth create_ns_servers_entry(void *param) 1558e1dd0a2fSth { 1559e1dd0a2fSth #define CHUNK_SIZE 16 1560e1dd0a2fSth 1561e1dd0a2fSth dir_server_t *server = (dir_server_t *)param; 1562e1dd0a2fSth ns_ldap_return_code *retCode = calloc(1, 1563e1dd0a2fSth sizeof (ns_ldap_return_code)); 1564e1dd0a2fSth uint32_t sc_counter = 0, sm_counter = 0; 1565e1dd0a2fSth uint32_t sc_mem_blocks = 1, sm_mem_blocks = 1; 1566e1dd0a2fSth char *rootDSE = NULL, *attr, *val, *rest, **ptr; 1567e1dd0a2fSth ns_ldap_error_t *error = NULL; 1568e1dd0a2fSth 1569e1dd0a2fSth if (retCode == NULL) { 1570e1dd0a2fSth return (NULL); 1571e1dd0a2fSth } 1572e1dd0a2fSth 1573e1dd0a2fSth /* 1574e1dd0a2fSth * We call this function in non anon-fallback mode because we 1575e1dd0a2fSth * want the whole procedure to fail as soon as possible to 1576e1dd0a2fSth * indicate there are problems with connecting to the server. 1577e1dd0a2fSth */ 1578e1dd0a2fSth *retCode = __ns_ldap_getRootDSE(server->ip, 1579e1dd0a2fSth &rootDSE, 1580e1dd0a2fSth &error, 1581e1dd0a2fSth SA_ALLOW_FALLBACK); 1582e1dd0a2fSth 1583e1dd0a2fSth if (*retCode == NS_LDAP_MEMORY) { 1584e1dd0a2fSth free(retCode); 1585e1dd0a2fSth return (NULL); 1586e1dd0a2fSth } 1587e1dd0a2fSth 1588e1dd0a2fSth /* 1589e1dd0a2fSth * If the root DSE can not be obtained, log an error and keep the 1590e1dd0a2fSth * server. 1591e1dd0a2fSth */ 1592e1dd0a2fSth if (*retCode != NS_LDAP_SUCCESS) { 1593e1dd0a2fSth server->status = INFO_SERVER_ERROR; 1594e1dd0a2fSth syslog(LOG_WARNING, 1595e1dd0a2fSth gettext("libsldap (\"standalone\" mode): " 1596e1dd0a2fSth "can not obtain the root DSE from %s. %s"), 1597e1dd0a2fSth server->ip, 1598e1dd0a2fSth error && error->message ? error->message : ""); 1599e1dd0a2fSth if (error) { 1600e1dd0a2fSth (void) __ns_ldap_freeError(&error); 1601e1dd0a2fSth } 1602e1dd0a2fSth return (retCode); 1603e1dd0a2fSth } 1604e1dd0a2fSth 1605e1dd0a2fSth /* Get the first attribute of the root DSE. */ 1606e1dd0a2fSth attr = strtok_r(rootDSE, DOORLINESEP, &rest); 1607e1dd0a2fSth if (attr == NULL) { 1608e1dd0a2fSth free(rootDSE); 1609e1dd0a2fSth server->status = INFO_SERVER_ERROR; 1610e1dd0a2fSth syslog(LOG_WARNING, 1611e1dd0a2fSth gettext("libsldap (\"standalone\" mode): " 1612e1dd0a2fSth "the root DSE from %s is empty or corrupted."), 1613e1dd0a2fSth server->ip); 1614e1dd0a2fSth *retCode = NS_LDAP_INTERNAL; 1615e1dd0a2fSth return (retCode); 1616e1dd0a2fSth } 1617e1dd0a2fSth 1618e1dd0a2fSth server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *)); 1619e1dd0a2fSth server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *)); 1620e1dd0a2fSth if (server->controls == NULL || server->saslMech == NULL) { 1621e1dd0a2fSth free(rootDSE); 1622e1dd0a2fSth free(retCode); 1623e1dd0a2fSth return (NULL); 1624e1dd0a2fSth } 1625e1dd0a2fSth 1626e1dd0a2fSth do { 1627e1dd0a2fSth if ((val = strchr(attr, '=')) == NULL) { 1628e1dd0a2fSth continue; 1629e1dd0a2fSth } 1630e1dd0a2fSth ++val; 1631e1dd0a2fSth 1632e1dd0a2fSth if (strncasecmp(attr, 1633e1dd0a2fSth _SASLMECHANISM, 1634e1dd0a2fSth _SASLMECHANISM_LEN) == 0) { 1635e1dd0a2fSth if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) { 1636e1dd0a2fSth ptr = (char **)realloc(server->saslMech, 1637e1dd0a2fSth CHUNK_SIZE * 1638e1dd0a2fSth ++sm_mem_blocks * 1639e1dd0a2fSth sizeof (char *)); 1640e1dd0a2fSth if (ptr == NULL) { 1641e1dd0a2fSth *retCode = NS_LDAP_MEMORY; 1642e1dd0a2fSth break; 1643e1dd0a2fSth } 1644e1dd0a2fSth bzero((char *)ptr + 1645e1dd0a2fSth (sm_counter + 1) * 1646e1dd0a2fSth sizeof (char *), 1647e1dd0a2fSth CHUNK_SIZE * 1648e1dd0a2fSth sm_mem_blocks * 1649e1dd0a2fSth sizeof (char *) - 1650e1dd0a2fSth (sm_counter + 1) * 1651e1dd0a2fSth sizeof (char *)); 1652e1dd0a2fSth server->saslMech = ptr; 1653e1dd0a2fSth } 1654e1dd0a2fSth server->saslMech[sm_counter] = strdup(val); 1655e1dd0a2fSth if (server->saslMech[sm_counter] == NULL) { 1656e1dd0a2fSth *retCode = NS_LDAP_MEMORY; 1657e1dd0a2fSth break; 1658e1dd0a2fSth } 1659e1dd0a2fSth ++sm_counter; 1660e1dd0a2fSth continue; 1661e1dd0a2fSth } 1662e1dd0a2fSth if (strncasecmp(attr, 1663e1dd0a2fSth _SUPPORTEDCONTROL, 1664e1dd0a2fSth _SUPPORTEDCONTROL_LEN) == 0) { 1665e1dd0a2fSth if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) { 1666e1dd0a2fSth ptr = (char **)realloc(server->controls, 1667e1dd0a2fSth CHUNK_SIZE * 1668e1dd0a2fSth ++sc_mem_blocks * 1669e1dd0a2fSth sizeof (char *)); 1670e1dd0a2fSth if (ptr == NULL) { 1671e1dd0a2fSth *retCode = NS_LDAP_MEMORY; 1672e1dd0a2fSth break; 1673e1dd0a2fSth } 1674e1dd0a2fSth bzero((char *)ptr + 1675e1dd0a2fSth (sc_counter + 1) * 1676e1dd0a2fSth sizeof (char *), 1677e1dd0a2fSth CHUNK_SIZE * 1678e1dd0a2fSth sc_mem_blocks * 1679e1dd0a2fSth sizeof (char *) - 1680e1dd0a2fSth (sc_counter + 1) * 1681e1dd0a2fSth sizeof (char *)); 1682e1dd0a2fSth server->controls = ptr; 1683e1dd0a2fSth } 1684e1dd0a2fSth 1685e1dd0a2fSth server->controls[sc_counter] = strdup(val); 1686e1dd0a2fSth if (server->controls[sc_counter] == NULL) { 1687e1dd0a2fSth *retCode = NS_LDAP_MEMORY; 1688e1dd0a2fSth break; 1689e1dd0a2fSth } 1690e1dd0a2fSth ++sc_counter; 1691e1dd0a2fSth continue; 1692e1dd0a2fSth } 1693e1dd0a2fSth 1694e1dd0a2fSth } while (attr = strtok_r(NULL, DOORLINESEP, &rest)); 1695e1dd0a2fSth 1696e1dd0a2fSth free(rootDSE); 1697e1dd0a2fSth 1698e1dd0a2fSth if (*retCode == NS_LDAP_MEMORY) { 1699e1dd0a2fSth free(retCode); 1700e1dd0a2fSth return (NULL); 1701e1dd0a2fSth } 1702e1dd0a2fSth 1703e1dd0a2fSth server->controls[sc_counter] = NULL; 1704e1dd0a2fSth server->saslMech[sm_counter] = NULL; 1705e1dd0a2fSth 1706e1dd0a2fSth server->status = INFO_SERVER_UP; 1707e1dd0a2fSth 1708e1dd0a2fSth return (retCode); 1709e1dd0a2fSth #undef CHUNK_SIZE 1710e1dd0a2fSth } 1711e1dd0a2fSth 1712e1dd0a2fSth 1713e1dd0a2fSth /* 1714e1dd0a2fSth * This function creates a new local list of root DSEs from all the servers 1715e1dd0a2fSth * mentioned in the DUAProfile (or local NS BEC) and returns 1716e1dd0a2fSth * a pointer to the list. 1717e1dd0a2fSth */ 1718e1dd0a2fSth static 1719e1dd0a2fSth ns_ldap_return_code 1720e1dd0a2fSth createDirServerList(dir_server_list_t **new_list, 1721e1dd0a2fSth ns_ldap_error_t **errorp) 1722e1dd0a2fSth { 1723e1dd0a2fSth char **serverList; 1724e1dd0a2fSth ns_ldap_return_code retCode = NS_LDAP_SUCCESS; 1725e1dd0a2fSth dir_server_t *tmpSrvArray; 1726e1dd0a2fSth long srvListLength, i; 1727e1dd0a2fSth thread_t *thrPool, thrID; 1728e1dd0a2fSth void *status = NULL; 1729e1dd0a2fSth 1730e1dd0a2fSth if (errorp == NULL) { 1731e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1732e1dd0a2fSth } 1733e1dd0a2fSth 1734e1dd0a2fSth *errorp = NULL; 1735e1dd0a2fSth 1736e1dd0a2fSth if (new_list == NULL) { 1737e1dd0a2fSth return (NS_LDAP_INVALID_PARAM); 1738e1dd0a2fSth } 1739e1dd0a2fSth 1740e1dd0a2fSth retCode = __s_api_getServers(&serverList, errorp); 1741e1dd0a2fSth if (retCode != NS_LDAP_SUCCESS || serverList == NULL) { 1742e1dd0a2fSth return (retCode); 1743e1dd0a2fSth } 1744e1dd0a2fSth 1745e1dd0a2fSth for (i = 0; serverList[i]; ++i) { 1746e1dd0a2fSth ; 1747e1dd0a2fSth } 1748e1dd0a2fSth srvListLength = i; 1749e1dd0a2fSth 1750e1dd0a2fSth thrPool = calloc(srvListLength, sizeof (thread_t)); 1751e1dd0a2fSth if (thrPool == NULL) { 1752e1dd0a2fSth __s_api_free2dArray(serverList); 1753e1dd0a2fSth return (NS_LDAP_MEMORY); 1754e1dd0a2fSth } 1755e1dd0a2fSth 1756e1dd0a2fSth *new_list = (dir_server_list_t *)calloc(1, 1757e1dd0a2fSth sizeof (dir_server_list_t)); 1758e1dd0a2fSth if (*new_list == NULL) { 1759e1dd0a2fSth __s_api_free2dArray(serverList); 1760e1dd0a2fSth free(thrPool); 1761e1dd0a2fSth return (NS_LDAP_MEMORY); 1762e1dd0a2fSth } 1763e1dd0a2fSth (void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL); 1764e1dd0a2fSth 1765e1dd0a2fSth (*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1, 1766e1dd0a2fSth sizeof (dir_server_t *)); 1767e1dd0a2fSth if ((*new_list)->nsServers == NULL) { 1768e1dd0a2fSth free(*new_list); 1769e1dd0a2fSth *new_list = NULL; 1770e1dd0a2fSth __s_api_free2dArray(serverList); 1771e1dd0a2fSth free(thrPool); 1772e1dd0a2fSth return (NS_LDAP_MEMORY); 1773e1dd0a2fSth } 1774e1dd0a2fSth 1775e1dd0a2fSth /* 1776e1dd0a2fSth * Allocate a set of dir_server_t structures as an array, 1777e1dd0a2fSth * with one alloc call and then initialize the nsServers pointers 1778e1dd0a2fSth * with the addresses of the array's members. 1779e1dd0a2fSth */ 1780e1dd0a2fSth tmpSrvArray = (dir_server_t *)calloc(srvListLength, 1781e1dd0a2fSth sizeof (dir_server_t)); 1782e1dd0a2fSth for (i = 0; i < srvListLength; ++i) { 1783e1dd0a2fSth (*new_list)->nsServers[i] = &tmpSrvArray[i]; 1784e1dd0a2fSth 1785e1dd0a2fSth (*new_list)->nsServers[i]->info = INFO_STATUS_NEW; 1786e1dd0a2fSth (void) mutex_init(&(*new_list)->nsServers[i]->updateStatus, 1787e1dd0a2fSth USYNC_THREAD, 1788e1dd0a2fSth NULL); 1789e1dd0a2fSth 1790e1dd0a2fSth (*new_list)->nsServers[i]->ip = strdup(serverList[i]); 1791e1dd0a2fSth if ((*new_list)->nsServers[i]->ip == NULL) { 1792e1dd0a2fSth retCode = NS_LDAP_MEMORY; 1793e1dd0a2fSth break; 1794e1dd0a2fSth } 1795e1dd0a2fSth 1796e1dd0a2fSth (*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING; 1797e1dd0a2fSth 1798e1dd0a2fSth switch (thr_create(NULL, 1799e1dd0a2fSth 0, 1800e1dd0a2fSth create_ns_servers_entry, 1801e1dd0a2fSth (*new_list)->nsServers[i], 1802e1dd0a2fSth 0, 1803e1dd0a2fSth &thrID)) { 1804e1dd0a2fSth case EAGAIN: 1805e1dd0a2fSth (*new_list)->nsServers[i]->status = 1806e1dd0a2fSth INFO_SERVER_ERROR; 1807e1dd0a2fSth continue; 1808e1dd0a2fSth break; 1809e1dd0a2fSth case ENOMEM: 1810e1dd0a2fSth (*new_list)->nsServers[i]->status = 1811e1dd0a2fSth INFO_SERVER_ERROR; 1812e1dd0a2fSth continue; 1813e1dd0a2fSth break; 1814e1dd0a2fSth default: 1815e1dd0a2fSth thrPool[i] = thrID; 1816e1dd0a2fSth continue; 1817e1dd0a2fSth break; 1818e1dd0a2fSth } 1819e1dd0a2fSth } 1820e1dd0a2fSth 1821e1dd0a2fSth for (i = 0; i < srvListLength; ++i) { 1822e1dd0a2fSth if (thrPool[i] != 0 && 1823e1dd0a2fSth thr_join(thrPool[i], NULL, &status) == 0) { 1824e1dd0a2fSth if (status == NULL) { 1825e1dd0a2fSth /* 1826e1dd0a2fSth * Some memory allocation problems occured. Just 1827e1dd0a2fSth * ignore the server and hope there will be some 1828e1dd0a2fSth * other good ones. 1829e1dd0a2fSth */ 1830e1dd0a2fSth (*new_list)->nsServers[i]->status = 1831e1dd0a2fSth INFO_SERVER_ERROR; 1832e1dd0a2fSth } 1833e1dd0a2fSth free(status); 1834e1dd0a2fSth } 1835e1dd0a2fSth } 1836e1dd0a2fSth 1837e1dd0a2fSth __s_api_free2dArray(serverList); 1838e1dd0a2fSth free(thrPool); 1839e1dd0a2fSth 1840e1dd0a2fSth if (retCode == NS_LDAP_MEMORY) { 1841e1dd0a2fSth (void) disposeOfOldList(*new_list); 1842e1dd0a2fSth return (NS_LDAP_MEMORY); 1843e1dd0a2fSth } 1844e1dd0a2fSth 1845e1dd0a2fSth return (NS_LDAP_SUCCESS); 1846e1dd0a2fSth } 1847e1dd0a2fSth 1848e1dd0a2fSth /* 1849e1dd0a2fSth * This functions replaces the local list of root DSEs with a new one and starts 1850e1dd0a2fSth * a thread destroying the old list. There is no need for other threads to wait 1851e1dd0a2fSth * until the old list will be destroyed. 1852e1dd0a2fSth * Since it is possible that more than one thread can start creating the list, 1853e1dd0a2fSth * this function should be protected by mutexes to be sure that only one thread 1854e1dd0a2fSth * performs the initialization. 1855e1dd0a2fSth */ 1856e1dd0a2fSth static 1857e1dd0a2fSth ns_ldap_return_code 1858e1dd0a2fSth initGlobalList(ns_ldap_error_t **error) 1859e1dd0a2fSth { 1860e1dd0a2fSth dir_server_list_t *new_list, *old_list; 1861e1dd0a2fSth ns_ldap_return_code ret_code; 1862e1dd0a2fSth thread_t tid; 1863e1dd0a2fSth 1864e1dd0a2fSth ret_code = createDirServerList(&new_list, error); 1865e1dd0a2fSth if (ret_code != NS_LDAP_SUCCESS) { 1866e1dd0a2fSth return (ret_code); 1867e1dd0a2fSth } 1868e1dd0a2fSth 1869e1dd0a2fSth old_list = dir_servers.list; 1870e1dd0a2fSth dir_servers.list = new_list; 1871e1dd0a2fSth 1872e1dd0a2fSth if (old_list) { 1873e1dd0a2fSth (void) thr_create(NULL, 1874e1dd0a2fSth 0, 1875e1dd0a2fSth disposeOfOldList, 1876e1dd0a2fSth old_list, 1877e1dd0a2fSth THR_DETACHED, 1878e1dd0a2fSth &tid); 1879e1dd0a2fSth } 1880e1dd0a2fSth 1881e1dd0a2fSth return (NS_LDAP_SUCCESS); 1882e1dd0a2fSth } 1883e1dd0a2fSth 1884e1dd0a2fSth static 1885e1dd0a2fSth struct { 1886e1dd0a2fSth char *authMech; 1887e1dd0a2fSth ns_auth_t auth; 1888e1dd0a2fSth } authArray[] = {{"none", {NS_LDAP_AUTH_NONE, 1889e1dd0a2fSth NS_LDAP_TLS_NONE, 1890e1dd0a2fSth NS_LDAP_SASL_NONE, 1891e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1892e1dd0a2fSth {"simple", {NS_LDAP_AUTH_SIMPLE, 1893e1dd0a2fSth NS_LDAP_TLS_NONE, 1894e1dd0a2fSth NS_LDAP_SASL_NONE, 1895e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1896e1dd0a2fSth {"tls:simple", {NS_LDAP_AUTH_TLS, 1897e1dd0a2fSth NS_LDAP_TLS_SIMPLE, 1898e1dd0a2fSth NS_LDAP_SASL_NONE, 1899e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1900e1dd0a2fSth {"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS, 1901e1dd0a2fSth NS_LDAP_TLS_SASL, 1902e1dd0a2fSth NS_LDAP_SASL_CRAM_MD5, 1903e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1904e1dd0a2fSth {"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS, 1905e1dd0a2fSth NS_LDAP_TLS_SASL, 1906e1dd0a2fSth NS_LDAP_SASL_DIGEST_MD5, 1907e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1908e1dd0a2fSth {"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL, 1909e1dd0a2fSth NS_LDAP_TLS_SASL, 1910e1dd0a2fSth NS_LDAP_SASL_CRAM_MD5, 1911e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1912e1dd0a2fSth {"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL, 1913e1dd0a2fSth NS_LDAP_TLS_SASL, 1914e1dd0a2fSth NS_LDAP_SASL_DIGEST_MD5, 1915e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}, 1916e1dd0a2fSth {"sasl/GSSAPI", {NS_LDAP_AUTH_SASL, 1917e1dd0a2fSth NS_LDAP_TLS_SASL, 1918e1dd0a2fSth NS_LDAP_SASL_GSSAPI, 1919e1dd0a2fSth NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}}, 1920e1dd0a2fSth {NULL, {NS_LDAP_AUTH_NONE, 1921e1dd0a2fSth NS_LDAP_TLS_NONE, 1922e1dd0a2fSth NS_LDAP_SASL_NONE, 1923e1dd0a2fSth NS_LDAP_SASLOPT_NONE}}}; 1924e1dd0a2fSth 1925e1dd0a2fSth ns_ldap_return_code 1926e1dd0a2fSth __ns_ldap_initAuth(const char *auth_mech, 1927e1dd0a2fSth ns_auth_t *auth, 1928e1dd0a2fSth ns_ldap_error_t **errorp) 1929e1dd0a2fSth { 1930e1dd0a2fSth uint32_t i; 1931e1dd0a2fSth char errmsg[MAXERROR]; 1932e1dd0a2fSth 1933e1dd0a2fSth if (auth_mech == NULL) { 1934e1dd0a2fSth (void) snprintf(errmsg, 1935e1dd0a2fSth sizeof (errmsg), 1936e1dd0a2fSth gettext("Invalid authentication method specified\n")); 1937e1dd0a2fSth MKERROR(LOG_WARNING, 1938e1dd0a2fSth *errorp, 1939e1dd0a2fSth NS_LDAP_INTERNAL, 1940e1dd0a2fSth strdup(errmsg), 1941e1dd0a2fSth NS_LDAP_MEMORY); 1942e1dd0a2fSth return (NS_LDAP_INTERNAL); 1943e1dd0a2fSth } 1944e1dd0a2fSth 1945e1dd0a2fSth for (i = 0; authArray[i].authMech != NULL; ++i) { 1946e1dd0a2fSth if (strcasecmp(auth_mech, authArray[i].authMech) == 0) { 1947e1dd0a2fSth *auth = authArray[i].auth; 1948e1dd0a2fSth return (NS_LDAP_SUCCESS); 1949e1dd0a2fSth } 1950e1dd0a2fSth } 1951e1dd0a2fSth 1952e1dd0a2fSth (void) snprintf(errmsg, 1953e1dd0a2fSth sizeof (errmsg), 1954e1dd0a2fSth gettext("Invalid authentication method specified\n")); 1955e1dd0a2fSth MKERROR(LOG_WARNING, 1956e1dd0a2fSth *errorp, 1957e1dd0a2fSth NS_LDAP_INTERNAL, 1958e1dd0a2fSth strdup(errmsg), 1959e1dd0a2fSth NS_LDAP_MEMORY); 1960e1dd0a2fSth return (NS_LDAP_INTERNAL); 1961e1dd0a2fSth } 1962e1dd0a2fSth 1963e1dd0a2fSth /* 1964e1dd0a2fSth * This function "informs" libsldap that a client application has specified 1965e1dd0a2fSth * a directory to use. The function obtains a DUAProfile, credentials, 1966e1dd0a2fSth * and naming context. During all further operations on behalf 1967e1dd0a2fSth * of the application requested a standalone schema libsldap will use 1968e1dd0a2fSth * the information obtained by __ns_ldap_initStandalone() instead of 1969e1dd0a2fSth * door_call(3C)ing ldap_cachemgr(1M). 1970e1dd0a2fSth * 1971e1dd0a2fSth * INPUT: 1972e1dd0a2fSth * sa_conf - a structure describing where and in which way to obtain all 1973e1dd0a2fSth * the configuration describing how to communicate to 1974e1dd0a2fSth * a choosen LDAP directory, 1975e1dd0a2fSth * errorp - an error object describing an error occured. 1976e1dd0a2fSth */ 1977e1dd0a2fSth ns_ldap_return_code 1978e1dd0a2fSth __ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf, 1979e1dd0a2fSth ns_ldap_error_t **errorp) { 1980e1dd0a2fSth 1981e1dd0a2fSth ns_cred_t user_cred = {{NS_LDAP_AUTH_NONE, 1982e1dd0a2fSth NS_LDAP_TLS_NONE, 1983e1dd0a2fSth NS_LDAP_SASL_NONE, 1984e1dd0a2fSth NS_LDAP_SASLOPT_NONE}, 1985e1dd0a2fSth NULL, 1986e1dd0a2fSth {NULL, NULL}}; 1987e1dd0a2fSth char *dua_profile = NULL; 1988e1dd0a2fSth char errmsg[MAXERROR]; 1989e1dd0a2fSth ns_config_t *cfg; 1990e1dd0a2fSth int ret_code; 1991e1dd0a2fSth 1992e1dd0a2fSth if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL || 1993e1dd0a2fSth sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) { 1994e1dd0a2fSth (void) snprintf(errmsg, 1995e1dd0a2fSth sizeof (errmsg), 1996e1dd0a2fSth gettext("Bind DN and bind password" 1997e1dd0a2fSth " must both be provided\n")); 1998e1dd0a2fSth MKERROR(LOG_ERR, 1999e1dd0a2fSth *errorp, 2000e1dd0a2fSth NS_CONFIG_NOTLOADED, 2001e1dd0a2fSth strdup(errmsg), 2002e1dd0a2fSth NS_LDAP_MEMORY); 2003e1dd0a2fSth return (NS_LDAP_INTERNAL); 2004e1dd0a2fSth } 2005e1dd0a2fSth 2006e1dd0a2fSth switch (sa_conf->type) { 2007e1dd0a2fSth case NS_LDAP_SERVER: 2008e1dd0a2fSth if (sa_conf->SA_BIND_DN != NULL) { 2009e1dd0a2fSth user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN; 2010e1dd0a2fSth user_cred.auth.type = NS_LDAP_AUTH_SIMPLE; 2011e1dd0a2fSth } 2012e1dd0a2fSth 2013e1dd0a2fSth if (sa_conf->SA_BIND_PWD != NULL) { 2014e1dd0a2fSth user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD; 2015e1dd0a2fSth } 2016e1dd0a2fSth 2017e1dd0a2fSth if (sa_conf->SA_AUTH != NULL) { 2018e1dd0a2fSth user_cred.auth.type = sa_conf->SA_AUTH->type; 2019e1dd0a2fSth user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype; 2020e1dd0a2fSth user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech; 2021e1dd0a2fSth user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt; 2022e1dd0a2fSth } 2023e1dd0a2fSth 2024e1dd0a2fSth if (sa_conf->SA_CERT_PATH != NULL) { 2025e1dd0a2fSth user_cred.hostcertpath = sa_conf->SA_CERT_PATH; 2026e1dd0a2fSth } 2027e1dd0a2fSth 2028e1dd0a2fSth ret_code = __ns_ldap_getConnectionInfoFromDUA( 2029e1dd0a2fSth &sa_conf->ds_profile.server, 2030e1dd0a2fSth &user_cred, 2031e1dd0a2fSth &dua_profile, 2032e1dd0a2fSth NULL, 2033e1dd0a2fSth errorp); 2034e1dd0a2fSth if (ret_code != NS_LDAP_SUCCESS) { 2035e1dd0a2fSth return (ret_code); 2036e1dd0a2fSth } 2037e1dd0a2fSth 2038e1dd0a2fSth cfg = __s_api_create_config_door_str(dua_profile, errorp); 2039e1dd0a2fSth if (cfg == NULL) { 2040e1dd0a2fSth free(dua_profile); 2041e1dd0a2fSth return (NS_LDAP_CONFIG); 2042e1dd0a2fSth } 2043e1dd0a2fSth 2044e1dd0a2fSth if (sa_conf->SA_CERT_PATH != NULL) { 2045e1dd0a2fSth char *certPathAttr; 2046e1dd0a2fSth ParamIndexType type; 2047e1dd0a2fSth 2048e1dd0a2fSth switch (cfg->version) { 2049e1dd0a2fSth case NS_LDAP_V1: 2050e1dd0a2fSth certPathAttr = "NS_LDAP_CERT_PATH"; 2051e1dd0a2fSth break; 2052e1dd0a2fSth default: /* Version 2 */ 2053e1dd0a2fSth certPathAttr = "NS_LDAP_HOST_CERTPATH"; 2054e1dd0a2fSth break; 2055e1dd0a2fSth } 2056e1dd0a2fSth 2057e1dd0a2fSth if (__s_api_get_versiontype(cfg, 2058e1dd0a2fSth certPathAttr, 2059e1dd0a2fSth &type) == 0 && 2060e1dd0a2fSth (ret_code = __ns_ldap_setParamValue(cfg, 2061e1dd0a2fSth type, 2062e1dd0a2fSth sa_conf->SA_CERT_PATH, 2063e1dd0a2fSth errorp)) != NS_LDAP_SUCCESS) { 2064e1dd0a2fSth __s_api_destroy_config(cfg); 2065e1dd0a2fSth return (ret_code); 2066e1dd0a2fSth } 2067e1dd0a2fSth } 2068e1dd0a2fSth 2069e1dd0a2fSth if (sa_conf->SA_BIND_DN != NULL && 2070e1dd0a2fSth sa_conf->SA_BIND_PWD != NULL) { 2071*434c5a06SMilan Jurik char *authMethods; 2072e1dd0a2fSth 2073*434c5a06SMilan Jurik authMethods = __s_api_strValue(cfg, NS_LDAP_AUTH_P, 2074e1dd0a2fSth NS_FILE_FMT); 2075e1dd0a2fSth if (authMethods != NULL && 2076e1dd0a2fSth strstr(authMethods, "sasl/GSSAPI") != NULL) { 2077e1dd0a2fSth /* 2078e1dd0a2fSth * The received DUAProfile specifies 2079e1dd0a2fSth * sasl/GSSAPI as an auth. mechanism. 2080e1dd0a2fSth * The bind DN and password will be 2081e1dd0a2fSth * ignored. 2082e1dd0a2fSth */ 2083e1dd0a2fSth syslog(LOG_INFO, gettext("sasl/GSSAPI will be " 2084e1dd0a2fSth "used as an authentication method. " 2085e1dd0a2fSth "The bind DN and password will " 2086e1dd0a2fSth "be ignored.\n")); 2087*434c5a06SMilan Jurik free(authMethods); 2088e1dd0a2fSth break; 2089e1dd0a2fSth } 2090e1dd0a2fSth 2091*434c5a06SMilan Jurik if (authMethods != NULL) 2092*434c5a06SMilan Jurik free(authMethods); 2093*434c5a06SMilan Jurik 2094e1dd0a2fSth if (__ns_ldap_setParamValue(cfg, 2095e1dd0a2fSth NS_LDAP_BINDDN_P, 2096e1dd0a2fSth sa_conf->SA_BIND_DN, 2097e1dd0a2fSth errorp) != NS_LDAP_SUCCESS) { 2098e1dd0a2fSth __s_api_destroy_config(cfg); 2099e1dd0a2fSth return (NS_LDAP_CONFIG); 2100e1dd0a2fSth } 2101e1dd0a2fSth 2102e1dd0a2fSth if (__ns_ldap_setParamValue(cfg, 2103e1dd0a2fSth NS_LDAP_BINDPASSWD_P, 2104e1dd0a2fSth sa_conf->SA_BIND_PWD, 2105e1dd0a2fSth errorp) != NS_LDAP_SUCCESS) { 2106e1dd0a2fSth __s_api_destroy_config(cfg); 2107e1dd0a2fSth return (NS_LDAP_CONFIG); 2108e1dd0a2fSth } 2109e1dd0a2fSth } 2110e1dd0a2fSth 2111e1dd0a2fSth break; 2112e1dd0a2fSth default: /* NS_CACHEMGR */ 2113e1dd0a2fSth return (NS_LDAP_SUCCESS); 2114e1dd0a2fSth } 2115e1dd0a2fSth 2116e1dd0a2fSth __s_api_init_config(cfg); 2117ca190d8dSmichen /* Connection management should use the new config now. */ 2118ca190d8dSmichen __s_api_reinit_conn_mgmt_new_config(cfg); 2119e1dd0a2fSth __ns_ldap_setServer(TRUE); 2120e1dd0a2fSth 2121e1dd0a2fSth (void) mutex_lock(&dir_servers.listReplaceLock); 2122e1dd0a2fSth if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) { 2123e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2124e1dd0a2fSth return (ret_code); 2125e1dd0a2fSth } 2126e1dd0a2fSth dir_servers.standalone = 1; 2127e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2128e1dd0a2fSth 2129e1dd0a2fSth return (NS_LDAP_SUCCESS); 2130e1dd0a2fSth } 2131e1dd0a2fSth 2132e1dd0a2fSth /* 2133e1dd0a2fSth * INPUT: 2134e1dd0a2fSth * serverAddr is the address of a server and 2135e1dd0a2fSth * request is one of the following: 2136e1dd0a2fSth * NS_CACHE_NEW: get a new server address, addr is ignored. 2137e1dd0a2fSth * NS_CACHE_NORESP: get the next one, remove addr from list. 2138e1dd0a2fSth * NS_CACHE_NEXT: get the next one, keep addr on list. 2139e1dd0a2fSth * NS_CACHE_WRITE: get a non-replica server, if possible, if not, same 2140e1dd0a2fSth * as NS_CACHE_NEXT. 2141e1dd0a2fSth * addrType: 2142e1dd0a2fSth * NS_CACHE_ADDR_IP: return server address as is, this is default. 2143e1dd0a2fSth * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only 2144e1dd0a2fSth * self credential case requires such format. 2145e1dd0a2fSth * OUTPUT: 2146e1dd0a2fSth * ret 2147e1dd0a2fSth * 2148e1dd0a2fSth * a structure of type ns_server_info_t containing the server address 2149e1dd0a2fSth * or name, server controls and supported SASL mechanisms. 2150e1dd0a2fSth * NOTE: Caller should allocate space for the structure and free 2151e1dd0a2fSth * all the space allocated by the function for the information contained 2152e1dd0a2fSth * in the structure. 2153e1dd0a2fSth * 2154e1dd0a2fSth * error - an error object describing an error, if any. 2155e1dd0a2fSth */ 2156e1dd0a2fSth ns_ldap_return_code 2157e1dd0a2fSth __s_api_findRootDSE(const char *request, 2158e1dd0a2fSth const char *serverAddr, 2159e1dd0a2fSth const char *addrType, 2160e1dd0a2fSth ns_server_info_t *ret, 2161e1dd0a2fSth ns_ldap_error_t **error) 2162e1dd0a2fSth { 2163e1dd0a2fSth dir_server_list_t *current_list = NULL; 2164e1dd0a2fSth ns_ldap_return_code ret_code; 2165e1dd0a2fSth long i = 0; 2166e1dd0a2fSth int matched = FALSE; 2167e1dd0a2fSth dir_server_t *server = NULL; 2168e1dd0a2fSth char errmsg[MAXERROR]; 2169e1dd0a2fSth 2170e1dd0a2fSth (void) mutex_lock(&dir_servers.listReplaceLock); 2171e1dd0a2fSth if (dir_servers.list == NULL) { 2172e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2173e1dd0a2fSth (void) snprintf(errmsg, 2174e1dd0a2fSth sizeof (errmsg), 2175e1dd0a2fSth gettext("The list of root DSEs is empty: " 2176e1dd0a2fSth "the Standalone mode was not properly initialized")); 2177e1dd0a2fSth MKERROR(LOG_ERR, 2178e1dd0a2fSth *error, 2179e1dd0a2fSth NS_CONFIG_NOTLOADED, 2180e1dd0a2fSth strdup(errmsg), 2181e1dd0a2fSth NS_LDAP_MEMORY); 2182e1dd0a2fSth return (NS_LDAP_INTERNAL); 2183e1dd0a2fSth } 2184e1dd0a2fSth 2185e1dd0a2fSth current_list = dir_servers.list; 2186e1dd0a2fSth (void) rw_rdlock(¤t_list->listDestroyLock); 2187e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2188e1dd0a2fSth 2189e1dd0a2fSth /* 2190e1dd0a2fSth * The code below is mostly the clone of the 2191e1dd0a2fSth * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function. 2192e1dd0a2fSth * Currently we have two different server lists: one is maintained 2193e1dd0a2fSth * by libsldap ('standalone' mode), the other is in ldap_cachemgr 2194e1dd0a2fSth * (a part of its standard functionality). 2195e1dd0a2fSth */ 2196e1dd0a2fSth 2197e1dd0a2fSth /* 2198e1dd0a2fSth * If NS_CACHE_NEW, or the server info is new, 2199e1dd0a2fSth * starts from the beginning of the list. 2200e1dd0a2fSth */ 2201e1dd0a2fSth (void) mutex_lock(¤t_list->nsServers[0]->updateStatus); 2202e1dd0a2fSth if (strcmp(request, NS_CACHE_NEW) == 0 || 2203e1dd0a2fSth current_list->nsServers[0]->info == INFO_STATUS_NEW) { 2204e1dd0a2fSth matched = TRUE; 2205e1dd0a2fSth } 2206e1dd0a2fSth (void) mutex_unlock(¤t_list->nsServers[i]->updateStatus); 2207e1dd0a2fSth 2208e1dd0a2fSth for (i = 0; current_list->nsServers[i]; ++i) { 2209e1dd0a2fSth /* 2210e1dd0a2fSth * Lock the updateStatus mutex to 2211e1dd0a2fSth * make sure the server status stays the same 2212e1dd0a2fSth * while the data is being processed. 2213e1dd0a2fSth */ 2214e1dd0a2fSth if (matched == FALSE && 2215e1dd0a2fSth strcmp(current_list->nsServers[i]->ip, 2216e1dd0a2fSth serverAddr) == 0) { 2217e1dd0a2fSth matched = TRUE; 2218e1dd0a2fSth if (strcmp(request, NS_CACHE_NORESP) == 0) { 2219e1dd0a2fSth 2220e1dd0a2fSth /* 2221e1dd0a2fSth * if the server has already been removed, 2222e1dd0a2fSth * don't bother. 2223e1dd0a2fSth */ 2224e1dd0a2fSth (void) mutex_lock(¤t_list-> 2225e1dd0a2fSth nsServers[i]->updateStatus); 2226e1dd0a2fSth if (current_list->nsServers[i]->status == 2227e1dd0a2fSth INFO_SERVER_REMOVED) { 2228e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2229e1dd0a2fSth nsServers[i]-> 2230e1dd0a2fSth updateStatus); 2231e1dd0a2fSth continue; 2232e1dd0a2fSth } 2233e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2234e1dd0a2fSth nsServers[i]-> 2235e1dd0a2fSth updateStatus); 2236e1dd0a2fSth 2237e1dd0a2fSth /* 2238e1dd0a2fSth * if the information is new, 2239e1dd0a2fSth * give this server one more chance. 2240e1dd0a2fSth */ 2241e1dd0a2fSth (void) mutex_lock(¤t_list-> 2242e1dd0a2fSth nsServers[i]-> 2243e1dd0a2fSth updateStatus); 2244e1dd0a2fSth if (current_list->nsServers[i]->info == 2245e1dd0a2fSth INFO_STATUS_NEW && 2246e1dd0a2fSth current_list->nsServers[i]->status == 2247e1dd0a2fSth INFO_SERVER_UP) { 2248e1dd0a2fSth server = current_list->nsServers[i]; 2249e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2250e1dd0a2fSth nsServers[i]-> 2251e1dd0a2fSth updateStatus); 2252e1dd0a2fSth break; 2253e1dd0a2fSth } else { 2254e1dd0a2fSth /* 2255e1dd0a2fSth * it is recommended that 2256e1dd0a2fSth * before removing the 2257e1dd0a2fSth * server from the list, 2258e1dd0a2fSth * the server should be 2259e1dd0a2fSth * contacted one more time 2260e1dd0a2fSth * to make sure that it is 2261e1dd0a2fSth * really unavailable. 2262e1dd0a2fSth * For now, just trust the client 2263e1dd0a2fSth * (i.e., the sldap library) 2264e1dd0a2fSth * that it knows what it is 2265e1dd0a2fSth * doing and would not try 2266e1dd0a2fSth * to mess up the server 2267e1dd0a2fSth * list. 2268e1dd0a2fSth */ 2269e1dd0a2fSth current_list->nsServers[i]->status = 2270e1dd0a2fSth INFO_SERVER_REMOVED; 2271e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2272e1dd0a2fSth nsServers[i]-> 2273e1dd0a2fSth updateStatus); 2274e1dd0a2fSth continue; 2275e1dd0a2fSth } 2276e1dd0a2fSth } else { 2277e1dd0a2fSth /* 2278e1dd0a2fSth * req == NS_CACHE_NEXT or NS_CACHE_WRITE 2279e1dd0a2fSth */ 2280e1dd0a2fSth continue; 2281e1dd0a2fSth } 2282e1dd0a2fSth } 2283e1dd0a2fSth 2284e1dd0a2fSth if (matched) { 2285e1dd0a2fSth if (strcmp(request, NS_CACHE_WRITE) == 0) { 2286e1dd0a2fSth /* 2287e1dd0a2fSth * ldap_cachemgr checks here if the server 2288e1dd0a2fSth * is not a non-replica server (a server 2289e1dd0a2fSth * of type INFO_RW_WRITEABLE). But currently 2290e1dd0a2fSth * it considers all the servers in its list 2291e1dd0a2fSth * as those. 2292e1dd0a2fSth */ 2293e1dd0a2fSth (void) mutex_lock(¤t_list-> 2294e1dd0a2fSth nsServers[i]-> 2295e1dd0a2fSth updateStatus); 2296e1dd0a2fSth if (current_list->nsServers[i]->status == 2297e1dd0a2fSth INFO_SERVER_UP) { 2298e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2299e1dd0a2fSth nsServers[i]-> 2300e1dd0a2fSth updateStatus); 2301e1dd0a2fSth server = current_list->nsServers[i]; 2302e1dd0a2fSth break; 2303e1dd0a2fSth } 2304e1dd0a2fSth } else { 2305e1dd0a2fSth (void) mutex_lock(¤t_list-> 2306e1dd0a2fSth nsServers[i]-> 2307e1dd0a2fSth updateStatus); 2308e1dd0a2fSth if (current_list->nsServers[i]->status == 2309e1dd0a2fSth INFO_SERVER_UP) { 2310e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2311e1dd0a2fSth nsServers[i]-> 2312e1dd0a2fSth updateStatus); 2313e1dd0a2fSth server = current_list->nsServers[i]; 2314e1dd0a2fSth break; 2315e1dd0a2fSth } 2316e1dd0a2fSth } 2317e1dd0a2fSth 2318e1dd0a2fSth (void) mutex_unlock(¤t_list-> 2319e1dd0a2fSth nsServers[i]-> 2320e1dd0a2fSth updateStatus); 2321e1dd0a2fSth } 2322e1dd0a2fSth } 2323e1dd0a2fSth 2324e1dd0a2fSth if (server == NULL) { 2325e1dd0a2fSth (void) rw_unlock(¤t_list->listDestroyLock); 2326e1dd0a2fSth (void) snprintf(errmsg, 2327e1dd0a2fSth sizeof (errmsg), 2328e1dd0a2fSth gettext("No servers are available")); 2329e1dd0a2fSth MKERROR(LOG_ERR, 2330e1dd0a2fSth *error, 2331e1dd0a2fSth NS_CONFIG_NOTLOADED, 2332e1dd0a2fSth strdup(errmsg), 2333e1dd0a2fSth NS_LDAP_MEMORY); 2334e1dd0a2fSth return (NS_LDAP_NOTFOUND); 2335e1dd0a2fSth } 2336e1dd0a2fSth 2337e1dd0a2fSth (void) mutex_lock(&server->updateStatus); 2338e1dd0a2fSth server->info = INFO_STATUS_OLD; 2339e1dd0a2fSth (void) mutex_unlock(&server->updateStatus); 2340e1dd0a2fSth 2341e1dd0a2fSth if (ret == NULL) { 2342e1dd0a2fSth (void) rw_unlock(¤t_list->listDestroyLock); 2343e1dd0a2fSth return (NS_LDAP_SUCCESS); 2344e1dd0a2fSth } 2345e1dd0a2fSth 2346e1dd0a2fSth if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 2347e1dd0a2fSth ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN); 2348e1dd0a2fSth if (ret_code != NS_LDAP_SUCCESS) { 2349e1dd0a2fSth (void) snprintf(errmsg, 2350e1dd0a2fSth sizeof (errmsg), 2351e1dd0a2fSth gettext("The %s address " 2352e1dd0a2fSth "can not be resolved into " 2353e1dd0a2fSth "a host name. Returning " 2354e1dd0a2fSth "the address as it is."), 2355e1dd0a2fSth server->ip); 2356e1dd0a2fSth MKERROR(LOG_ERR, 2357e1dd0a2fSth *error, 2358e1dd0a2fSth NS_CONFIG_NOTLOADED, 2359e1dd0a2fSth strdup(errmsg), 2360e1dd0a2fSth NS_LDAP_MEMORY); 2361e1dd0a2fSth return (NS_LDAP_INTERNAL); 2362e1dd0a2fSth } 2363e1dd0a2fSth } 2364e1dd0a2fSth 2365e1dd0a2fSth ret->server = strdup(server->ip); 2366e1dd0a2fSth 2367e1dd0a2fSth ret->controls = __s_api_cp2dArray(server->controls); 2368e1dd0a2fSth ret->saslMechanisms = __s_api_cp2dArray(server->saslMech); 2369e1dd0a2fSth 2370e1dd0a2fSth (void) rw_unlock(¤t_list->listDestroyLock); 2371e1dd0a2fSth 2372e1dd0a2fSth return (NS_LDAP_SUCCESS); 2373e1dd0a2fSth } 2374e1dd0a2fSth 2375e1dd0a2fSth /* 2376e1dd0a2fSth * This function iterates through the list of the configured LDAP servers 2377e1dd0a2fSth * and "pings" those which are marked as removed or if any error occurred 2378e1dd0a2fSth * during the previous receiving of the server's root DSE. If the 2379e1dd0a2fSth * function is able to reach such a server and get its root DSE, it 2380e1dd0a2fSth * marks the server as on-line. Otherwise, the server's status is set 2381e1dd0a2fSth * to "Error". 2382e1dd0a2fSth * For each server the function tries to connect to, it fires up 2383e1dd0a2fSth * a separate thread and then waits until all the treads finish. 2384e1dd0a2fSth * The function returns NS_LDAP_INTERNAL if the Standalone mode was not 2385e1dd0a2fSth * initialized or was canceled prior to an invocation of 2386e1dd0a2fSth * __ns_ldap_pingOfflineServers(). 2387e1dd0a2fSth */ 2388e1dd0a2fSth ns_ldap_return_code 2389e1dd0a2fSth __ns_ldap_pingOfflineServers(void) 2390e1dd0a2fSth { 2391e1dd0a2fSth dir_server_list_t *current_list = NULL; 2392e1dd0a2fSth ns_ldap_return_code retCode = NS_LDAP_SUCCESS; 2393e1dd0a2fSth long srvListLength, i = 0; 2394e1dd0a2fSth thread_t *thrPool, thrID; 2395e1dd0a2fSth void *status = NULL; 2396e1dd0a2fSth 2397e1dd0a2fSth (void) mutex_lock(&dir_servers.listReplaceLock); 2398e1dd0a2fSth if (dir_servers.list == NULL) { 2399e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2400e1dd0a2fSth return (NS_LDAP_INTERNAL); 2401e1dd0a2fSth } 2402e1dd0a2fSth 2403e1dd0a2fSth current_list = dir_servers.list; 2404e1dd0a2fSth (void) rw_wrlock(¤t_list->listDestroyLock); 2405e1dd0a2fSth (void) mutex_unlock(&dir_servers.listReplaceLock); 2406e1dd0a2fSth 2407e1dd0a2fSth while (current_list->nsServers[i] != NULL) { 2408e1dd0a2fSth ++i; 2409e1dd0a2fSth } 2410e1dd0a2fSth srvListLength = i; 2411e1dd0a2fSth 2412e1dd0a2fSth thrPool = calloc(srvListLength, sizeof (thread_t)); 2413e1dd0a2fSth if (thrPool == NULL) { 2414e1dd0a2fSth (void) rw_unlock(¤t_list->listDestroyLock); 2415e1dd0a2fSth return (NS_LDAP_MEMORY); 2416e1dd0a2fSth } 2417e1dd0a2fSth 2418e1dd0a2fSth for (i = 0; i < srvListLength; ++i) { 2419e1dd0a2fSth if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED && 2420e1dd0a2fSth current_list->nsServers[i]->status != INFO_SERVER_ERROR) { 2421e1dd0a2fSth continue; 2422e1dd0a2fSth } 2423e1dd0a2fSth current_list->nsServers[i]->status = INFO_SERVER_CONNECTING; 2424e1dd0a2fSth current_list->nsServers[i]->info = INFO_STATUS_NEW; 2425e1dd0a2fSth 2426e1dd0a2fSth __s_api_free2dArray(current_list->nsServers[i]->controls); 2427e1dd0a2fSth current_list->nsServers[i]->controls = NULL; 2428e1dd0a2fSth __s_api_free2dArray(current_list->nsServers[i]->saslMech); 2429e1dd0a2fSth current_list->nsServers[i]->saslMech = NULL; 2430e1dd0a2fSth 2431e1dd0a2fSth switch (thr_create(NULL, 2432e1dd0a2fSth 0, 2433e1dd0a2fSth create_ns_servers_entry, 2434e1dd0a2fSth current_list->nsServers[i], 2435e1dd0a2fSth 0, 2436e1dd0a2fSth &thrID)) { 2437e1dd0a2fSth case EAGAIN: 2438e1dd0a2fSth current_list->nsServers[i]->status = INFO_SERVER_ERROR; 2439e1dd0a2fSth continue; 2440e1dd0a2fSth break; 2441e1dd0a2fSth case ENOMEM: 2442e1dd0a2fSth current_list->nsServers[i]->status = INFO_SERVER_ERROR; 2443e1dd0a2fSth retCode = NS_LDAP_MEMORY; 2444e1dd0a2fSth break; 2445e1dd0a2fSth default: 2446e1dd0a2fSth thrPool[i] = thrID; 2447e1dd0a2fSth continue; 2448e1dd0a2fSth break; 2449e1dd0a2fSth } 2450e1dd0a2fSth /* A memory allocation error has occured */ 2451e1dd0a2fSth break; 2452e1dd0a2fSth 2453e1dd0a2fSth } 2454e1dd0a2fSth 2455e1dd0a2fSth for (i = 0; i < srvListLength; ++i) { 2456e1dd0a2fSth if (thrPool[i] != 0 && 2457e1dd0a2fSth thr_join(thrPool[i], NULL, &status) == 0) { 2458e1dd0a2fSth if (status == NULL) { 2459e1dd0a2fSth current_list->nsServers[i]->status = 2460e1dd0a2fSth INFO_SERVER_ERROR; 2461e1dd0a2fSth retCode = NS_LDAP_MEMORY; 2462e1dd0a2fSth } 2463e1dd0a2fSth free(status); 2464e1dd0a2fSth } 2465e1dd0a2fSth } 2466e1dd0a2fSth 2467e1dd0a2fSth (void) rw_unlock(¤t_list->listDestroyLock); 2468e1dd0a2fSth 2469e1dd0a2fSth free(thrPool); 2470e1dd0a2fSth 2471e1dd0a2fSth return (retCode); 2472e1dd0a2fSth } 2473