4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <sys/types.h>
34 #include <sasl/sasl.h>
35 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
45 #include "ns_internal.h"
47 static int self_gssapi_only
= 0;
48 static mutex_t self_gssapi_only_lock
= DEFAULTMUTEX
;
50 #define DNS_FMRI "svc:/network/dns/client:default"
53 #define NSSWITCH_CONF "/etc/nsswitch.conf"
58 #define CLIENT_FPRINTF if (mode_verbose && !mode_quiet) (void) fprintf
61 * nscd calls this function to set self_gssapi_only flag so libsldap performs
62 * sasl/GSSAPI bind only. Also see comments of __ns_ldap_self_gssapi_config.
64 * Input: flag 0 use any kind of connection
65 * 1 use self/gssapi connection only
68 __ns_ldap_self_gssapi_only_set(int flag
) {
69 (void) mutex_lock(&self_gssapi_only_lock
);
70 self_gssapi_only
= flag
;
71 (void) mutex_unlock(&self_gssapi_only_lock
);
75 * Get the flag value of self_gssapi_only
78 __s_api_self_gssapi_only_get(void) {
80 (void) mutex_lock(&self_gssapi_only_lock
);
81 flag
= self_gssapi_only
;
82 (void) mutex_unlock(&self_gssapi_only_lock
);
87 * nscd calls this function to detect the current native ldap configuration.
89 * NS_LDAP_SELF_GSSAPI_CONFIG_NONE: No credential level self and
90 * no authentication method sasl/GSSAPI is
92 * NS_LDAP_SELF_GSSAPI_CONFIG_ONLY: Only credential level self and
93 * authentication method sasl/GSSAPI are
95 * NS_LDAP_SELF_GSSAPI_CONFIG_MIXED: More than one credential level are
96 * configured, including self.
97 * More than one authentication method
98 * are configured, including sasl/GSSAPI.
100 * __s_api_crosscheck makes sure self and sasl/GSSAPI pair up if they do
103 * When nscd detects it's MIXED case, it calls __ns_ldap_self_gssapi_only_set
104 * to force libsldap to do sasl/GSSAPI bind only for per-user lookup.
106 * Return: NS_LDAP_SUCCESS
107 * OTHERWISE - FAILURE
109 * Output: config. See comments above.
113 __ns_ldap_self_gssapi_config(ns_ldap_self_gssapi_config_t
*config
) {
114 int self
= 0, other_level
= 0, gssapi
= 0, other_method
= 0;
115 ns_auth_t
**aMethod
= NULL
, **aNext
= NULL
;
116 int **cLevel
= NULL
, **cNext
= NULL
, rc
;
117 ns_ldap_error_t
*errp
= NULL
;
121 return (NS_LDAP_INVALID_PARAM
);
123 *config
= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
;
126 * If config files don't exist, return NS_LDAP_CONFIG.
127 * It's the same return code __ns_ldap_getParam
128 * returns in the same situation.
130 if ((fp
= fopen(NSCONFIGFILE
, "rF")) == NULL
)
131 return (NS_LDAP_CONFIG
);
134 if ((fp
= fopen(NSCREDFILE
, "rF")) == NULL
)
135 return (NS_LDAP_CONFIG
);
139 /* Get the credential level list */
140 if ((rc
= __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P
,
141 (void ***)&cLevel
, &errp
)) != NS_LDAP_SUCCESS
) {
143 (void) __ns_ldap_freeError(&errp
);
145 (void) __ns_ldap_freeParam((void ***)&cLevel
);
149 (void) __ns_ldap_freeError(&errp
);
150 /* Get the authentication method list */
151 if ((rc
= __ns_ldap_getParam(NS_LDAP_AUTH_P
,
152 (void ***)&aMethod
, &errp
)) != NS_LDAP_SUCCESS
) {
154 (void) __ns_ldap_freeError(&errp
);
156 (void) __ns_ldap_freeParam((void ***)&cLevel
);
158 (void) __ns_ldap_freeParam((void ***)&aMethod
);
162 (void) __ns_ldap_freeError(&errp
);
164 if (cLevel
== NULL
|| aMethod
== NULL
) {
166 (void) __ns_ldap_freeParam((void ***)&cLevel
);
168 (void) __ns_ldap_freeParam((void ***)&aMethod
);
169 return (NS_LDAP_SUCCESS
);
172 for (cNext
= cLevel
; *cNext
!= NULL
; cNext
++) {
173 if (**cNext
== NS_LDAP_CRED_SELF
)
178 for (aNext
= aMethod
; *aNext
!= NULL
; aNext
++) {
179 if ((*aNext
)->saslmech
== NS_LDAP_SASL_GSSAPI
)
185 if (self
> 0 && gssapi
> 0) {
186 if (other_level
== 0 && other_method
== 0)
187 *config
= NS_LDAP_SELF_GSSAPI_CONFIG_ONLY
;
189 *config
= NS_LDAP_SELF_GSSAPI_CONFIG_MIXED
;
193 (void) __ns_ldap_freeParam((void ***)&cLevel
);
195 (void) __ns_ldap_freeParam((void ***)&aMethod
);
196 return (NS_LDAP_SUCCESS
);
200 __s_api_sasl_bind_callback(
201 /* LINTED E_FUNC_ARG_UNUSED */
203 /* LINTED E_FUNC_ARG_UNUSED */
209 sasl_interact_t
*interact
= in
;
210 ns_sasl_cb_param_t
*cred
= (ns_sasl_cb_param_t
*)defaults
;
213 while (interact
->id
!= SASL_CB_LIST_END
) {
215 switch (interact
->id
) {
217 case SASL_CB_GETREALM
:
220 case SASL_CB_AUTHNAME
:
229 case SASL_CB_NOECHOPROMPT
:
230 case SASL_CB_ECHOPROMPT
:
237 * No need to do strdup(ret), the data is always
238 * available in 'defaults' and libldap won't
239 * free it either. strdup(ret) causes memory
242 interact
->result
= ret
;
243 interact
->len
= strlen(ret
);
245 interact
->result
= NULL
;
251 return (LDAP_SUCCESS
);
255 * Find "dbase: service1 [...] services2" in fname and return
256 * " service1 [...] services2"
258 * Find "hosts: files dns" and return " files dns"
261 __ns_nsw_getconfig(const char *dbase
, const char *fname
, int *errp
)
264 char *linep
, *retp
= NULL
;
265 char lineq
[BUFSIZ
], db_colon
[BUFSIZ
];
267 if ((fp
= fopen(fname
, "rF")) == NULL
) {
268 *errp
= NS_LDAP_CONFIG
;
271 *errp
= NS_LDAP_SUCCESS
;
273 while (linep
= fgets(lineq
, BUFSIZ
, fp
)) {
274 char *tokenp
, *comment
;
277 * Ignore portion of line following the comment character '#'.
279 if ((comment
= strchr(linep
, '#')) != NULL
) {
282 if ((*linep
== '\0') || isspace(*linep
)) {
285 (void) snprintf(db_colon
, BUFSIZ
, "%s:", dbase
);
286 if ((tokenp
= strstr(linep
, db_colon
)) == NULL
) {
287 continue; /* ignore this line */
290 retp
= strdup(tokenp
+ strlen(db_colon
));
292 *errp
= NS_LDAP_MEMORY
;
300 * Test the configurations of the "hosts" and "ipnodes"
301 * dns has to be present and appear before ldap
303 * "dns" , "dns files" "dns ldap files", "files dns" are allowed.
305 * Kerberos requires dns or it'd fail.
308 test_dns_nsswitch(int foreground
,
310 ns_ldap_error_t
**errpp
) {
311 int ldap
, dns
, i
, pserr
, rc
= NS_LDAP_SUCCESS
;
312 char *db
[3] = {"hosts", "ipnodes", NULL
};
313 char buf
[MSGSIZE
], *conf
= NULL
, *token
= NULL
, *last
= NULL
;
315 for (i
= 0; db
[i
] != NULL
; i
++) {
316 conf
= __ns_nsw_getconfig(db
[i
], fname
, &pserr
);
319 (void) snprintf(buf
, MSGSIZE
,
320 gettext("Parsing %s to find \"%s:\" "
322 fname
, db
[i
], pserr
);
324 (void) fprintf(stderr
, "%s\n", buf
);
326 MKERROR(LOG_ERR
, *errpp
, NS_LDAP_CONFIG
,
327 strdup(buf
), NS_LDAP_MEMORY
);
332 token
= strtok_r(conf
, " ", &last
);
333 while (token
!= NULL
) {
334 if (strncmp(token
, "dns", 3) == 0) {
336 (void) snprintf(buf
, MSGSIZE
,
337 gettext("%s: ldap can't appear "
338 "before dns"), db
[i
]);
340 (void) fprintf(stderr
,
344 MKERROR(LOG_ERR
, *errpp
,
350 return (NS_LDAP_CONFIG
);
354 } else if (strncmp(token
, "ldap", 4) == 0) {
358 token
= strtok_r(NULL
, " ", &last
);
365 (void) snprintf(buf
, MSGSIZE
,
366 gettext("%s: dns is not defined in "
367 "%s"), db
[i
], fname
);
369 (void) fprintf(stderr
, "start: %s\n", buf
);
371 MKERROR(LOG_ERR
, *errpp
, NS_LDAP_CONFIG
,
372 strdup(buf
), NS_LDAP_MEMORY
);
382 is_service(const char *fmri
, const char *state
) {
384 boolean_t result
= B_FALSE
;
386 if ((st
= smf_get_state(fmri
)) != NULL
) {
387 if (strcmp(st
, state
) == 0)
396 * This function checks dns prerequisites for sasl/GSSAPI bind.
397 * It's called only if config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY ||
398 * config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED.
401 __ns_ldap_check_dns_preq(int foreground
,
405 ns_ldap_self_gssapi_config_t config
,
406 ns_ldap_error_t
**errpp
) {
409 int retcode
= NS_LDAP_SUCCESS
;
415 return (NS_LDAP_INVALID_PARAM
);
417 if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_NONE
)
418 /* Shouldn't happen. Check this value just in case */
419 return (NS_LDAP_SUCCESS
);
421 if ((retcode
= test_dns_nsswitch(foreground
, fname
, errpp
)) !=
425 if (is_service(DNS_FMRI
, SCF_STATE_STRING_ONLINE
)) {
427 CLIENT_FPRINTF(stdout
, "start: %s\n",
428 gettext("DNS client is enabled"));
430 syslog(LOG_INFO
, "libsldap: %s",
431 gettext("DNS client is enabled"));
433 return (NS_LDAP_SUCCESS
);
435 if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_ONLY
) {
436 (void) snprintf(buf
, MSGSIZE
,
437 gettext("%s: DNS client is not enabled. "
438 "Run \"svcadm enable %s\". %s."),
439 "Error", DNS_FMRI
, "Abort");
441 retcode
= NS_LDAP_CONFIG
;
442 } else if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_MIXED
) {
443 (void) snprintf(buf
, MSGSIZE
,
444 gettext("%s: DNS client is not enabled. "
445 "Run \"svcadm enable %s\". %s."
446 "Fall back to other cred level/bind. "),
447 "Warning", DNS_FMRI
, "Continue");
449 retcode
= NS_LDAP_SUCCESS
;
453 (void) fprintf(stderr
, "start: %s\n", buf
);
455 MKERROR(loglevel
, *errpp
, retcode
, strdup(buf
),
463 * Check if sasl/GSSAPI works
466 __ns_ldap_check_gssapi_preq(int foreground
,
469 ns_ldap_self_gssapi_config_t config
,
470 ns_ldap_error_t
**errpp
) {
473 char *attr
[2] = {"dn", NULL
}, buf
[MSGSIZE
];
475 ns_ldap_result_t
*result
= NULL
;
481 return (NS_LDAP_INVALID_PARAM
);
483 if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_NONE
)
484 /* Don't need to check */
485 return (NS_LDAP_SUCCESS
);
487 (void) memset(&cred
, 0, sizeof (ns_cred_t
));
489 cred
.auth
.type
= NS_LDAP_AUTH_SASL
;
490 cred
.auth
.tlstype
= NS_LDAP_TLS_NONE
;
491 cred
.auth
.saslmech
= NS_LDAP_SASL_GSSAPI
;
493 rc
= __ns_ldap_list(NULL
, (const char *)"objectclass=*",
494 NULL
, (const char **)attr
, &cred
,
495 NS_LDAP_SCOPE_BASE
, &result
, errpp
, NULL
, NULL
);
497 (void) __ns_ldap_freeResult(&result
);
499 if (rc
== NS_LDAP_SUCCESS
) {
501 CLIENT_FPRINTF(stdout
, "start: %s\n",
502 gettext("sasl/GSSAPI bind works"));
504 syslog(LOG_INFO
, "libsldap: %s",
505 gettext("sasl/GSSAPI bind works"));
507 return (NS_LDAP_SUCCESS
);
509 if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_ONLY
) {
510 (void) snprintf(buf
, MSGSIZE
,
511 gettext("%s: sasl/GSSAPI bind is not "
515 } else if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_MIXED
) {
516 (void) snprintf(buf
, MSGSIZE
,
517 gettext("%s: sasl/GSSAPI bind is not "
518 "working. Fall back to other cred "
520 "Warning", "Continue");
522 /* reset return code */
523 rc
= NS_LDAP_SUCCESS
;
527 (void) fprintf(stderr
, "start: %s\n", buf
);
529 MKERROR(loglevel
, *errpp
, rc
, strdup(buf
),
536 * This is called by ldap_cachemgr to check dns and gssapi prequisites.
539 __ns_ldap_check_all_preq(int foreground
,
542 ns_ldap_self_gssapi_config_t config
,
543 ns_ldap_error_t
**errpp
) {
550 return (NS_LDAP_INVALID_PARAM
);
552 if (config
== NS_LDAP_SELF_GSSAPI_CONFIG_NONE
)
553 /* Don't need to check */
554 return (NS_LDAP_SUCCESS
);
556 if ((rc
= __ns_ldap_check_dns_preq(foreground
,
557 mode_verbose
, mode_quiet
, NSSWITCH_CONF
,
558 config
, errpp
)) != NS_LDAP_SUCCESS
)
560 if ((rc
= __ns_ldap_check_gssapi_preq(foreground
,
561 mode_verbose
, mode_quiet
, config
, errpp
)) !=
565 return (NS_LDAP_SUCCESS
);