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