Print this page
3285 memory leaks in libsldap
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libsldap/common/ns_connect.c
+++ new/usr/src/lib/libsldap/common/ns_connect.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <stdlib.h>
27 28 #include <stdio.h>
28 29 #include <errno.h>
29 30 #include <string.h>
30 31 #include <synch.h>
31 32 #include <time.h>
32 33 #include <libintl.h>
33 34 #include <thread.h>
34 35 #include <syslog.h>
35 36 #include <sys/mman.h>
36 37 #include <nsswitch.h>
37 38 #include <nss_dbdefs.h>
38 39 #include "solaris-priv.h"
39 40 #include "solaris-int.h"
40 41 #include "ns_sldap.h"
41 42 #include "ns_internal.h"
42 43 #include "ns_cache_door.h"
43 44 #include "ns_connmgmt.h"
44 45 #include "ldappr.h"
45 46 #include <sys/stat.h>
46 47 #include <fcntl.h>
47 48 #include <procfs.h>
48 49 #include <unistd.h>
49 50
50 51 #define USE_DEFAULT_PORT 0
51 52
52 53 static ns_ldap_return_code performBind(const ns_cred_t *,
53 54 LDAP *,
54 55 int,
55 56 ns_ldap_error_t **,
56 57 int,
57 58 int);
58 59 static ns_ldap_return_code createSession(const ns_cred_t *,
59 60 const char *,
60 61 uint16_t,
61 62 int,
62 63 LDAP **,
63 64 ns_ldap_error_t **);
64 65
65 66 extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *,
66 67 LDAPControl **, LDAPControl **);
67 68 extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
68 69
69 70 extern int __door_getconf(char **buffer, int *buflen,
70 71 ns_ldap_error_t **error, int callnumber);
71 72 extern int __ns_ldap_freeUnixCred(UnixCred_t **credp);
72 73 extern int SetDoorInfoToUnixCred(char *buffer,
73 74 ns_ldap_error_t **errorp,
74 75 UnixCred_t **cred);
75 76
76 77 static int openConnection(LDAP **, const char *, const ns_cred_t *,
77 78 int, ns_ldap_error_t **, int, int, ns_conn_user_t *, int);
78 79 static void
79 80 _DropConnection(ConnectionID cID, int flag, int fini);
80 81
81 82 static mutex_t sessionPoolLock = DEFAULTMUTEX;
82 83
83 84 static Connection **sessionPool = NULL;
84 85 static int sessionPoolSize = 0;
85 86
86 87 /*
87 88 * SSF values are for SASL integrity & privacy.
88 89 * JES DS5.2 does not support this feature but DS6 does.
89 90 * The values between 0 and 65535 can work with both server versions.
90 91 */
91 92 #define MAX_SASL_SSF 65535
92 93 #define MIN_SASL_SSF 0
93 94
94 95 /* Number of hostnames to allocate memory for */
95 96 #define NUMTOMALLOC 32
96 97
97 98 /*
98 99 * This function get the servers from the lists and returns
99 100 * the first server with the empty lists of server controls and
100 101 * SASL mechanisms. It is invoked if it is not possible to obtain a server
101 102 * from ldap_cachemgr or the local list.
102 103 */
103 104 static
104 105 ns_ldap_return_code
105 106 getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error)
106 107 {
107 108 char **servers = NULL;
108 109 ns_ldap_return_code ret_code;
109 110 char errstr[MAXERROR];
110 111
111 112 /* get first server from config list unavailable otherwise */
112 113 ret_code = __s_api_getServers(&servers, error);
113 114 if (ret_code != NS_LDAP_SUCCESS) {
114 115 if (servers != NULL) {
115 116 __s_api_free2dArray(servers);
116 117 }
117 118 return (ret_code);
118 119 }
119 120
120 121 if (servers == NULL || servers[0] == NULL) {
121 122 __s_api_free2dArray(servers);
122 123 (void) sprintf(errstr,
123 124 gettext("No server found in configuration"));
124 125 MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT,
125 126 strdup(errstr), NS_LDAP_MEMORY);
126 127 return (NS_LDAP_CONFIG);
127 128 }
128 129
129 130 ret->server = strdup(servers[0]);
130 131 if (ret->server == NULL) {
131 132 __s_api_free2dArray(servers);
132 133 return (NS_LDAP_MEMORY);
133 134 }
134 135
135 136 ret->saslMechanisms = NULL;
136 137 ret->controls = NULL;
137 138
138 139 __s_api_free2dArray(servers);
139 140
140 141 return (NS_LDAP_SUCCESS);
141 142 }
142 143
143 144 /* very similar to __door_getldapconfig() in ns_config.c */
144 145 static int
145 146 __door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error)
146 147 {
147 148 return (__door_getconf(buffer, buflen, error, GETADMINCRED));
148 149 }
149 150
150 151 /*
151 152 * This function requests Admin credentials from the cache manager through
152 153 * the door functionality
153 154 */
154 155
155 156 static int
156 157 requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error)
157 158 {
158 159 char *buffer = NULL;
159 160 int buflen = 0;
160 161 int ret;
161 162
162 163 *error = NULL;
163 164 ret = __door_getadmincred(&buffer, &buflen, error);
164 165
165 166 if (ret != NS_LDAP_SUCCESS) {
166 167 if (*error != NULL && (*error)->message != NULL)
167 168 syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
168 169 return (ret);
169 170 }
170 171
171 172 /* now convert from door format */
172 173 ret = SetDoorInfoToUnixCred(buffer, error, cred);
173 174 free(buffer);
174 175
175 176 return (ret);
176 177 }
177 178
178 179 /*
179 180 * This function requests a server from the cache manager through
180 181 * the door functionality
181 182 */
182 183
183 184 int
184 185 __s_api_requestServer(const char *request, const char *server,
185 186 ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType)
186 187 {
187 188 union {
188 189 ldap_data_t s_d;
189 190 char s_b[DOORBUFFERSIZE];
190 191 } space;
191 192 ldap_data_t *sptr;
192 193 int ndata;
193 194 int adata;
194 195 char errstr[MAXERROR];
195 196 const char *ireq;
196 197 char *rbuf, *ptr, *rest;
197 198 char *dptr;
198 199 char **mptr, **mptr1, **cptr, **cptr1;
199 200 int mcnt, ccnt;
200 201 int len;
201 202 ns_ldap_return_code ret_code;
202 203
203 204 if (ret == NULL || error == NULL) {
204 205 return (NS_LDAP_OP_FAILED);
205 206 }
206 207 (void) memset(ret, 0, sizeof (ns_server_info_t));
207 208 *error = NULL;
208 209
209 210 if (request == NULL)
210 211 ireq = NS_CACHE_NEW;
211 212 else
212 213 ireq = request;
213 214
214 215 /*
215 216 * In the 'Standalone' mode a server will be obtained
216 217 * from the local libsldap's list
217 218 */
218 219 if (__s_api_isStandalone()) {
219 220 if ((ret_code = __s_api_findRootDSE(ireq,
220 221 server,
221 222 addrType,
222 223 ret,
223 224 error)) != NS_LDAP_SUCCESS) {
224 225 /*
225 226 * get first server from local list only once
226 227 * to prevent looping
227 228 */
228 229 if (strcmp(ireq, NS_CACHE_NEW) != 0)
229 230 return (ret_code);
230 231
231 232 syslog(LOG_WARNING,
232 233 "libsldap (\"standalone\" mode): "
233 234 "can not find any available server. "
234 235 "Return the first one from the lists");
235 236 if (*error != NULL) {
236 237 (void) __ns_ldap_freeError(error);
237 238 }
238 239
239 240 ret_code = getFirstFromConfig(ret, error);
240 241 if (ret_code != NS_LDAP_SUCCESS) {
241 242 return (ret_code);
242 243 }
243 244
244 245 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
245 246 ret_code = __s_api_ip2hostname(ret->server,
246 247 &ret->serverFQDN);
247 248 if (ret_code != NS_LDAP_SUCCESS) {
248 249 (void) snprintf(errstr,
249 250 sizeof (errstr),
250 251 gettext("The %s address "
251 252 "can not be resolved into "
252 253 "a host name. Returning "
253 254 "the address as it is."),
254 255 ret->server);
255 256 MKERROR(LOG_ERR,
256 257 *error,
257 258 NS_CONFIG_NOTLOADED,
258 259 strdup(errstr),
259 260 NS_LDAP_MEMORY);
260 261 free(ret->server);
261 262 ret->server = NULL;
262 263 return (NS_LDAP_INTERNAL);
263 264 }
264 265 }
265 266 }
266 267
267 268 return (NS_LDAP_SUCCESS);
268 269 }
269 270
270 271 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
271 272
272 273 adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1);
273 274 if (server != NULL) {
274 275 adata += strlen(DOORLINESEP) + 1;
275 276 adata += strlen(server) + 1;
276 277 }
277 278 ndata = sizeof (space);
278 279 len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
279 280 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
280 281 if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
281 282 return (NS_LDAP_MEMORY);
282 283 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >=
283 284 len)
284 285 return (NS_LDAP_MEMORY);
285 286 if (server != NULL) {
286 287 if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
287 288 DOORLINESEP, len) >= len)
288 289 return (NS_LDAP_MEMORY);
289 290 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server,
290 291 len) >= len)
291 292 return (NS_LDAP_MEMORY);
292 293 }
293 294 sptr = &space.s_d;
294 295
295 296 switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
296 297 case NS_CACHE_SUCCESS:
297 298 break;
298 299 /* this case is for when the $mgr is not running, but ldapclient */
299 300 /* is trying to initialize things */
300 301 case NS_CACHE_NOSERVER:
301 302 ret_code = getFirstFromConfig(ret, error);
302 303 if (ret_code != NS_LDAP_SUCCESS) {
303 304 return (ret_code);
304 305 }
305 306
306 307 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
307 308 ret_code = __s_api_ip2hostname(ret->server,
308 309 &ret->serverFQDN);
309 310 if (ret_code != NS_LDAP_SUCCESS) {
310 311 (void) snprintf(errstr,
311 312 sizeof (errstr),
312 313 gettext("The %s address "
313 314 "can not be resolved into "
314 315 "a host name. Returning "
315 316 "the address as it is."),
316 317 ret->server);
317 318 MKERROR(LOG_ERR,
318 319 *error,
319 320 NS_CONFIG_NOTLOADED,
320 321 strdup(errstr),
321 322 NS_LDAP_MEMORY);
322 323 free(ret->server);
323 324 ret->server = NULL;
324 325 return (NS_LDAP_INTERNAL);
325 326 }
326 327 }
327 328 return (NS_LDAP_SUCCESS);
328 329 case NS_CACHE_NOTFOUND:
329 330 default:
330 331 return (NS_LDAP_OP_FAILED);
331 332 }
332 333
333 334 /* copy info from door call return structure here */
334 335 rbuf = space.s_d.ldap_ret.ldap_u.config;
335 336
336 337 /* Get the host */
337 338 ptr = strtok_r(rbuf, DOORLINESEP, &rest);
338 339 if (ptr == NULL) {
339 340 (void) sprintf(errstr, gettext("No server returned from "
340 341 "ldap_cachemgr"));
341 342 MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
342 343 strdup(errstr), NS_LDAP_MEMORY);
343 344 return (NS_LDAP_OP_FAILED);
344 345 }
345 346 ret->server = strdup(ptr);
346 347 if (ret->server == NULL) {
347 348 return (NS_LDAP_MEMORY);
348 349 }
349 350 /* Get the host FQDN format */
350 351 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
351 352 ptr = strtok_r(NULL, DOORLINESEP, &rest);
352 353 if (ptr == NULL) {
353 354 (void) sprintf(errstr, gettext("No server FQDN format "
354 355 "returned from ldap_cachemgr"));
355 356 MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
356 357 strdup(errstr), NULL);
357 358 free(ret->server);
358 359 ret->server = NULL;
359 360 return (NS_LDAP_OP_FAILED);
360 361 }
361 362 ret->serverFQDN = strdup(ptr);
362 363 if (ret->serverFQDN == NULL) {
363 364 free(ret->server);
364 365 ret->server = NULL;
365 366 return (NS_LDAP_MEMORY);
366 367 }
367 368 }
368 369
369 370 /* get the Supported Controls/SASL mechs */
370 371 mptr = NULL;
371 372 mcnt = 0;
372 373 cptr = NULL;
373 374 ccnt = 0;
374 375 for (;;) {
375 376 ptr = strtok_r(NULL, DOORLINESEP, &rest);
376 377 if (ptr == NULL)
377 378 break;
378 379 if (strncasecmp(ptr, _SASLMECHANISM,
379 380 _SASLMECHANISM_LEN) == 0) {
380 381 dptr = strchr(ptr, '=');
381 382 if (dptr == NULL)
382 383 continue;
383 384 dptr++;
384 385 mptr1 = (char **)realloc((void *)mptr,
385 386 sizeof (char *) * (mcnt+2));
386 387 if (mptr1 == NULL) {
387 388 __s_api_free2dArray(mptr);
388 389 if (sptr != &space.s_d) {
389 390 (void) munmap((char *)sptr, ndata);
390 391 }
391 392 __s_api_free2dArray(cptr);
392 393 __s_api_free_server_info(ret);
393 394 return (NS_LDAP_MEMORY);
394 395 }
395 396 mptr = mptr1;
396 397 mptr[mcnt] = strdup(dptr);
397 398 if (mptr[mcnt] == NULL) {
398 399 if (sptr != &space.s_d) {
399 400 (void) munmap((char *)sptr, ndata);
400 401 }
401 402 __s_api_free2dArray(cptr);
402 403 cptr = NULL;
403 404 __s_api_free2dArray(mptr);
404 405 mptr = NULL;
405 406 __s_api_free_server_info(ret);
406 407 return (NS_LDAP_MEMORY);
407 408 }
408 409 mcnt++;
409 410 mptr[mcnt] = NULL;
410 411 }
411 412 if (strncasecmp(ptr, _SUPPORTEDCONTROL,
412 413 _SUPPORTEDCONTROL_LEN) == 0) {
413 414 dptr = strchr(ptr, '=');
414 415 if (dptr == NULL)
415 416 continue;
416 417 dptr++;
417 418 cptr1 = (char **)realloc((void *)cptr,
418 419 sizeof (char *) * (ccnt+2));
419 420 if (cptr1 == NULL) {
420 421 if (sptr != &space.s_d) {
421 422 (void) munmap((char *)sptr, ndata);
422 423 }
423 424 __s_api_free2dArray(cptr);
424 425 __s_api_free2dArray(mptr);
425 426 mptr = NULL;
426 427 __s_api_free_server_info(ret);
427 428 return (NS_LDAP_MEMORY);
428 429 }
429 430 cptr = cptr1;
430 431 cptr[ccnt] = strdup(dptr);
431 432 if (cptr[ccnt] == NULL) {
432 433 if (sptr != &space.s_d) {
433 434 (void) munmap((char *)sptr, ndata);
434 435 }
435 436 __s_api_free2dArray(cptr);
436 437 cptr = NULL;
437 438 __s_api_free2dArray(mptr);
438 439 mptr = NULL;
439 440 __s_api_free_server_info(ret);
440 441 return (NS_LDAP_MEMORY);
441 442 }
442 443 ccnt++;
443 444 cptr[ccnt] = NULL;
444 445 }
445 446 }
446 447 if (mptr != NULL) {
447 448 ret->saslMechanisms = mptr;
448 449 }
449 450 if (cptr != NULL) {
450 451 ret->controls = cptr;
451 452 }
452 453
453 454
454 455 /* clean up door call */
455 456 if (sptr != &space.s_d) {
456 457 (void) munmap((char *)sptr, ndata);
457 458 }
458 459 *error = NULL;
459 460
460 461 return (NS_LDAP_SUCCESS);
461 462 }
462 463
463 464
464 465 #ifdef DEBUG
465 466 /*
466 467 * printCred(): prints the credential structure
467 468 */
↓ open down ↓ |
434 lines elided |
↑ open up ↑ |
468 469 static void
469 470 printCred(FILE *fp, const ns_cred_t *cred)
470 471 {
471 472 thread_t t = thr_self();
472 473
473 474 if (cred == NULL) {
474 475 (void) fprintf(fp, "tid= %d: printCred: cred is NULL\n", t);
475 476 return;
476 477 }
477 478
478 - (void) fprintf(fp, "tid= %d: AuthType=%d", t, cred->auth.type);
479 - (void) fprintf(fp, "tid= %d: TlsType=%d", t, cred->auth.tlstype);
480 - (void) fprintf(fp, "tid= %d: SaslMech=%d", t, cred->auth.saslmech);
481 - (void) fprintf(fp, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt);
479 + (void) fprintf(fp, "tid= %d: AuthType=%d\n", t, cred->auth.type);
480 + (void) fprintf(fp, "tid= %d: TlsType=%d\n", t, cred->auth.tlstype);
481 + (void) fprintf(fp, "tid= %d: SaslMech=%d\n", t, cred->auth.saslmech);
482 + (void) fprintf(fp, "tid= %d: SaslOpt=%d\n", t, cred->auth.saslopt);
482 483 if (cred->hostcertpath)
483 484 (void) fprintf(fp, "tid= %d: hostCertPath=%s\n",
484 485 t, cred->hostcertpath);
485 486 if (cred->cred.unix_cred.userID)
486 487 (void) fprintf(fp, "tid= %d: userID=%s\n",
487 488 t, cred->cred.unix_cred.userID);
488 489 if (cred->cred.unix_cred.passwd)
489 490 (void) fprintf(fp, "tid= %d: passwd=%s\n",
490 491 t, cred->cred.unix_cred.passwd);
491 492 }
492 493
493 494 /*
494 495 * printConnection(): prints the connection structure
495 496 */
496 497 static void
497 498 printConnection(FILE *fp, Connection *con)
498 499 {
499 500 thread_t t = thr_self();
500 501
501 502 if (con == NULL)
502 503 return;
503 504
504 505 (void) fprintf(fp, "tid= %d: connectionID=%d\n", t, con->connectionId);
505 506 (void) fprintf(fp, "tid= %d: usedBit=%d\n", t, con->usedBit);
506 507 (void) fprintf(fp, "tid= %d: threadID=%d\n", t, con->threadID);
507 508 if (con->serverAddr) {
508 509 (void) fprintf(fp, "tid= %d: serverAddr=%s\n",
509 510 t, con->serverAddr);
510 511 }
511 512 printCred(fp, con->auth);
512 513 }
513 514 #endif
514 515
515 516 /*
516 517 * addConnection(): inserts a connection in the connection list.
517 518 * It will also sets use bit and the thread Id for the thread
518 519 * using the connection for the first time.
519 520 * Returns: -1 = failure, new Connection ID = success
520 521 */
521 522 static int
522 523 addConnection(Connection *con)
523 524 {
524 525 int i;
525 526
526 527 if (!con)
527 528 return (-1);
528 529 #ifdef DEBUG
529 530 (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
530 531 #endif /* DEBUG */
531 532 (void) mutex_lock(&sessionPoolLock);
532 533 if (sessionPool == NULL) {
533 534 sessionPoolSize = SESSION_CACHE_INC;
534 535 sessionPool = calloc(sessionPoolSize,
535 536 sizeof (Connection *));
536 537 if (!sessionPool) {
537 538 (void) mutex_unlock(&sessionPoolLock);
538 539 return (-1);
539 540 }
540 541 #ifdef DEBUG
541 542 (void) fprintf(stderr, "Initialized sessionPool\n");
542 543 #endif /* DEBUG */
543 544 }
544 545 for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
545 546 ;
546 547 if (i == sessionPoolSize) {
547 548 /* run out of array, need to increase sessionPool */
548 549 Connection **cl;
549 550 cl = (Connection **) realloc(sessionPool,
550 551 (sessionPoolSize + SESSION_CACHE_INC) *
551 552 sizeof (Connection *));
552 553 if (!cl) {
553 554 (void) mutex_unlock(&sessionPoolLock);
554 555 return (-1);
555 556 }
556 557 (void) memset(cl + sessionPoolSize, 0,
557 558 SESSION_CACHE_INC * sizeof (Connection *));
558 559 sessionPool = cl;
559 560 sessionPoolSize += SESSION_CACHE_INC;
560 561 #ifdef DEBUG
561 562 (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
562 563 sessionPoolSize);
563 564 #endif /* DEBUG */
564 565 }
565 566 sessionPool[i] = con;
566 567 con->usedBit = B_TRUE;
567 568 (void) mutex_unlock(&sessionPoolLock);
568 569 con->connectionId = i + CONID_OFFSET;
569 570 #ifdef DEBUG
570 571 (void) fprintf(stderr, "Connection added [%d]\n", i);
571 572 printConnection(stderr, con);
572 573 #endif /* DEBUG */
573 574 return (i + CONID_OFFSET);
574 575 }
575 576
576 577 /*
577 578 * findConnection(): find an available connection from the list
578 579 * that matches the criteria specified in Connection structure.
579 580 * If serverAddr is NULL, then find a connection to any server
580 581 * as long as it matches the rest of the parameters.
581 582 * Returns: -1 = failure, the Connection ID found = success.
582 583 */
583 584 static int
584 585 findConnection(int flags, const char *serverAddr,
585 586 const ns_cred_t *auth, Connection **conp)
586 587 {
587 588 Connection *cp;
588 589 int i;
589 590 #ifdef DEBUG
590 591 thread_t t;
591 592 #endif /* DEBUG */
592 593
593 594 if (auth == NULL || conp == NULL)
594 595 return (-1);
595 596 *conp = NULL;
596 597
597 598 /*
598 599 * If a new connection is requested, no need to continue.
599 600 * If the process is not nscd and is not requesting keep
600 601 * connections alive, no need to continue.
601 602 */
602 603 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() &&
603 604 !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN)))
604 605 return (-1);
605 606
606 607 #ifdef DEBUG
607 608 t = thr_self();
608 609 (void) fprintf(stderr, "tid= %d: Find connection\n", t);
609 610 (void) fprintf(stderr, "tid= %d: Looking for ....\n", t);
610 611 if (serverAddr && *serverAddr)
611 612 (void) fprintf(stderr, "tid= %d: serverAddr=%s\n",
612 613 t, serverAddr);
613 614 else
614 615 (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t);
615 616 printCred(stderr, auth);
616 617 fflush(stderr);
617 618 #endif /* DEBUG */
618 619 if (sessionPool == NULL)
619 620 return (-1);
620 621 (void) mutex_lock(&sessionPoolLock);
621 622 for (i = 0; i < sessionPoolSize; ++i) {
622 623 if (sessionPool[i] == NULL)
623 624 continue;
624 625 cp = sessionPool[i];
625 626 #ifdef DEBUG
626 627 (void) fprintf(stderr,
627 628 "tid: %d: checking connection [%d] ....\n", t, i);
628 629 printConnection(stderr, cp);
629 630 #endif /* DEBUG */
630 631 if ((cp->usedBit) || (serverAddr && *serverAddr &&
631 632 (strcasecmp(serverAddr, cp->serverAddr) != 0)))
632 633 continue;
633 634
634 635 if (__s_api_is_auth_matched(cp->auth, auth) == B_FALSE)
635 636 continue;
636 637
637 638 /* found an available connection */
638 639 cp->usedBit = B_TRUE;
639 640 (void) mutex_unlock(&sessionPoolLock);
640 641 cp->threadID = thr_self();
641 642 *conp = cp;
642 643 #ifdef DEBUG
643 644 (void) fprintf(stderr,
644 645 "tid %d: Connection found cID=%d\n", t, i);
645 646 fflush(stderr);
646 647 #endif /* DEBUG */
647 648 return (i + CONID_OFFSET);
648 649 }
649 650 (void) mutex_unlock(&sessionPoolLock);
650 651 return (-1);
651 652 }
652 653
653 654 /*
654 655 * Free a Connection structure
655 656 */
656 657 void
657 658 __s_api_freeConnection(Connection *con)
658 659 {
659 660 if (con == NULL)
660 661 return;
661 662 if (con->serverAddr)
662 663 free(con->serverAddr);
663 664 if (con->auth)
664 665 (void) __ns_ldap_freeCred(&(con->auth));
665 666 if (con->saslMechanisms) {
666 667 __s_api_free2dArray(con->saslMechanisms);
667 668 }
668 669 if (con->controls) {
669 670 __s_api_free2dArray(con->controls);
670 671 }
671 672 free(con);
672 673 }
673 674
674 675 /*
675 676 * Find a connection matching the passed in criteria. If an open
676 677 * connection with that criteria exists use it, otherwise open a
677 678 * new connection.
678 679 * Success: returns the pointer to the Connection structure
679 680 * Failure: returns NULL, error code and message should be in errorp
680 681 */
681 682
682 683 static int
683 684 makeConnection(Connection **conp, const char *serverAddr,
684 685 const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
685 686 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd,
686 687 int nopasswd_acct_mgmt, int flags, char ***badsrvrs,
687 688 ns_conn_user_t *conn_user)
688 689 {
689 690 Connection *con = NULL;
690 691 ConnectionID id;
691 692 char errmsg[MAXERROR];
692 693 int rc, exit_rc = NS_LDAP_SUCCESS;
693 694 ns_server_info_t sinfo;
↓ open down ↓ |
202 lines elided |
↑ open up ↑ |
694 695 char *hReq, *host = NULL;
695 696 LDAP *ld = NULL;
696 697 int passwd_mgmt = 0;
697 698 int totalbad = 0; /* Number of servers contacted unsuccessfully */
698 699 short memerr = 0; /* Variable for tracking memory allocation */
699 700 char *serverAddrType = NULL, **bindHost = NULL;
700 701
701 702
702 703 if (conp == NULL || errorp == NULL || auth == NULL)
703 704 return (NS_LDAP_INVALID_PARAM);
704 - *errorp = NULL;
705 + if (*errorp)
706 + __ns_ldap_freeError(errorp);
705 707 *conp = NULL;
706 708 (void) memset(&sinfo, 0, sizeof (sinfo));
707 709
708 710 if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) {
709 711 /* connection found in cache */
710 712 #ifdef DEBUG
711 713 (void) fprintf(stderr, "tid= %d: connection found in "
712 714 "cache %d\n", thr_self(), id);
713 715 fflush(stderr);
714 716 #endif /* DEBUG */
715 717 *cID = id;
716 718 *conp = con;
717 719 return (NS_LDAP_SUCCESS);
718 720 }
719 721
720 722 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
721 723 serverAddrType = NS_CACHE_ADDR_HOSTNAME;
722 724 bindHost = &sinfo.serverFQDN;
723 725 } else {
724 726 serverAddrType = NS_CACHE_ADDR_IP;
725 727 bindHost = &sinfo.server;
726 728 }
727 729
728 730 if (serverAddr) {
729 731 if (__s_api_isInitializing()) {
730 732 /*
731 733 * When obtaining the root DSE, connect to the server
732 734 * passed here through the serverAddr parameter
733 735 */
734 736 sinfo.server = strdup(serverAddr);
735 737 if (sinfo.server == NULL)
736 738 return (NS_LDAP_MEMORY);
737 739 if (strcmp(serverAddrType,
738 740 NS_CACHE_ADDR_HOSTNAME) == 0) {
739 741 rc = __s_api_ip2hostname(sinfo.server,
740 742 &sinfo.serverFQDN);
741 743 if (rc != NS_LDAP_SUCCESS) {
742 744 (void) snprintf(errmsg,
743 745 sizeof (errmsg),
744 746 gettext("The %s address "
745 747 "can not be resolved into "
746 748 "a host name. Returning "
747 749 "the address as it is."),
748 750 serverAddr);
749 751 MKERROR(LOG_ERR,
750 752 *errorp,
751 753 NS_CONFIG_NOTLOADED,
752 754 strdup(errmsg),
753 755 NS_LDAP_MEMORY);
754 756 __s_api_free_server_info(&sinfo);
755 757 return (NS_LDAP_INTERNAL);
756 758 }
757 759 }
758 760 } else {
759 761 /*
760 762 * We're given the server address, just use it.
761 763 * In case of sasl/GSSAPI, serverAddr would need
762 764 * to be a FQDN. We assume this is the case for now.
763 765 *
764 766 * Only the server address fields of sinfo structure
765 767 * are filled in since these are the only relevant
766 768 * data that we have. Other fields of this structure
767 769 * (controls, saslMechanisms) are kept to NULL.
768 770 */
769 771 sinfo.server = strdup(serverAddr);
770 772 if (sinfo.server == NULL) {
771 773 return (NS_LDAP_MEMORY);
772 774 }
773 775 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
774 776 sinfo.serverFQDN = strdup(serverAddr);
775 777 if (sinfo.serverFQDN == NULL) {
776 778 free(sinfo.server);
777 779 return (NS_LDAP_MEMORY);
778 780 }
779 781 }
780 782 }
781 783 rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
782 784 fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
783 785 if (rc == NS_LDAP_SUCCESS || rc ==
784 786 NS_LDAP_SUCCESS_WITH_INFO) {
785 787 exit_rc = rc;
786 788 goto create_con;
787 789 } else {
788 790 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
789 791 (void) snprintf(errmsg, sizeof (errmsg),
790 792 "%s %s", gettext("makeConnection: "
791 793 "failed to open connection using "
792 794 "sasl/GSSAPI to"), *bindHost);
793 795 } else {
794 796 (void) snprintf(errmsg, sizeof (errmsg),
795 797 "%s %s", gettext("makeConnection: "
796 798 "failed to open connection to"),
797 799 *bindHost);
798 800 }
799 801 syslog(LOG_ERR, "libsldap: %s", errmsg);
800 802 __s_api_free_server_info(&sinfo);
801 803 return (rc);
802 804 }
803 805 }
804 806
805 807 /* No cached connection, create one */
806 808 for (; ; ) {
807 809 if (host == NULL)
808 810 hReq = NS_CACHE_NEW;
809 811 else
810 812 hReq = NS_CACHE_NEXT;
811 813 rc = __s_api_requestServer(hReq, host, &sinfo, errorp,
812 814 serverAddrType);
813 815 if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
814 816 (host && (strcasecmp(host, sinfo.server) == 0))) {
815 817 /* Log the error */
816 818 if (*errorp) {
817 819 (void) snprintf(errmsg, sizeof (errmsg),
818 820 "%s: (%s)", gettext("makeConnection: "
819 821 "unable to make LDAP connection, "
820 822 "request for a server failed"),
821 823 (*errorp)->message);
822 824 syslog(LOG_ERR, "libsldap: %s", errmsg);
823 825 }
824 826
825 827 __s_api_free_server_info(&sinfo);
826 828 if (host)
827 829 free(host);
828 830 return (NS_LDAP_OP_FAILED);
829 831 }
830 832 if (host)
831 833 free(host);
832 834 host = strdup(sinfo.server);
833 835 if (host == NULL) {
834 836 __s_api_free_server_info(&sinfo);
835 837 return (NS_LDAP_MEMORY);
836 838 }
837 839
838 840 /* check if server supports password management */
839 841 passwd_mgmt = __s_api_contain_passwd_control_oid(
840 842 sinfo.controls);
841 843 /* check if server supports password less account mgmt */
842 844 if (nopasswd_acct_mgmt &&
843 845 !__s_api_contain_account_usable_control_oid(
844 846 sinfo.controls)) {
845 847 syslog(LOG_WARNING, "libsldap: server %s does not "
846 848 "provide account information without password",
847 849 host);
848 850 free(host);
849 851 __s_api_free_server_info(&sinfo);
850 852 return (NS_LDAP_OP_FAILED);
851 853 }
852 854 /* make the connection */
853 855 rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
854 856 fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
855 857 /* if success, go to create connection structure */
856 858 if (rc == NS_LDAP_SUCCESS ||
857 859 rc == NS_LDAP_SUCCESS_WITH_INFO) {
858 860 exit_rc = rc;
859 861 break;
860 862 }
861 863
862 864 /*
863 865 * If not able to reach the server, inform the ldap
864 866 * cache manager that the server should be removed
865 867 * from its server list. Thus, the manager will not
866 868 * return this server on the next get-server request
867 869 * and will also reduce the server list refresh TTL,
868 870 * so that it will find out sooner when the server
869 871 * is up again.
870 872 */
871 873 if (rc == NS_LDAP_INTERNAL && *errorp != NULL) {
872 874 if ((*errorp)->status == LDAP_CONNECT_ERROR ||
873 875 (*errorp)->status == LDAP_SERVER_DOWN) {
874 876 /* Reset memory allocation error */
875 877 memerr = 0;
876 878 /*
877 879 * We contacted a server that we could
878 880 * not either authenticate to or contact.
879 881 * If it is due to authentication, then
880 882 * we need to try the server again. So,
881 883 * do not remove the server yet, but
882 884 * add it to the bad server list.
883 885 * The caller routine will remove
884 886 * the servers if:
885 887 * a). A good server is found or
886 888 * b). All the possible methods
887 889 * are tried without finding
888 890 * a good server
889 891 */
890 892 if (*badsrvrs == NULL) {
891 893 if (!(*badsrvrs = (char **)malloc
892 894 (sizeof (char *) * NUMTOMALLOC))) {
893 895 memerr = 1;
894 896 }
895 897 /* Allocate memory in chunks of NUMTOMALLOC */
896 898 } else if ((totalbad % NUMTOMALLOC) ==
897 899 NUMTOMALLOC - 1) {
898 900 char **tmpptr;
899 901 if (!(tmpptr = (char **)realloc(
900 902 *badsrvrs,
901 903 (sizeof (char *) * NUMTOMALLOC *
902 904 ((totalbad/NUMTOMALLOC) + 2))))) {
903 905 memerr = 1;
904 906 } else {
905 907 *badsrvrs = tmpptr;
906 908 }
907 909 }
908 910 /*
909 911 * Store host only if there were no unsuccessful
910 912 * memory allocations above
911 913 */
912 914 if (!memerr &&
913 915 !((*badsrvrs)[totalbad++] = strdup(host))) {
914 916 memerr = 1;
915 917 totalbad--;
916 918 }
917 919 (*badsrvrs)[totalbad] = NULL;
918 920 }
919 921 }
920 922
921 923 /* else, cleanup and go for the next server */
922 924 __s_api_free_server_info(&sinfo);
923 925
924 926 /* Return if we had memory allocation errors */
925 927 if (memerr)
926 928 return (NS_LDAP_MEMORY);
927 929 if (*errorp) {
928 930 /*
929 931 * If openConnection() failed due to
930 932 * password policy, or invalid credential,
931 933 * keep *errorp and exit
932 934 */
933 935 if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD ||
934 936 (*errorp)->status == LDAP_INVALID_CREDENTIALS) {
935 937 free(host);
936 938 return (rc);
937 939 } else {
938 940 (void) __ns_ldap_freeError(errorp);
939 941 *errorp = NULL;
940 942 }
941 943 }
942 944 }
943 945
944 946 create_con:
945 947 /* we have created ld, setup con structure */
946 948 if (host)
947 949 free(host);
948 950 if ((con = calloc(1, sizeof (Connection))) == NULL) {
949 951 __s_api_free_server_info(&sinfo);
950 952 /*
951 953 * If password control attached in **errorp,
952 954 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
953 955 * free the error structure
954 956 */
955 957 if (*errorp) {
956 958 (void) __ns_ldap_freeError(errorp);
957 959 *errorp = NULL;
958 960 }
959 961 (void) ldap_unbind(ld);
960 962 return (NS_LDAP_MEMORY);
961 963 }
962 964
963 965 con->serverAddr = sinfo.server; /* Store original format */
964 966 if (sinfo.serverFQDN != NULL) {
965 967 free(sinfo.serverFQDN);
966 968 sinfo.serverFQDN = NULL;
967 969 }
968 970 con->saslMechanisms = sinfo.saslMechanisms;
969 971 con->controls = sinfo.controls;
970 972
971 973 con->auth = __ns_ldap_dupAuth(auth);
972 974 if (con->auth == NULL) {
973 975 (void) ldap_unbind(ld);
974 976 __s_api_freeConnection(con);
975 977 /*
976 978 * If password control attached in **errorp,
977 979 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
978 980 * free the error structure
979 981 */
980 982 if (*errorp) {
981 983 (void) __ns_ldap_freeError(errorp);
982 984 *errorp = NULL;
983 985 }
984 986 return (NS_LDAP_MEMORY);
985 987 }
986 988
987 989 con->threadID = thr_self();
988 990 con->pid = getpid();
989 991
990 992 con->ld = ld;
991 993 /* add MT connection to the MT connection pool */
992 994 if (conn_user != NULL && conn_user->conn_mt != NULL) {
993 995 if (__s_api_conn_mt_add(con, conn_user, errorp) ==
994 996 NS_LDAP_SUCCESS) {
995 997 *conp = con;
996 998 return (exit_rc);
997 999 } else {
998 1000 (void) ldap_unbind(ld);
999 1001 __s_api_freeConnection(con);
1000 1002 return ((*errorp)->status);
1001 1003 }
1002 1004 }
1003 1005
1004 1006 /* MT connection not supported or not required case */
1005 1007 if ((id = addConnection(con)) == -1) {
1006 1008 (void) ldap_unbind(ld);
1007 1009 __s_api_freeConnection(con);
1008 1010 /*
1009 1011 * If password control attached in **errorp,
1010 1012 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1011 1013 * free the error structure
1012 1014 */
1013 1015 if (*errorp) {
1014 1016 (void) __ns_ldap_freeError(errorp);
1015 1017 *errorp = NULL;
1016 1018 }
1017 1019 return (NS_LDAP_MEMORY);
1018 1020 }
1019 1021 #ifdef DEBUG
1020 1022 (void) fprintf(stderr, "tid= %d: connection added into "
1021 1023 "cache %d\n", thr_self(), id);
1022 1024 fflush(stderr);
1023 1025 #endif /* DEBUG */
1024 1026 *cID = id;
1025 1027 *conp = con;
1026 1028 return (exit_rc);
1027 1029 }
1028 1030
1029 1031 /*
1030 1032 * Return the specified connection to the pool. If necessary
1031 1033 * delete the connection.
1032 1034 */
1033 1035
1034 1036 static void
1035 1037 _DropConnection(ConnectionID cID, int flag, int fini)
1036 1038 {
1037 1039 Connection *cp;
1038 1040 int id;
1039 1041 int use_mutex = !fini;
1040 1042 struct timeval zerotime;
1041 1043 LDAPMessage *res;
1042 1044
1043 1045 zerotime.tv_sec = zerotime.tv_usec = 0L;
1044 1046
1045 1047 id = cID - CONID_OFFSET;
1046 1048 if (id < 0 || id >= sessionPoolSize)
1047 1049 return;
1048 1050 #ifdef DEBUG
1049 1051 (void) fprintf(stderr,
1050 1052 "tid %d: Dropping connection cID=%d flag=0x%x\n",
1051 1053 thr_self(), cID, flag);
1052 1054 fflush(stderr);
1053 1055 #endif /* DEBUG */
1054 1056 if (use_mutex)
1055 1057 (void) mutex_lock(&sessionPoolLock);
1056 1058
1057 1059 cp = sessionPool[id];
1058 1060 /* sanity check before removing */
1059 1061 if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
1060 1062 if (use_mutex)
1061 1063 (void) mutex_unlock(&sessionPoolLock);
1062 1064 return;
1063 1065 }
1064 1066
1065 1067 if (!fini &&
1066 1068 ((flag & NS_LDAP_NEW_CONN) == 0) &&
1067 1069 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() ||
1068 1070 __s_api_peruser_proc())) {
1069 1071 /* release Connection (keep alive) */
1070 1072 cp->usedBit = B_FALSE;
1071 1073 cp->threadID = 0; /* unmark the threadID */
1072 1074 /*
1073 1075 * Do sanity cleanup of remaining results.
1074 1076 */
1075 1077 while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL,
1076 1078 &zerotime, &res) > 0) {
1077 1079 if (res != NULL)
1078 1080 (void) ldap_msgfree(res);
1079 1081 }
1080 1082 if (use_mutex)
1081 1083 (void) mutex_unlock(&sessionPoolLock);
1082 1084 } else {
1083 1085 /* delete Connection (disconnect) */
1084 1086 sessionPool[id] = NULL;
1085 1087 if (use_mutex)
1086 1088 (void) mutex_unlock(&sessionPoolLock);
1087 1089 (void) ldap_unbind(cp->ld);
1088 1090 __s_api_freeConnection(cp);
1089 1091 }
1090 1092 }
1091 1093
1092 1094 void
1093 1095 DropConnection(ConnectionID cID, int flag)
1094 1096 {
1095 1097 _DropConnection(cID, flag, 0);
1096 1098 }
1097 1099
1098 1100 /*
1099 1101 * This routine is called after a bind operation is
1100 1102 * done in openConnection() to process the password
1101 1103 * management information, if any.
1102 1104 *
1103 1105 * Input:
1104 1106 * bind_type: "simple" or "sasl/DIGEST-MD5"
1105 1107 * ldaprc : ldap rc from the ldap bind operation
1106 1108 * controls : controls returned by the server
1107 1109 * errmsg : error message from the server
1108 1110 * fail_if_new_pwd_reqd:
1109 1111 * flag indicating if connection should be open
1110 1112 * when password needs to change immediately
1111 1113 * passwd_mgmt:
1112 1114 * flag indicating if server supports password
1113 1115 * policy/management
1114 1116 *
1115 1117 * Output : ns_ldap_error structure, which may contain
1116 1118 * password status and number of seconds until
1117 1119 * expired
1118 1120 *
1119 1121 * return rc:
1120 1122 * NS_LDAP_EXTERNAL: error, connection should not open
1121 1123 * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
1122 1124 * NS_LDAP_SUCCESS: OK to open connection
1123 1125 *
1124 1126 */
1125 1127
1126 1128 static int
1127 1129 process_pwd_mgmt(char *bind_type, int ldaprc,
1128 1130 LDAPControl **controls,
1129 1131 char *errmsg, ns_ldap_error_t **errorp,
1130 1132 int fail_if_new_pwd_reqd,
1131 1133 int passwd_mgmt)
1132 1134 {
1133 1135 char errstr[MAXERROR];
1134 1136 LDAPControl **ctrl = NULL;
1135 1137 int exit_rc;
1136 1138 ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD;
1137 1139 int sec_until_exp = 0;
1138 1140
1139 1141 /*
1140 1142 * errmsg may be an empty string,
1141 1143 * even if ldaprc is LDAP_SUCCESS,
1142 1144 * free the empty string if that's the case
1143 1145 */
1144 1146 if (errmsg &&
1145 1147 (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) {
1146 1148 ldap_memfree(errmsg);
1147 1149 errmsg = NULL;
1148 1150 }
1149 1151
1150 1152 if (ldaprc != LDAP_SUCCESS) {
1151 1153 /*
1152 1154 * try to map ldap rc and error message to
1153 1155 * a password status
1154 1156 */
1155 1157 if (errmsg) {
1156 1158 if (passwd_mgmt)
1157 1159 pwd_status =
1158 1160 __s_api_set_passwd_status(
1159 1161 ldaprc, errmsg);
1160 1162 ldap_memfree(errmsg);
1161 1163 }
1162 1164
1163 1165 (void) snprintf(errstr, sizeof (errstr),
1164 1166 gettext("openConnection: "
1165 1167 "%s bind failed "
1166 1168 "- %s"), bind_type, ldap_err2string(ldaprc));
1167 1169
1168 1170 if (pwd_status != NS_PASSWD_GOOD) {
1169 1171 MKERROR_PWD_MGMT(*errorp,
1170 1172 ldaprc, strdup(errstr),
1171 1173 pwd_status, 0, NULL);
1172 1174 } else {
1173 1175 MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr),
1174 1176 NS_LDAP_MEMORY);
1175 1177 }
1176 1178 if (controls)
1177 1179 ldap_controls_free(controls);
1178 1180
1179 1181 return (NS_LDAP_INTERNAL);
1180 1182 }
1181 1183
1182 1184 /*
1183 1185 * ldaprc is LDAP_SUCCESS,
1184 1186 * process the password management controls, if any
1185 1187 */
1186 1188 exit_rc = NS_LDAP_SUCCESS;
1187 1189 if (controls && passwd_mgmt) {
1188 1190 /*
1189 1191 * The control with the OID
1190 1192 * 2.16.840.1.113730.3.4.4 (or
1191 1193 * LDAP_CONTROL_PWEXPIRED, as defined
1192 1194 * in the ldap.h header file) is the
1193 1195 * expired password control.
1194 1196 *
1195 1197 * This control is used if the server
1196 1198 * is configured to require users to
1197 1199 * change their passwords when first
1198 1200 * logging in and whenever the
1199 1201 * passwords are reset.
1200 1202 *
1201 1203 * If the user is logging in for the
1202 1204 * first time or if the user's
1203 1205 * password has been reset, the
1204 1206 * server sends this control to
1205 1207 * indicate that the client needs to
1206 1208 * change the password immediately.
1207 1209 *
1208 1210 * At this point, the only operation
1209 1211 * that the client can perform is to
1210 1212 * change the user's password. If the
1211 1213 * client requests any other LDAP
1212 1214 * operation, the server sends back
1213 1215 * an LDAP_UNWILLING_TO_PERFORM
1214 1216 * result code with an expired
1215 1217 * password control.
1216 1218 *
1217 1219 * The control with the OID
1218 1220 * 2.16.840.1.113730.3.4.5 (or
1219 1221 * LDAP_CONTROL_PWEXPIRING, as
1220 1222 * defined in the ldap.h header file)
1221 1223 * is the password expiration warning
1222 1224 * control.
1223 1225 *
1224 1226 * This control is used if the server
1225 1227 * is configured to expire user
1226 1228 * passwords after a certain amount
1227 1229 * of time.
1228 1230 *
1229 1231 * The server sends this control back
1230 1232 * to the client if the client binds
1231 1233 * using a password that will soon
1232 1234 * expire. The ldctl_value field of
1233 1235 * the LDAPControl structure
1234 1236 * specifies the number of seconds
1235 1237 * before the password will expire.
1236 1238 */
1237 1239 for (ctrl = controls; *ctrl; ctrl++) {
1238 1240
1239 1241 if (strcmp((*ctrl)->ldctl_oid,
1240 1242 LDAP_CONTROL_PWEXPIRED) == 0) {
1241 1243 /*
1242 1244 * if the caller wants this bind
1243 1245 * to fail, set up the error info.
1244 1246 * If call to this function is
1245 1247 * for searching the LDAP directory,
1246 1248 * e.g., __ns_ldap_list(),
1247 1249 * there's really no sense to
1248 1250 * let a connection open and
1249 1251 * then fail immediately afterward
1250 1252 * on the LDAP search operation with
1251 1253 * the LDAP_UNWILLING_TO_PERFORM rc
1252 1254 */
1253 1255 pwd_status =
1254 1256 NS_PASSWD_CHANGE_NEEDED;
1255 1257 if (fail_if_new_pwd_reqd) {
1256 1258 (void) snprintf(errstr,
1257 1259 sizeof (errstr),
1258 1260 gettext(
1259 1261 "openConnection: "
1260 1262 "%s bind "
1261 1263 "failed "
1262 1264 "- password "
1263 1265 "expired. It "
1264 1266 " needs to change "
1265 1267 "immediately!"),
1266 1268 bind_type);
1267 1269 MKERROR_PWD_MGMT(*errorp,
1268 1270 LDAP_SUCCESS,
1269 1271 strdup(errstr),
1270 1272 pwd_status,
1271 1273 0,
1272 1274 NULL);
1273 1275 exit_rc = NS_LDAP_INTERNAL;
1274 1276 } else {
1275 1277 MKERROR_PWD_MGMT(*errorp,
1276 1278 LDAP_SUCCESS,
1277 1279 NULL,
1278 1280 pwd_status,
1279 1281 0,
1280 1282 NULL);
1281 1283 exit_rc =
1282 1284 NS_LDAP_SUCCESS_WITH_INFO;
1283 1285 }
1284 1286 break;
1285 1287 } else if (strcmp((*ctrl)->ldctl_oid,
1286 1288 LDAP_CONTROL_PWEXPIRING) == 0) {
1287 1289 pwd_status =
1288 1290 NS_PASSWD_ABOUT_TO_EXPIRE;
1289 1291 if ((*ctrl)->
1290 1292 ldctl_value.bv_len > 0 &&
1291 1293 (*ctrl)->
1292 1294 ldctl_value.bv_val)
1293 1295 sec_until_exp =
1294 1296 atoi((*ctrl)->
1295 1297 ldctl_value.bv_val);
1296 1298 MKERROR_PWD_MGMT(*errorp,
1297 1299 LDAP_SUCCESS,
1298 1300 NULL,
1299 1301 pwd_status,
1300 1302 sec_until_exp,
1301 1303 NULL);
1302 1304 exit_rc =
1303 1305 NS_LDAP_SUCCESS_WITH_INFO;
1304 1306 break;
1305 1307 }
1306 1308 }
1307 1309 }
1308 1310
1309 1311 if (controls)
1310 1312 ldap_controls_free(controls);
1311 1313
1312 1314 return (exit_rc);
1313 1315 }
1314 1316
1315 1317 static int
1316 1318 ldap_in_nss_switch(char *db)
1317 1319 {
1318 1320 enum __nsw_parse_err pserr;
1319 1321 struct __nsw_switchconfig *conf;
1320 1322 struct __nsw_lookup *lkp;
1321 1323 const char *name;
1322 1324 int found = 0;
1323 1325
1324 1326 conf = __nsw_getconfig(db, &pserr);
1325 1327 if (conf == NULL) {
1326 1328 return (-1);
1327 1329 }
1328 1330
1329 1331 /* check for skip and count other backends */
1330 1332 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
1331 1333 name = lkp->service_name;
1332 1334 if (strcmp(name, "ldap") == 0) {
1333 1335 found = 1;
1334 1336 break;
1335 1337 }
1336 1338 }
1337 1339 (void) __nsw_freeconfig(conf);
1338 1340 return (found);
1339 1341 }
1340 1342
1341 1343 static int
1342 1344 openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
1343 1345 int timeoutSec, ns_ldap_error_t **errorp,
1344 1346 int fail_if_new_pwd_reqd, int passwd_mgmt,
1345 1347 ns_conn_user_t *conn_user, int flags)
1346 1348 {
1347 1349 LDAP *ld = NULL;
1348 1350 int ldapVersion = LDAP_VERSION3;
1349 1351 int derefOption = LDAP_DEREF_ALWAYS;
1350 1352 int zero = 0;
1351 1353 int timeoutMilliSec = timeoutSec * 1000;
1352 1354 uint16_t port = USE_DEFAULT_PORT;
1353 1355 char *s;
1354 1356 char errstr[MAXERROR];
1355 1357 int followRef;
1356 1358
1357 1359 ns_ldap_return_code ret_code = NS_LDAP_SUCCESS;
1358 1360
1359 1361 *errorp = NULL;
1360 1362 *ldp = NULL;
1361 1363
1362 1364 /* determine if the host name contains a port number */
1363 1365 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */
1364 1366 s = strchr(s != NULL ? s : serverAddr, ':');
1365 1367 if (s != NULL) {
1366 1368 if (sscanf(s + 1, "%hu", &port) != 1) {
1367 1369 (void) snprintf(errstr,
1368 1370 sizeof (errstr),
1369 1371 gettext("openConnection: cannot "
1370 1372 "convert %s into a valid "
1371 1373 "port number for the "
1372 1374 "%s server. A default value "
1373 1375 "will be used."),
1374 1376 s,
1375 1377 serverAddr);
1376 1378 syslog(LOG_ERR, "libsldap: %s", errstr);
1377 1379 } else {
1378 1380 *s = '\0';
1379 1381 }
1380 1382 }
1381 1383
1382 1384 ret_code = createSession(auth,
1383 1385 serverAddr,
1384 1386 port,
1385 1387 timeoutMilliSec,
1386 1388 &ld,
1387 1389 errorp);
1388 1390 if (s != NULL) {
1389 1391 *s = ':';
1390 1392 }
1391 1393 if (ret_code != NS_LDAP_SUCCESS) {
1392 1394 return (ret_code);
1393 1395 }
1394 1396
1395 1397 /* check to see if the underlying libsldap supports MT connection */
1396 1398 if (conn_user != NULL) {
1397 1399 int rc;
1398 1400
1399 1401 rc = __s_api_check_libldap_MT_conn_support(conn_user, ld,
1400 1402 errorp);
1401 1403 if (rc != NS_LDAP_SUCCESS) {
1402 1404 (void) ldap_unbind(ld);
1403 1405 return (rc);
1404 1406 }
1405 1407 }
1406 1408
1407 1409 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
1408 1410 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
1409 1411 /*
1410 1412 * This library will handle the referral itself based on API flags or
1411 1413 * configuration file specification. The LDAP bind operation is an
1412 1414 * exception where we rely on the LDAP library to follow the referal.
1413 1415 *
1414 1416 * The LDAP follow referral option must be set to OFF for the libldap5
1415 1417 * to pass the referral info up to this library. This option MUST be
1416 1418 * set to OFF after we have performed a sucessful bind. If we are not
1417 1419 * to follow referrals we MUST also set the LDAP follow referral option
1418 1420 * to OFF before we perform an LDAP bind.
1419 1421 */
1420 1422 ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp);
1421 1423 if (ret_code != NS_LDAP_SUCCESS) {
1422 1424 (void) ldap_unbind(ld);
1423 1425 return (ret_code);
1424 1426 }
1425 1427
1426 1428 if (followRef)
1427 1429 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1428 1430 else
1429 1431 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1430 1432
1431 1433 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
1432 1434 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
1433 1435 /* setup TCP/IP connect timeout */
1434 1436 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
1435 1437 &timeoutMilliSec);
1436 1438 /* retry if LDAP I/O was interrupted */
1437 1439 (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1438 1440
1439 1441 ret_code = performBind(auth,
1440 1442 ld,
1441 1443 timeoutSec,
1442 1444 errorp,
1443 1445 fail_if_new_pwd_reqd,
1444 1446 passwd_mgmt);
1445 1447
1446 1448 if (ret_code == NS_LDAP_SUCCESS ||
1447 1449 ret_code == NS_LDAP_SUCCESS_WITH_INFO) {
1448 1450 /*
1449 1451 * Turn off LDAP referral following so that this library can
1450 1452 * process referrals.
1451 1453 */
1452 1454 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1453 1455 *ldp = ld;
1454 1456 }
1455 1457
1456 1458 return (ret_code);
1457 1459 }
1458 1460
1459 1461 /*
1460 1462 * FUNCTION: __s_api_getDefaultAuth
1461 1463 *
1462 1464 * Constructs a credential for authentication using the config module.
1463 1465 *
1464 1466 * RETURN VALUES:
1465 1467 *
1466 1468 * NS_LDAP_SUCCESS If successful
1467 1469 * NS_LDAP_CONFIG If there are any config errors.
1468 1470 * NS_LDAP_MEMORY Memory errors.
1469 1471 * NS_LDAP_OP_FAILED If there are no more authentication methods so can
1470 1472 * not build a new authp.
1471 1473 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
1472 1474 * necessary fields of a cred for a given auth method
1473 1475 * are not provided.
1474 1476 * INPUT:
1475 1477 *
1476 1478 * cLevel Currently requested credential level to be tried
1477 1479 *
1478 1480 * aMethod Currently requested authentication method to be tried
1479 1481 *
1480 1482 * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password
1481 1483 *
1482 1484 * OUTPUT:
1483 1485 *
1484 1486 * authp authentication method to use.
1485 1487 */
1486 1488 static int
1487 1489 __s_api_getDefaultAuth(
1488 1490 int *cLevel,
1489 1491 ns_auth_t *aMethod,
1490 1492 ns_cred_t **authp,
1491 1493 int getAdmin)
1492 1494 {
1493 1495 void **paramVal = NULL;
1494 1496 char *modparamVal = NULL;
1495 1497 int getUid = 0;
1496 1498 int getPasswd = 0;
1497 1499 int getCertpath = 0;
1498 1500 int rc = 0;
1499 1501 ns_ldap_error_t *errorp = NULL;
1500 1502 UnixCred_t *AdminCred = NULL;
1501 1503
1502 1504 #ifdef DEBUG
1503 1505 (void) fprintf(stderr, "__s_api_getDefaultAuth START\n");
1504 1506 #endif
1505 1507
1506 1508 if (aMethod == NULL) {
1507 1509 /* Require an Auth */
1508 1510 return (NS_LDAP_INVALID_PARAM);
1509 1511
1510 1512 }
1511 1513 /*
1512 1514 * credential level "self" can work with auth method sasl/GSSAPI only
1513 1515 */
1514 1516 if (cLevel && *cLevel == NS_LDAP_CRED_SELF &&
1515 1517 aMethod->saslmech != NS_LDAP_SASL_GSSAPI)
1516 1518 return (NS_LDAP_INVALID_PARAM);
1517 1519
1518 1520 *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
1519 1521 if ((*authp) == NULL)
1520 1522 return (NS_LDAP_MEMORY);
1521 1523
1522 1524 (*authp)->auth = *aMethod;
1523 1525
1524 1526 switch (aMethod->type) {
1525 1527 case NS_LDAP_AUTH_NONE:
1526 1528 return (NS_LDAP_SUCCESS);
1527 1529 case NS_LDAP_AUTH_SIMPLE:
1528 1530 getUid++;
1529 1531 getPasswd++;
1530 1532 break;
1531 1533 case NS_LDAP_AUTH_SASL:
1532 1534 if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1533 1535 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
1534 1536 getUid++;
1535 1537 getPasswd++;
1536 1538 } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) {
1537 1539 (void) __ns_ldap_freeCred(authp);
1538 1540 return (NS_LDAP_INVALID_PARAM);
1539 1541 }
1540 1542 break;
1541 1543 case NS_LDAP_AUTH_TLS:
1542 1544 if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) ||
1543 1545 ((aMethod->tlstype == NS_LDAP_TLS_SASL) &&
1544 1546 ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1545 1547 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) {
1546 1548 getUid++;
1547 1549 getPasswd++;
1548 1550 getCertpath++;
1549 1551 } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) {
1550 1552 getCertpath++;
1551 1553 } else {
1552 1554 (void) __ns_ldap_freeCred(authp);
1553 1555 return (NS_LDAP_INVALID_PARAM);
1554 1556 }
1555 1557 break;
1556 1558 }
1557 1559
1558 1560 if (getUid) {
1559 1561 paramVal = NULL;
1560 1562 if (getAdmin) {
1561 1563 /*
1562 1564 * Assume AdminCred has been retrieved from
1563 1565 * ldap_cachemgr already. It will not work
1564 1566 * without userID or password. Flags getUid
1565 1567 * and getPasswd should always be set
1566 1568 * together.
1567 1569 */
1568 1570 AdminCred = calloc(1, sizeof (UnixCred_t));
1569 1571 if (AdminCred == NULL) {
1570 1572 (void) __ns_ldap_freeCred(authp);
1571 1573 return (NS_LDAP_MEMORY);
1572 1574 }
1573 1575
1574 1576 rc = requestAdminCred(&AdminCred, &errorp);
1575 1577 if (rc != NS_LDAP_SUCCESS) {
1576 1578 (void) __ns_ldap_freeCred(authp);
1577 1579 (void) __ns_ldap_freeUnixCred(&AdminCred);
1578 1580 (void) __ns_ldap_freeError(&errorp);
1579 1581 return (rc);
1580 1582 }
1581 1583
1582 1584 if (AdminCred->userID == NULL) {
1583 1585 (void) __ns_ldap_freeCred(authp);
1584 1586 (void) __ns_ldap_freeUnixCred(&AdminCred);
1585 1587 return (NS_LDAP_INVALID_PARAM);
1586 1588 }
1587 1589 (*authp)->cred.unix_cred.userID = AdminCred->userID;
1588 1590 AdminCred->userID = NULL;
1589 1591 } else {
1590 1592 rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
1591 1593 ¶mVal, &errorp);
1592 1594 if (rc != NS_LDAP_SUCCESS) {
1593 1595 (void) __ns_ldap_freeCred(authp);
1594 1596 (void) __ns_ldap_freeError(&errorp);
1595 1597 return (rc);
1596 1598 }
1597 1599
1598 1600 if (paramVal == NULL || *paramVal == NULL) {
1599 1601 (void) __ns_ldap_freeCred(authp);
1600 1602 return (NS_LDAP_INVALID_PARAM);
1601 1603 }
1602 1604
1603 1605 (*authp)->cred.unix_cred.userID =
1604 1606 strdup((char *)*paramVal);
1605 1607 (void) __ns_ldap_freeParam(¶mVal);
1606 1608 }
1607 1609 if ((*authp)->cred.unix_cred.userID == NULL) {
1608 1610 (void) __ns_ldap_freeCred(authp);
1609 1611 (void) __ns_ldap_freeUnixCred(&AdminCred);
1610 1612 return (NS_LDAP_MEMORY);
1611 1613 }
1612 1614 }
1613 1615 if (getPasswd) {
1614 1616 paramVal = NULL;
1615 1617 if (getAdmin) {
1616 1618 /*
1617 1619 * Assume AdminCred has been retrieved from
1618 1620 * ldap_cachemgr already. It will not work
1619 1621 * without the userID anyway because for
1620 1622 * getting admin credential, flags getUid
1621 1623 * and getPasswd should always be set
1622 1624 * together.
1623 1625 */
1624 1626 if (AdminCred == NULL || AdminCred->passwd == NULL) {
1625 1627 (void) __ns_ldap_freeCred(authp);
1626 1628 (void) __ns_ldap_freeUnixCred(&AdminCred);
1627 1629 return (NS_LDAP_INVALID_PARAM);
1628 1630 }
1629 1631 modparamVal = dvalue(AdminCred->passwd);
1630 1632 } else {
1631 1633 rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
1632 1634 ¶mVal, &errorp);
1633 1635 if (rc != NS_LDAP_SUCCESS) {
1634 1636 (void) __ns_ldap_freeCred(authp);
1635 1637 (void) __ns_ldap_freeError(&errorp);
1636 1638 return (rc);
1637 1639 }
1638 1640
1639 1641 if (paramVal == NULL || *paramVal == NULL) {
1640 1642 (void) __ns_ldap_freeCred(authp);
1641 1643 return (NS_LDAP_INVALID_PARAM);
1642 1644 }
1643 1645
1644 1646 modparamVal = dvalue((char *)*paramVal);
1645 1647 (void) __ns_ldap_freeParam(¶mVal);
1646 1648 }
1647 1649
1648 1650 if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) {
1649 1651 (void) __ns_ldap_freeCred(authp);
1650 1652 (void) __ns_ldap_freeUnixCred(&AdminCred);
1651 1653 if (modparamVal != NULL)
1652 1654 free(modparamVal);
1653 1655 return (NS_LDAP_INVALID_PARAM);
1654 1656 }
1655 1657
1656 1658 (*authp)->cred.unix_cred.passwd = modparamVal;
1657 1659 }
1658 1660 if (getCertpath) {
1659 1661 paramVal = NULL;
1660 1662 if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1661 1663 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) {
1662 1664 (void) __ns_ldap_freeCred(authp);
1663 1665 (void) __ns_ldap_freeUnixCred(&AdminCred);
1664 1666 (void) __ns_ldap_freeError(&errorp);
1665 1667 *authp = NULL;
1666 1668 return (rc);
1667 1669 }
1668 1670
1669 1671 if (paramVal == NULL || *paramVal == NULL) {
1670 1672 (void) __ns_ldap_freeCred(authp);
1671 1673 (void) __ns_ldap_freeUnixCred(&AdminCred);
1672 1674 *authp = NULL;
1673 1675 return (NS_LDAP_INVALID_PARAM);
1674 1676 }
1675 1677
1676 1678 (*authp)->hostcertpath = strdup((char *)*paramVal);
1677 1679 (void) __ns_ldap_freeParam(¶mVal);
1678 1680 if ((*authp)->hostcertpath == NULL) {
1679 1681 (void) __ns_ldap_freeCred(authp);
1680 1682 (void) __ns_ldap_freeUnixCred(&AdminCred);
1681 1683 *authp = NULL;
1682 1684 return (NS_LDAP_MEMORY);
1683 1685 }
1684 1686 }
1685 1687 (void) __ns_ldap_freeUnixCred(&AdminCred);
1686 1688 return (NS_LDAP_SUCCESS);
1687 1689 }
1688 1690
1689 1691 /*
1690 1692 * FUNCTION: getConnection
1691 1693 *
1692 1694 * internal version of __s_api_getConnection()
1693 1695 */
1694 1696 static int
1695 1697 getConnection(
1696 1698 const char *server,
1697 1699 const int flags,
1698 1700 const ns_cred_t *cred, /* credentials for bind */
1699 1701 ConnectionID *sessionId,
1700 1702 Connection **session,
1701 1703 ns_ldap_error_t **errorp,
1702 1704 int fail_if_new_pwd_reqd,
1703 1705 int nopasswd_acct_mgmt,
1704 1706 ns_conn_user_t *conn_user)
1705 1707 {
1706 1708 char errmsg[MAXERROR];
1707 1709 ns_auth_t **aMethod = NULL;
1708 1710 ns_auth_t **aNext = NULL;
1709 1711 int **cLevel = NULL;
1710 1712 int **cNext = NULL;
1711 1713 int timeoutSec = NS_DEFAULT_BIND_TIMEOUT;
1712 1714 int rc;
1713 1715 Connection *con = NULL;
1714 1716 int sec = 1;
1715 1717 ns_cred_t *authp = NULL;
1716 1718 ns_cred_t anon;
1717 1719 int version = NS_LDAP_V2, self_gssapi_only = 0;
1718 1720 void **paramVal = NULL;
1719 1721 char **badSrvrs = NULL; /* List of problem hostnames */
1720 1722
1721 1723 if ((session == NULL) || (sessionId == NULL)) {
1722 1724 return (NS_LDAP_INVALID_PARAM);
1723 1725 }
1724 1726 *session = NULL;
1725 1727
1726 1728 /* reuse MT connection if needed and if available */
1727 1729 if (conn_user != NULL) {
1728 1730 rc = __s_api_conn_mt_get(server, flags, cred, session, errorp,
1729 1731 conn_user);
1730 1732 if (rc != NS_LDAP_NOTFOUND)
1731 1733 return (rc);
1732 1734 }
1733 1735
1734 1736 /* get profile version number */
1735 1737 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
1736 1738 ¶mVal, errorp)) != NS_LDAP_SUCCESS)
1737 1739 return (rc);
1738 1740 if (paramVal == NULL) {
1739 1741 (void) sprintf(errmsg, gettext("getConnection: no file "
1740 1742 "version"));
1741 1743 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg),
1742 1744 NS_LDAP_CONFIG);
1743 1745 return (NS_LDAP_CONFIG);
1744 1746 }
1745 1747 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
1746 1748 version = NS_LDAP_V1;
1747 1749 (void) __ns_ldap_freeParam((void ***)¶mVal);
1748 1750
1749 1751 /* Get the bind timeout value */
1750 1752 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp);
1751 1753 if (paramVal != NULL && *paramVal != NULL) {
1752 1754 timeoutSec = **((int **)paramVal);
1753 1755 (void) __ns_ldap_freeParam(¶mVal);
1754 1756 }
1755 1757 if (*errorp)
1756 1758 (void) __ns_ldap_freeError(errorp);
1757 1759
1758 1760 if (cred == NULL) {
1759 1761 /* Get the authentication method list */
1760 1762 if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
1761 1763 (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS)
1762 1764 return (rc);
1763 1765 if (aMethod == NULL) {
1764 1766 aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *));
1765 1767 if (aMethod == NULL)
1766 1768 return (NS_LDAP_MEMORY);
1767 1769 aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
1768 1770 if (aMethod[0] == NULL) {
1769 1771 free(aMethod);
1770 1772 return (NS_LDAP_MEMORY);
1771 1773 }
1772 1774 if (version == NS_LDAP_V1)
1773 1775 (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE;
1774 1776 else {
1775 1777 (aMethod[0])->type = NS_LDAP_AUTH_SASL;
1776 1778 (aMethod[0])->saslmech =
1777 1779 NS_LDAP_SASL_DIGEST_MD5;
1778 1780 (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE;
1779 1781 }
1780 1782 }
1781 1783
1782 1784 /* Get the credential level list */
1783 1785 if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
1784 1786 (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) {
1785 1787 (void) __ns_ldap_freeParam((void ***)&aMethod);
1786 1788 return (rc);
1787 1789 }
1788 1790 if (cLevel == NULL) {
1789 1791 cLevel = (int **)calloc(2, sizeof (int *));
1790 1792 if (cLevel == NULL)
1791 1793 return (NS_LDAP_MEMORY);
1792 1794 cLevel[0] = (int *)calloc(1, sizeof (int));
1793 1795 if (cLevel[0] == NULL)
1794 1796 return (NS_LDAP_MEMORY);
1795 1797 if (version == NS_LDAP_V1)
1796 1798 *(cLevel[0]) = NS_LDAP_CRED_PROXY;
1797 1799 else
1798 1800 *(cLevel[0]) = NS_LDAP_CRED_ANON;
1799 1801 }
1800 1802 }
1801 1803
1802 1804 /* setup the anon credential for anonymous connection */
1803 1805 (void) memset(&anon, 0, sizeof (ns_cred_t));
1804 1806 anon.auth.type = NS_LDAP_AUTH_NONE;
1805 1807
1806 1808 for (;;) {
1807 1809 if (cred != NULL) {
1808 1810 /* using specified auth method */
1809 1811 rc = makeConnection(&con, server, cred,
1810 1812 sessionId, timeoutSec, errorp,
1811 1813 fail_if_new_pwd_reqd,
1812 1814 nopasswd_acct_mgmt, flags, &badSrvrs, conn_user);
1813 1815 /* not using bad server if credentials were supplied */
1814 1816 if (badSrvrs && *badSrvrs) {
1815 1817 __s_api_free2dArray(badSrvrs);
1816 1818 badSrvrs = NULL;
1817 1819 }
1818 1820 if (rc == NS_LDAP_SUCCESS ||
1819 1821 rc == NS_LDAP_SUCCESS_WITH_INFO) {
1820 1822 *session = con;
1821 1823 break;
1822 1824 }
1823 1825 } else {
1824 1826 self_gssapi_only = __s_api_self_gssapi_only_get();
1825 1827 /* for every cred level */
1826 1828 for (cNext = cLevel; *cNext != NULL; cNext++) {
1827 1829 if (self_gssapi_only &&
1828 1830 **cNext != NS_LDAP_CRED_SELF)
1829 1831 continue;
1830 1832 if (**cNext == NS_LDAP_CRED_ANON) {
1831 1833 /*
1832 1834 * make connection anonymously
1833 1835 * Free the down server list before
1834 1836 * looping through
1835 1837 */
1836 1838 if (badSrvrs && *badSrvrs) {
1837 1839 __s_api_free2dArray(badSrvrs);
1838 1840 badSrvrs = NULL;
1839 1841 }
1840 1842 rc = makeConnection(&con, server, &anon,
1841 1843 sessionId, timeoutSec, errorp,
1842 1844 fail_if_new_pwd_reqd,
1843 1845 nopasswd_acct_mgmt, flags,
1844 1846 &badSrvrs, conn_user);
1845 1847 if (rc == NS_LDAP_SUCCESS ||
1846 1848 rc ==
1847 1849 NS_LDAP_SUCCESS_WITH_INFO) {
1848 1850 *session = con;
1849 1851 goto done;
1850 1852 }
1851 1853 continue;
1852 1854 }
1853 1855 /* for each cred level */
1854 1856 for (aNext = aMethod; *aNext != NULL; aNext++) {
1855 1857 if (self_gssapi_only &&
1856 1858 (*aNext)->saslmech !=
1857 1859 NS_LDAP_SASL_GSSAPI)
1858 1860 continue;
1859 1861 /*
1860 1862 * self coexists with sasl/GSSAPI only
1861 1863 * and non-self coexists with non-gssapi
1862 1864 * only
1863 1865 */
1864 1866 if ((**cNext == NS_LDAP_CRED_SELF &&
1865 1867 (*aNext)->saslmech !=
1866 1868 NS_LDAP_SASL_GSSAPI) ||
1867 1869 (**cNext != NS_LDAP_CRED_SELF &&
1868 1870 (*aNext)->saslmech ==
1869 1871 NS_LDAP_SASL_GSSAPI))
1870 1872 continue;
1871 1873 /* make connection and authenticate */
1872 1874 /* with default credentials */
1873 1875 authp = NULL;
1874 1876 rc = __s_api_getDefaultAuth(*cNext,
1875 1877 *aNext, &authp,
1876 1878 flags & NS_LDAP_READ_SHADOW);
1877 1879 if (rc != NS_LDAP_SUCCESS) {
1878 1880 continue;
1879 1881 }
1880 1882 /*
1881 1883 * Free the down server list before
1882 1884 * looping through
1883 1885 */
1884 1886 if (badSrvrs && *badSrvrs) {
1885 1887 __s_api_free2dArray(badSrvrs);
1886 1888 badSrvrs = NULL;
1887 1889 }
1888 1890 rc = makeConnection(&con, server, authp,
1889 1891 sessionId, timeoutSec, errorp,
1890 1892 fail_if_new_pwd_reqd,
1891 1893 nopasswd_acct_mgmt, flags,
1892 1894 &badSrvrs, conn_user);
1893 1895 (void) __ns_ldap_freeCred(&authp);
1894 1896 if (rc == NS_LDAP_SUCCESS ||
1895 1897 rc ==
1896 1898 NS_LDAP_SUCCESS_WITH_INFO) {
1897 1899 *session = con;
1898 1900 goto done;
1899 1901 }
1900 1902 }
1901 1903 }
1902 1904 }
1903 1905 if (flags & NS_LDAP_HARD) {
1904 1906 if (sec < LDAPMAXHARDLOOKUPTIME)
1905 1907 sec *= 2;
1906 1908 (void) sleep(sec);
1907 1909 } else {
1908 1910 break;
1909 1911 }
1910 1912 }
1911 1913
1912 1914 done:
1913 1915 if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) {
1914 1916 /*
1915 1917 * self_gssapi_only is true but no self/sasl/gssapi is
1916 1918 * configured
1917 1919 */
1918 1920 rc = NS_LDAP_CONFIG;
1919 1921 }
1920 1922
1921 1923 (void) __ns_ldap_freeParam((void ***)&aMethod);
1922 1924 (void) __ns_ldap_freeParam((void ***)&cLevel);
1923 1925
1924 1926 if (badSrvrs && *badSrvrs) {
1925 1927 /*
1926 1928 * At this point, either we have a successful
1927 1929 * connection or exhausted all the possible auths.
1928 1930 * and creds. Mark the problem servers as down
1929 1931 * so that the problem servers are not contacted
1930 1932 * again until the refresh_ttl expires.
1931 1933 */
1932 1934 (void) __s_api_removeBadServers(badSrvrs);
1933 1935 __s_api_free2dArray(badSrvrs);
1934 1936 }
1935 1937 return (rc);
1936 1938 }
1937 1939
1938 1940 /*
1939 1941 * FUNCTION: __s_api_getConnection
1940 1942 *
1941 1943 * Bind to the specified server or one from the server
1942 1944 * list and return the pointer.
1943 1945 *
1944 1946 * This function can rebind or not (NS_LDAP_HARD), it can require a
1945 1947 * credential or bind anonymously
1946 1948 *
1947 1949 * This function follows the DUA configuration schema algorithm
1948 1950 *
1949 1951 * RETURN VALUES:
1950 1952 *
1951 1953 * NS_LDAP_SUCCESS A connection was made successfully.
1952 1954 * NS_LDAP_SUCCESS_WITH_INFO
1953 1955 * A connection was made successfully, but with
1954 1956 * password management info in *errorp
1955 1957 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
1956 1958 * NS_LDAP_CONFIG If there are any config errors.
1957 1959 * NS_LDAP_MEMORY Memory errors.
1958 1960 * NS_LDAP_INTERNAL If there was a ldap error.
1959 1961 *
1960 1962 * INPUT:
1961 1963 *
1962 1964 * server Bind to this LDAP server only
1963 1965 * flags If NS_LDAP_HARD is set function will not return until it has
1964 1966 * a connection unless there is a authentication problem.
1965 1967 * If NS_LDAP_NEW_CONN is set the function must force a new
1966 1968 * connection to be created
1967 1969 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open
1968 1970 * auth Credentials for bind. This could be NULL in which case
1969 1971 * a default cred built from the config module is used.
1970 1972 * sessionId cookie that points to a previous session
1971 1973 * fail_if_new_pwd_reqd
1972 1974 * a flag indicating this function should fail if the passwd
1973 1975 * in auth needs to change immediately
1974 1976 * nopasswd_acct_mgmt
1975 1977 * a flag indicating that makeConnection should check before
1976 1978 * binding if server supports LDAP V3 password less
1977 1979 * account management
1978 1980 *
1979 1981 * OUTPUT:
1980 1982 *
1981 1983 * session pointer to a session with connection information
1982 1984 * errorp Set if there are any INTERNAL, or CONFIG error.
1983 1985 */
1984 1986 int
1985 1987 __s_api_getConnection(
1986 1988 const char *server,
1987 1989 const int flags,
1988 1990 const ns_cred_t *cred, /* credentials for bind */
1989 1991 ConnectionID *sessionId,
1990 1992 Connection **session,
1991 1993 ns_ldap_error_t **errorp,
1992 1994 int fail_if_new_pwd_reqd,
1993 1995 int nopasswd_acct_mgmt,
1994 1996 ns_conn_user_t *conn_user)
1995 1997 {
1996 1998 int rc;
1997 1999
1998 2000 rc = getConnection(server, flags, cred, sessionId, session,
1999 2001 errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
2000 2002 conn_user);
2001 2003
2002 2004 if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) {
2003 2005 if (conn_user != NULL && conn_user->conn_mt != NULL)
2004 2006 __s_api_conn_mt_remove(conn_user, rc, errorp);
2005 2007 }
2006 2008
2007 2009 return (rc);
2008 2010 }
2009 2011
2010 2012 void
2011 2013 __s_api_free_sessionPool()
2012 2014 {
2013 2015 int id;
2014 2016
2015 2017 (void) mutex_lock(&sessionPoolLock);
2016 2018
2017 2019 if (sessionPool != NULL) {
2018 2020 for (id = 0; id < sessionPoolSize; id++)
2019 2021 _DropConnection(id + CONID_OFFSET, 0, 1);
2020 2022 free(sessionPool);
2021 2023 sessionPool = NULL;
2022 2024 sessionPoolSize = 0;
2023 2025 }
2024 2026 (void) mutex_unlock(&sessionPoolLock);
2025 2027 }
2026 2028
2027 2029 /*
2028 2030 * This function initializes a TLS LDAP session. On success LDAP* is returned
2029 2031 * (pointed by *ldp). Otherwise, the function returns an NS error code and
2030 2032 * provide an additional info pointed by *errorp.
2031 2033 */
2032 2034 static
2033 2035 ns_ldap_return_code
2034 2036 createTLSSession(const ns_cred_t *auth, const char *serverAddr,
2035 2037 uint16_t port, int timeoutMilliSec,
2036 2038 LDAP **ldp, ns_ldap_error_t **errorp)
2037 2039 {
2038 2040 const char *hostcertpath;
2039 2041 char *alloc_hcp = NULL, errstr[MAXERROR];
2040 2042 int ldap_rc;
2041 2043
2042 2044 #ifdef DEBUG
2043 2045 (void) fprintf(stderr, "tid= %d: +++TLS transport\n",
2044 2046 thr_self());
2045 2047 #endif /* DEBUG */
2046 2048
2047 2049 if (prldap_set_session_option(NULL, NULL,
2048 2050 PRLDAP_OPT_IO_MAX_TIMEOUT,
2049 2051 timeoutMilliSec) != LDAP_SUCCESS) {
2050 2052 (void) snprintf(errstr, sizeof (errstr),
2051 2053 gettext("createTLSSession: failed to initialize "
2052 2054 "TLS security"));
2053 2055 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2054 2056 strdup(errstr), NS_LDAP_MEMORY);
2055 2057 return (NS_LDAP_INTERNAL);
2056 2058 }
2057 2059
2058 2060 hostcertpath = auth->hostcertpath;
2059 2061 if (hostcertpath == NULL) {
2060 2062 alloc_hcp = __s_get_hostcertpath();
2061 2063 hostcertpath = alloc_hcp;
2062 2064 }
2063 2065
2064 2066 if (hostcertpath == NULL)
2065 2067 return (NS_LDAP_MEMORY);
2066 2068
2067 2069 if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) {
2068 2070 if (alloc_hcp != NULL) {
2069 2071 free(alloc_hcp);
2070 2072 }
2071 2073 (void) snprintf(errstr, sizeof (errstr),
2072 2074 gettext("createTLSSession: failed to initialize "
2073 2075 "TLS security (%s)"),
2074 2076 ldapssl_err2string(ldap_rc));
2075 2077 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2076 2078 strdup(errstr), NS_LDAP_MEMORY);
2077 2079 return (NS_LDAP_INTERNAL);
2078 2080 }
2079 2081 if (alloc_hcp)
2080 2082 free(alloc_hcp);
2081 2083
2082 2084 *ldp = ldapssl_init(serverAddr, port, 1);
2083 2085
2084 2086 if (*ldp == NULL ||
2085 2087 ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) {
2086 2088 (void) snprintf(errstr, sizeof (errstr),
2087 2089 gettext("createTLSSession: failed to connect "
2088 2090 "using TLS (%s)"), strerror(errno));
2089 2091 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2090 2092 strdup(errstr), NS_LDAP_MEMORY);
2091 2093 return (NS_LDAP_INTERNAL);
2092 2094 }
2093 2095
2094 2096 return (NS_LDAP_SUCCESS);
2095 2097 }
2096 2098
2097 2099 /*
2098 2100 * Convert (resolve) hostname to IP address.
2099 2101 *
2100 2102 * INPUT:
2101 2103 *
2102 2104 * server - \[IPv6_address\][:port]
2103 2105 * - IPv4_address[:port]
2104 2106 * - hostname[:port]
2105 2107 *
2106 2108 * newaddr - Buffer to which this function writes resulting address,
2107 2109 * including the port number, if specified in server argument.
2108 2110 *
2109 2111 * newaddr_size - Size of the newaddr buffer.
2110 2112 *
2111 2113 * errstr - Buffer to which error string is written if error occurs.
2112 2114 *
2113 2115 * errstr_size - Size of the errstr buffer.
2114 2116 *
2115 2117 * OUTPUT:
2116 2118 *
2117 2119 * Returns 1 for success, 0 in case of error.
2118 2120 *
2119 2121 * newaddr - See above (INPUT section).
2120 2122 *
2121 2123 * errstr - See above (INPUT section).
2122 2124 */
2123 2125 static int
2124 2126 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size,
2125 2127 char *errstr, int errstr_size)
2126 2128 {
2127 2129 char *s;
2128 2130 unsigned short port = 0;
2129 2131 int err;
2130 2132 char buffer[NSS_BUFLEN_HOSTS];
2131 2133 struct hostent result;
2132 2134
2133 2135 /* Determine if the host name contains a port number. */
2134 2136
2135 2137 /* Skip over IPv6 address. */
2136 2138 s = strchr(server, ']');
2137 2139 s = strchr(s != NULL ? s : server, ':');
2138 2140 if (s != NULL) {
2139 2141 if (sscanf(s + 1, "%hu", &port) != 1) {
2140 2142 /* Address misformatted. No port number after : */
2141 2143 (void) snprintf(errstr, errstr_size, "%s",
2142 2144 gettext("Invalid host:port format"));
2143 2145 return (0);
2144 2146 } else
2145 2147 /* Cut off the :<port> part. */
2146 2148 *s = '\0';
2147 2149 }
2148 2150
2149 2151 buffer[0] = '\0';
2150 2152 /*
2151 2153 * Resolve hostname and fill in hostent structure.
2152 2154 */
2153 2155 if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS,
2154 2156 &err)) {
2155 2157 /*
2156 2158 * The only possible error here could be TRY_AGAIN if buffer was
2157 2159 * not big enough. NSS_BUFLEN_HOSTS should have been enough
2158 2160 * though.
2159 2161 */
2160 2162 (void) snprintf(errstr, errstr_size, "%s",
2161 2163 gettext("Unable to resolve address."));
2162 2164 return (0);
2163 2165 }
2164 2166
2165 2167
2166 2168 buffer[0] = '\0';
2167 2169 /*
2168 2170 * Convert the address to string.
2169 2171 */
2170 2172 if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer,
2171 2173 NSS_BUFLEN_HOSTS)) {
2172 2174 /* There's not much we can do. */
2173 2175 (void) snprintf(errstr, errstr_size, "%s",
2174 2176 gettext("Unable to convert address to string."));
2175 2177 return (0);
2176 2178 }
2177 2179
2178 2180 /* Put together the address and the port */
2179 2181 if (port > 0) {
2180 2182 switch (result.h_addrtype) {
2181 2183 case AF_INET6:
2182 2184 (void) snprintf(newaddr,
2183 2185 /* [IP]:<port>\0 */
2184 2186 1 + strlen(buffer) + 1 + 1 + 5 + 1,
2185 2187 "[%s]:%hu",
2186 2188 buffer,
2187 2189 port);
2188 2190 break;
2189 2191 /* AF_INET */
2190 2192 default :
2191 2193 (void) snprintf(newaddr,
2192 2194 /* IP:<port>\0 */
2193 2195 strlen(buffer) + 1 + 5 + 1,
2194 2196 "%s:%hu",
2195 2197 buffer,
2196 2198 port);
2197 2199 break;
2198 2200 }
2199 2201 } else {
2200 2202 (void) strncpy(newaddr, buffer, newaddr_size);
2201 2203 }
2202 2204
2203 2205 return (1);
2204 2206 }
2205 2207
2206 2208
2207 2209 /*
2208 2210 * This finction initializes a none-TLS LDAP session. On success LDAP*
2209 2211 * is returned (pointed by *ldp). Otherwise, the function returns
2210 2212 * an NS error code and provides an additional info pointed by *errorp.
2211 2213 */
2212 2214 static
2213 2215 ns_ldap_return_code
2214 2216 createNonTLSSession(const char *serverAddr,
2215 2217 uint16_t port, int gssapi,
2216 2218 LDAP **ldp, ns_ldap_error_t **errorp)
2217 2219 {
2218 2220 char errstr[MAXERROR];
2219 2221 char *addr;
2220 2222 int is_ip = 0;
2221 2223 /* [INET6_ADDRSTRLEN]:<port>\0 */
2222 2224 char svraddr[1+INET6_ADDRSTRLEN+1+1+5+1];
2223 2225 #ifdef DEBUG
2224 2226 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n",
2225 2227 thr_self());
2226 2228 #endif /* DEBUG */
2227 2229
2228 2230 if (gssapi == 0) {
2229 2231 is_ip = (__s_api_isipv4((char *)serverAddr) ||
2230 2232 __s_api_isipv6((char *)serverAddr));
2231 2233 }
2232 2234
2233 2235 /*
2234 2236 * Let's try to resolve IP address of server.
2235 2237 */
2236 2238 if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 ||
2237 2239 ldap_in_nss_switch((char *)"ipnodes") > 0)) {
2238 2240 addr = strdup(serverAddr);
2239 2241 if (addr == NULL)
2240 2242 return (NS_LDAP_MEMORY);
2241 2243 svraddr[0] = '\0';
2242 2244 if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr),
2243 2245 errstr, MAXERROR) == 1) {
2244 2246 serverAddr = svraddr;
2245 2247 free(addr);
2246 2248 } else {
2247 2249 free(addr);
2248 2250 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2249 2251 strdup(errstr), NS_LDAP_MEMORY);
2250 2252 return (NS_LDAP_INTERNAL);
2251 2253 }
2252 2254 }
2253 2255
2254 2256 /* Warning message IF cannot connect to host(s) */
2255 2257 if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) {
2256 2258 char *p = strerror(errno);
2257 2259 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2258 2260 strdup(p), NS_LDAP_MEMORY);
2259 2261 return (NS_LDAP_INTERNAL);
2260 2262 }
2261 2263
2262 2264 return (NS_LDAP_SUCCESS);
2263 2265 }
2264 2266
2265 2267 /*
2266 2268 * This finction initializes an LDAP session.
2267 2269 *
2268 2270 * INPUT:
2269 2271 * auth - a structure specified an authenticastion method and credentials,
2270 2272 * serverAddr - the address of a server to which a connection
2271 2273 * will be established,
2272 2274 * port - a port being listened by the server,
2273 2275 * timeoutMilliSec - a timeout in milliseconds for the Bind operation.
2274 2276 *
2275 2277 * OUTPUT:
2276 2278 * ldp - a pointer to an LDAP structure which will be used
2277 2279 * for all the subsequent operations against the server.
2278 2280 * If an error occurs, the function returns an NS error code
2279 2281 * and provides an additional info pointed by *errorp.
2280 2282 */
2281 2283 static
2282 2284 ns_ldap_return_code
2283 2285 createSession(const ns_cred_t *auth, const char *serverAddr,
2284 2286 uint16_t port, int timeoutMilliSec,
2285 2287 LDAP **ldp, ns_ldap_error_t **errorp)
2286 2288 {
2287 2289 int useSSL = 0, gssapi = 0;
2288 2290 char errstr[MAXERROR];
2289 2291
2290 2292 switch (auth->auth.type) {
2291 2293 case NS_LDAP_AUTH_NONE:
2292 2294 case NS_LDAP_AUTH_SIMPLE:
2293 2295 case NS_LDAP_AUTH_SASL:
2294 2296 break;
2295 2297 case NS_LDAP_AUTH_TLS:
2296 2298 useSSL = 1;
2297 2299 break;
2298 2300 default:
2299 2301 (void) sprintf(errstr,
2300 2302 gettext("openConnection: unsupported "
2301 2303 "authentication method (%d)"), auth->auth.type);
2302 2304 MKERROR(LOG_WARNING, *errorp,
2303 2305 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2304 2306 NS_LDAP_MEMORY);
2305 2307 return (NS_LDAP_INTERNAL);
2306 2308 }
2307 2309
2308 2310 if (port == USE_DEFAULT_PORT) {
2309 2311 port = useSSL ? LDAPS_PORT : LDAP_PORT;
2310 2312 }
2311 2313
2312 2314 if (auth->auth.type == NS_LDAP_AUTH_SASL &&
2313 2315 auth->auth.saslmech == NS_LDAP_SASL_GSSAPI)
2314 2316 gssapi = 1;
2315 2317
2316 2318 if (useSSL)
2317 2319 return (createTLSSession(auth, serverAddr, port,
2318 2320 timeoutMilliSec, ldp, errorp));
2319 2321 else
2320 2322 return (createNonTLSSession(serverAddr, port, gssapi,
2321 2323 ldp, errorp));
2322 2324 }
2323 2325
2324 2326 /*
2325 2327 * This finction performs a non-SASL bind operation. If an error accures,
2326 2328 * the function returns an NS error code and provides an additional info
2327 2329 * pointed by *errorp.
2328 2330 */
2329 2331 static
2330 2332 ns_ldap_return_code
2331 2333 doSimpleBind(const ns_cred_t *auth,
2332 2334 LDAP *ld,
2333 2335 int timeoutSec,
2334 2336 ns_ldap_error_t **errorp,
2335 2337 int fail_if_new_pwd_reqd,
2336 2338 int passwd_mgmt)
2337 2339 {
2338 2340 char *binddn, *passwd, errstr[MAXERROR], *errmsg;
2339 2341 int msgId, errnum = 0, ldap_rc;
2340 2342 ns_ldap_return_code ret_code;
2341 2343 LDAPMessage *resultMsg = NULL;
2342 2344 LDAPControl **controls;
2343 2345 struct timeval tv;
2344 2346
2345 2347 binddn = auth->cred.unix_cred.userID;
2346 2348 passwd = auth->cred.unix_cred.passwd;
2347 2349 if (passwd == NULL || *passwd == '\0' ||
2348 2350 binddn == NULL || *binddn == '\0') {
2349 2351 (void) sprintf(errstr, gettext("openConnection: "
2350 2352 "missing credentials for Simple bind"));
2351 2353 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
2352 2354 strdup(errstr), NS_LDAP_MEMORY);
2353 2355 (void) ldap_unbind(ld);
2354 2356 return (NS_LDAP_INTERNAL);
2355 2357 }
2356 2358
2357 2359 #ifdef DEBUG
2358 2360 (void) fprintf(stderr, "tid= %d: +++Simple bind\n",
2359 2361 thr_self());
2360 2362 #endif /* DEBUG */
2361 2363 msgId = ldap_simple_bind(ld, binddn, passwd);
2362 2364
2363 2365 if (msgId == -1) {
2364 2366 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2365 2367 (void *)&errnum);
2366 2368 (void) snprintf(errstr, sizeof (errstr),
2367 2369 gettext("openConnection: simple bind failed "
2368 2370 "- %s"), ldap_err2string(errnum));
2369 2371 (void) ldap_unbind(ld);
2370 2372 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2371 2373 NS_LDAP_MEMORY);
2372 2374 return (NS_LDAP_INTERNAL);
2373 2375 }
2374 2376
2375 2377 tv.tv_sec = timeoutSec;
2376 2378 tv.tv_usec = 0;
2377 2379 ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg);
2378 2380
2379 2381 if ((ldap_rc == -1) || (ldap_rc == 0)) {
2380 2382 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2381 2383 (void *)&errnum);
2382 2384 (void) snprintf(errstr, sizeof (errstr),
2383 2385 gettext("openConnection: simple bind failed "
2384 2386 "- %s"), ldap_err2string(errnum));
2385 2387 (void) ldap_msgfree(resultMsg);
2386 2388 (void) ldap_unbind(ld);
2387 2389 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2388 2390 NS_LDAP_MEMORY);
2389 2391 return (NS_LDAP_INTERNAL);
2390 2392 }
2391 2393
2392 2394 /*
2393 2395 * get ldaprc, controls, and error msg
2394 2396 */
2395 2397 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2396 2398 &errmsg, NULL, &controls, 1);
2397 2399
2398 2400 if (ldap_rc != LDAP_SUCCESS) {
2399 2401 (void) snprintf(errstr, sizeof (errstr),
2400 2402 gettext("openConnection: simple bind failed "
2401 2403 "- unable to parse result"));
2402 2404 (void) ldap_unbind(ld);
2403 2405 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2404 2406 strdup(errstr), NS_LDAP_MEMORY);
2405 2407 return (NS_LDAP_INTERNAL);
2406 2408 }
2407 2409
2408 2410 /* process the password management info, if any */
2409 2411 ret_code = process_pwd_mgmt("simple",
2410 2412 errnum, controls, errmsg,
2411 2413 errorp,
2412 2414 fail_if_new_pwd_reqd,
2413 2415 passwd_mgmt);
2414 2416
2415 2417 if (ret_code == NS_LDAP_INTERNAL) {
2416 2418 (void) ldap_unbind(ld);
2417 2419 }
2418 2420
2419 2421 return (ret_code);
2420 2422 }
2421 2423
2422 2424 /*
2423 2425 * This finction performs a SASL bind operation. If an error accures,
2424 2426 * the function returns an NS error code and provides an additional info
2425 2427 * pointed by *errorp.
2426 2428 */
2427 2429 static
2428 2430 ns_ldap_return_code
2429 2431 doSASLBind(const ns_cred_t *auth,
2430 2432 LDAP *ld,
2431 2433 int timeoutSec,
2432 2434 ns_ldap_error_t **errorp,
2433 2435 int fail_if_new_pwd_reqd,
2434 2436 int passwd_mgmt)
2435 2437 {
2436 2438 char *binddn, *passwd, *digest_md5_name,
2437 2439 errstr[MAXERROR], *errmsg;
2438 2440 struct berval cred;
2439 2441 int ldap_rc, errnum = 0;
2440 2442 ns_ldap_return_code ret_code;
2441 2443 struct timeval tv;
2442 2444 LDAPMessage *resultMsg;
2443 2445 LDAPControl **controls;
2444 2446 int min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF;
2445 2447 ns_sasl_cb_param_t sasl_param;
2446 2448
2447 2449 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE &&
2448 2450 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2449 2451 (void) sprintf(errstr,
2450 2452 gettext("openConnection: SASL options are "
2451 2453 "not supported (%d) for non-GSSAPI sasl bind"),
2452 2454 auth->auth.saslopt);
2453 2455 MKERROR(LOG_WARNING, *errorp,
2454 2456 LDAP_AUTH_METHOD_NOT_SUPPORTED,
2455 2457 strdup(errstr), NS_LDAP_MEMORY);
2456 2458 (void) ldap_unbind(ld);
2457 2459 return (NS_LDAP_INTERNAL);
2458 2460 }
2459 2461 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2460 2462 binddn = auth->cred.unix_cred.userID;
2461 2463 passwd = auth->cred.unix_cred.passwd;
2462 2464 if (passwd == NULL || *passwd == '\0' ||
2463 2465 binddn == NULL || *binddn == '\0') {
2464 2466 (void) sprintf(errstr,
2465 2467 gettext("openConnection: missing credentials "
2466 2468 "for SASL bind"));
2467 2469 MKERROR(LOG_WARNING, *errorp,
2468 2470 LDAP_INVALID_CREDENTIALS,
2469 2471 strdup(errstr), NS_LDAP_MEMORY);
2470 2472 (void) ldap_unbind(ld);
2471 2473 return (NS_LDAP_INTERNAL);
2472 2474 }
2473 2475 cred.bv_val = passwd;
2474 2476 cred.bv_len = strlen(passwd);
2475 2477 }
2476 2478
2477 2479 ret_code = NS_LDAP_SUCCESS;
2478 2480
2479 2481 switch (auth->auth.saslmech) {
2480 2482 case NS_LDAP_SASL_CRAM_MD5:
2481 2483 /*
2482 2484 * NOTE: if iDS changes to support cram_md5,
2483 2485 * please add password management code here.
2484 2486 * Since ldap_sasl_cram_md5_bind_s does not
2485 2487 * return anything that could be used to
2486 2488 * extract the ldap rc/errmsg/control to
2487 2489 * determine if bind failed due to password
2488 2490 * policy, a new cram_md5_bind API will need
2489 2491 * to be introduced. See
2490 2492 * ldap_x_sasl_digest_md5_bind() and case
2491 2493 * NS_LDAP_SASL_DIGEST_MD5 below for details.
2492 2494 */
2493 2495 if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn,
2494 2496 &cred, NULL, NULL)) != LDAP_SUCCESS) {
2495 2497 (void) ldap_get_option(ld,
2496 2498 LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2497 2499 (void) snprintf(errstr, sizeof (errstr),
2498 2500 gettext("openConnection: "
2499 2501 "sasl/CRAM-MD5 bind failed - %s"),
2500 2502 ldap_err2string(errnum));
2501 2503 MKERROR(LOG_WARNING, *errorp, errnum,
2502 2504 strdup(errstr), NS_LDAP_MEMORY);
2503 2505 (void) ldap_unbind(ld);
2504 2506 return (NS_LDAP_INTERNAL);
2505 2507 }
2506 2508 break;
2507 2509 case NS_LDAP_SASL_DIGEST_MD5:
2508 2510 digest_md5_name = malloc(strlen(binddn) + 5);
2509 2511 /* 5 = strlen("dn: ") + 1 */
2510 2512 if (digest_md5_name == NULL) {
2511 2513 (void) ldap_unbind(ld);
2512 2514 return (NS_LDAP_MEMORY);
2513 2515 }
2514 2516 (void) strcpy(digest_md5_name, "dn: ");
2515 2517 (void) strcat(digest_md5_name, binddn);
2516 2518
2517 2519 tv.tv_sec = timeoutSec;
2518 2520 tv.tv_usec = 0;
2519 2521 ldap_rc = ldap_x_sasl_digest_md5_bind(ld,
2520 2522 digest_md5_name, &cred, NULL, NULL,
2521 2523 &tv, &resultMsg);
2522 2524
2523 2525 if (resultMsg == NULL) {
2524 2526 free(digest_md5_name);
2525 2527 (void) ldap_get_option(ld,
2526 2528 LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2527 2529 (void) snprintf(errstr, sizeof (errstr),
2528 2530 gettext("openConnection: "
2529 2531 "DIGEST-MD5 bind failed - %s"),
2530 2532 ldap_err2string(errnum));
2531 2533 (void) ldap_unbind(ld);
2532 2534 MKERROR(LOG_WARNING, *errorp, errnum,
2533 2535 strdup(errstr), NS_LDAP_MEMORY);
2534 2536 return (NS_LDAP_INTERNAL);
2535 2537 }
2536 2538
2537 2539 /*
2538 2540 * get ldaprc, controls, and error msg
2539 2541 */
2540 2542 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2541 2543 &errmsg, NULL, &controls, 1);
2542 2544
2543 2545 if (ldap_rc != LDAP_SUCCESS) {
2544 2546 free(digest_md5_name);
2545 2547 (void) snprintf(errstr, sizeof (errstr),
2546 2548 gettext("openConnection: "
2547 2549 "DIGEST-MD5 bind failed "
2548 2550 "- unable to parse result"));
2549 2551 (void) ldap_unbind(ld);
2550 2552 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2551 2553 strdup(errstr), NS_LDAP_MEMORY);
2552 2554 return (NS_LDAP_INTERNAL);
2553 2555 }
2554 2556
2555 2557 /* process the password management info, if any */
2556 2558 ret_code = process_pwd_mgmt("sasl/DIGEST-MD5",
2557 2559 errnum, controls, errmsg,
2558 2560 errorp,
2559 2561 fail_if_new_pwd_reqd,
2560 2562 passwd_mgmt);
2561 2563
2562 2564 if (ret_code == NS_LDAP_INTERNAL) {
2563 2565 (void) ldap_unbind(ld);
2564 2566 }
2565 2567
2566 2568 free(digest_md5_name);
2567 2569 break;
2568 2570 case NS_LDAP_SASL_GSSAPI:
2569 2571 (void) memset(&sasl_param, 0,
2570 2572 sizeof (ns_sasl_cb_param_t));
2571 2573 sasl_param.authid = NULL;
2572 2574 sasl_param.authzid = "";
2573 2575 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN,
2574 2576 (void *)&min_ssf);
2575 2577 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX,
2576 2578 (void *)&max_ssf);
2577 2579
2578 2580 ldap_rc = ldap_sasl_interactive_bind_s(
2579 2581 ld, NULL, "GSSAPI",
2580 2582 NULL, NULL, LDAP_SASL_INTERACTIVE,
2581 2583 __s_api_sasl_bind_callback,
2582 2584 &sasl_param);
2583 2585
2584 2586 if (ldap_rc != LDAP_SUCCESS) {
2585 2587 (void) snprintf(errstr, sizeof (errstr),
2586 2588 gettext("openConnection: "
2587 2589 "GSSAPI bind failed "
2588 2590 "- %d %s"),
2589 2591 ldap_rc,
2590 2592 ldap_err2string(ldap_rc));
2591 2593 (void) ldap_unbind(ld);
2592 2594 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2593 2595 strdup(errstr), NS_LDAP_MEMORY);
2594 2596 return (NS_LDAP_INTERNAL);
2595 2597 }
2596 2598
2597 2599 break;
2598 2600 default:
2599 2601 (void) ldap_unbind(ld);
2600 2602 (void) sprintf(errstr,
2601 2603 gettext("openConnection: unsupported SASL "
2602 2604 "mechanism (%d)"), auth->auth.saslmech);
2603 2605 MKERROR(LOG_WARNING, *errorp,
2604 2606 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2605 2607 NS_LDAP_MEMORY);
2606 2608 return (NS_LDAP_INTERNAL);
2607 2609 }
2608 2610
2609 2611 return (ret_code);
2610 2612 }
2611 2613
2612 2614 /*
2613 2615 * This function performs an LDAP Bind operation proceeding
2614 2616 * from a type of the connection specified by auth->auth.type.
2615 2617 *
2616 2618 * INPUT:
2617 2619 * auth - a structure specified an authenticastion method and credentials,
2618 2620 * ld - a pointer returned by the createSession() function,
2619 2621 * timeoutSec - a timeout in seconds for the Bind operation,
2620 2622 * fail_if_new_pwd_reqd - a flag indicating that the call should fail
2621 2623 * if a new password is required,
2622 2624 * passwd_mgmt - a flag indicating that the server supports
2623 2625 * password management.
2624 2626 *
2625 2627 * OUTPUT:
2626 2628 * If an error accures, the function returns an NS error code
2627 2629 * and provides an additional info pointed by *errorp.
2628 2630 */
2629 2631 static
2630 2632 ns_ldap_return_code
2631 2633 performBind(const ns_cred_t *auth,
2632 2634 LDAP *ld,
2633 2635 int timeoutSec,
2634 2636 ns_ldap_error_t **errorp,
2635 2637 int fail_if_new_pwd_reqd,
2636 2638 int passwd_mgmt)
2637 2639 {
2638 2640 int bindType;
2639 2641 char errstr[MAXERROR];
2640 2642
2641 2643 ns_ldap_return_code (*binder)(const ns_cred_t *auth,
2642 2644 LDAP *ld,
2643 2645 int timeoutSec,
2644 2646 ns_ldap_error_t **errorp,
2645 2647 int fail_if_new_pwd_reqd,
2646 2648 int passwd_mgmt) = NULL;
2647 2649
2648 2650 if (!ld) {
2649 2651 (void) sprintf(errstr,
2650 2652 "performBind: LDAP session "
2651 2653 "is not initialized.");
2652 2654 MKERROR(LOG_WARNING, *errorp,
2653 2655 LDAP_AUTH_METHOD_NOT_SUPPORTED,
2654 2656 strdup(errstr), NS_LDAP_MEMORY);
2655 2657 return (NS_LDAP_INTERNAL);
2656 2658 }
2657 2659
2658 2660 bindType = auth->auth.type == NS_LDAP_AUTH_TLS ?
2659 2661 auth->auth.tlstype : auth->auth.type;
2660 2662
2661 2663 switch (bindType) {
2662 2664 case NS_LDAP_AUTH_NONE:
2663 2665 #ifdef DEBUG
2664 2666 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n",
2665 2667 thr_self());
2666 2668 #endif /* DEBUG */
2667 2669 break;
2668 2670 case NS_LDAP_AUTH_SIMPLE:
2669 2671 binder = doSimpleBind;
2670 2672 break;
2671 2673 case NS_LDAP_AUTH_SASL:
2672 2674 binder = doSASLBind;
2673 2675 break;
2674 2676 default:
2675 2677 (void) sprintf(errstr,
2676 2678 gettext("openConnection: unsupported "
2677 2679 "authentication method "
2678 2680 "(%d)"), bindType);
2679 2681 MKERROR(LOG_WARNING, *errorp,
2680 2682 LDAP_AUTH_METHOD_NOT_SUPPORTED,
2681 2683 strdup(errstr), NS_LDAP_MEMORY);
2682 2684 (void) ldap_unbind(ld);
2683 2685 return (NS_LDAP_INTERNAL);
2684 2686 }
2685 2687
2686 2688 if (binder != NULL) {
2687 2689 return (*binder)(auth,
2688 2690 ld,
2689 2691 timeoutSec,
2690 2692 errorp,
2691 2693 fail_if_new_pwd_reqd,
2692 2694 passwd_mgmt);
2693 2695 }
2694 2696
2695 2697 return (NS_LDAP_SUCCESS);
2696 2698 }
↓ open down ↓ |
1982 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX