1*cb5caa98Sdjl /*
2*cb5caa98Sdjl  * CDDL HEADER START
3*cb5caa98Sdjl  *
4*cb5caa98Sdjl  * The contents of this file are subject to the terms of the
5*cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6*cb5caa98Sdjl  * You may not use this file except in compliance with the License.
7*cb5caa98Sdjl  *
8*cb5caa98Sdjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*cb5caa98Sdjl  * or http://www.opensolaris.org/os/licensing.
10*cb5caa98Sdjl  * See the License for the specific language governing permissions
11*cb5caa98Sdjl  * and limitations under the License.
12*cb5caa98Sdjl  *
13*cb5caa98Sdjl  * When distributing Covered Code, include this CDDL HEADER in each
14*cb5caa98Sdjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*cb5caa98Sdjl  * If applicable, add the following below this CDDL HEADER, with the
16*cb5caa98Sdjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*cb5caa98Sdjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*cb5caa98Sdjl  *
19*cb5caa98Sdjl  * CDDL HEADER END
20*cb5caa98Sdjl  */
21*cb5caa98Sdjl /*
22*cb5caa98Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*cb5caa98Sdjl  * Use is subject to license terms.
24*cb5caa98Sdjl  */
25*cb5caa98Sdjl 
26*cb5caa98Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*cb5caa98Sdjl 
28*cb5caa98Sdjl #include <stdio.h>
29*cb5caa98Sdjl #include <stdlib.h>
30*cb5caa98Sdjl #include <strings.h>
31*cb5caa98Sdjl #include <sys/types.h>
32*cb5caa98Sdjl #include <sys/stat.h>
33*cb5caa98Sdjl #include <unistd.h>
34*cb5caa98Sdjl #include <thread.h>
35*cb5caa98Sdjl #include <synch.h>
36*cb5caa98Sdjl #include <sasl/sasl.h>
37*cb5caa98Sdjl #include <sys/socket.h>
38*cb5caa98Sdjl #include <netdb.h>
39*cb5caa98Sdjl #include <netinet/in.h>
40*cb5caa98Sdjl #include <arpa/inet.h>
41*cb5caa98Sdjl #include <syslog.h>
42*cb5caa98Sdjl #include <ctype.h>
43*cb5caa98Sdjl #include <libscf.h>
44*cb5caa98Sdjl #include <libintl.h>
45*cb5caa98Sdjl #include <locale.h>
46*cb5caa98Sdjl #include "ns_sldap.h"
47*cb5caa98Sdjl #include "ns_internal.h"
48*cb5caa98Sdjl 
49*cb5caa98Sdjl static int self_gssapi_only = 0;
50*cb5caa98Sdjl static mutex_t self_gssapi_only_lock = DEFAULTMUTEX;
51*cb5caa98Sdjl 
52*cb5caa98Sdjl #define	DNS_FMRI	"svc:/network/dns/client:default"
53*cb5caa98Sdjl #define	MSGSIZE		256
54*cb5caa98Sdjl 
55*cb5caa98Sdjl #define	NSSWITCH_CONF	"/etc/nsswitch.conf"
56*cb5caa98Sdjl 
57*cb5caa98Sdjl /*
58*cb5caa98Sdjl  * Error Handling
59*cb5caa98Sdjl  */
60*cb5caa98Sdjl #define	CLIENT_FPRINTF if (mode_verbose && !mode_quiet) (void) fprintf
61*cb5caa98Sdjl 
62*cb5caa98Sdjl /*
63*cb5caa98Sdjl  * One time initializtion
64*cb5caa98Sdjl  */
65*cb5caa98Sdjl int		sasl_gssapi_inited = 0;
66*cb5caa98Sdjl static mutex_t	sasl_gssapi_lock = DEFAULTMUTEX;
67*cb5caa98Sdjl int
68*cb5caa98Sdjl __s_api_sasl_gssapi_init(void) {
69*cb5caa98Sdjl 	int rc = NS_LDAP_SUCCESS;
70*cb5caa98Sdjl 	(void) mutex_lock(&sasl_gssapi_lock);
71*cb5caa98Sdjl 	if (!sasl_gssapi_inited) {
72*cb5caa98Sdjl 			if (getuid() == 0) {
73*cb5caa98Sdjl 				if (system(
74*cb5caa98Sdjl 					"/usr/sbin/cryptoadm disable metaslot")
75*cb5caa98Sdjl 					== 0) {
76*cb5caa98Sdjl 					syslog(LOG_WARNING,
77*cb5caa98Sdjl 						"libsldap: Metaslot disabled "
78*cb5caa98Sdjl 						"for self credential mode");
79*cb5caa98Sdjl 					sasl_gssapi_inited = 1;
80*cb5caa98Sdjl 				} else {
81*cb5caa98Sdjl 					syslog(LOG_ERR,
82*cb5caa98Sdjl 						"libsldap: Can't disable "
83*cb5caa98Sdjl 						"Metaslot for self credential "
84*cb5caa98Sdjl 						"mode");
85*cb5caa98Sdjl 					rc = NS_LDAP_INTERNAL;
86*cb5caa98Sdjl 				}
87*cb5caa98Sdjl 			}
88*cb5caa98Sdjl 	}
89*cb5caa98Sdjl 	(void) mutex_unlock(&sasl_gssapi_lock);
90*cb5caa98Sdjl 
91*cb5caa98Sdjl 	return (rc);
92*cb5caa98Sdjl }
93*cb5caa98Sdjl 
94*cb5caa98Sdjl /*
95*cb5caa98Sdjl  * nscd calls this function to set self_gssapi_only flag so libsldap performs
96*cb5caa98Sdjl  * sasl/GSSAPI bind only. Also see comments of __ns_ldap_self_gssapi_config.
97*cb5caa98Sdjl  *
98*cb5caa98Sdjl  * Input: flag 0 use any kind of connection
99*cb5caa98Sdjl  *             1 use self/gssapi connection only
100*cb5caa98Sdjl  */
101*cb5caa98Sdjl void
102*cb5caa98Sdjl __ns_ldap_self_gssapi_only_set(int flag) {
103*cb5caa98Sdjl 	(void) mutex_lock(&self_gssapi_only_lock);
104*cb5caa98Sdjl 	self_gssapi_only = flag;
105*cb5caa98Sdjl 	(void) mutex_unlock(&self_gssapi_only_lock);
106*cb5caa98Sdjl }
107*cb5caa98Sdjl /*
108*cb5caa98Sdjl  * Get the flag value of self_gssapi_only
109*cb5caa98Sdjl  */
110*cb5caa98Sdjl int
111*cb5caa98Sdjl __s_api_self_gssapi_only_get(void) {
112*cb5caa98Sdjl 	int flag;
113*cb5caa98Sdjl 	(void) mutex_lock(&self_gssapi_only_lock);
114*cb5caa98Sdjl 	flag = self_gssapi_only;
115*cb5caa98Sdjl 	(void) mutex_unlock(&self_gssapi_only_lock);
116*cb5caa98Sdjl 	return (flag);
117*cb5caa98Sdjl }
118*cb5caa98Sdjl /*
119*cb5caa98Sdjl  * nscd calls this function to detect the current native ldap configuration.
120*cb5caa98Sdjl  * The output are
121*cb5caa98Sdjl  * NS_LDAP_SELF_GSSAPI_CONFIG_NONE: No credential level self and
122*cb5caa98Sdjl  *                                  no authentication method sasl/GSSAPI is
123*cb5caa98Sdjl  *                                  configured.
124*cb5caa98Sdjl  * NS_LDAP_SELF_GSSAPI_CONFIG_ONLY: Only credential level self and
125*cb5caa98Sdjl  *                                  authentication method sasl/GSSAPI are
126*cb5caa98Sdjl  *                                  configured.
127*cb5caa98Sdjl  * NS_LDAP_SELF_GSSAPI_CONFIG_MIXED: More than one credential level are
128*cb5caa98Sdjl  *                                   configured, including self.
129*cb5caa98Sdjl  *                                   More than one authentication method
130*cb5caa98Sdjl  *                                   are configured, including sasl/GSSAPI.
131*cb5caa98Sdjl  *
132*cb5caa98Sdjl  * __s_api_crosscheck makes sure self and sasl/GSSAPI pair up if they do
133*cb5caa98Sdjl  * get configured.
134*cb5caa98Sdjl  *
135*cb5caa98Sdjl  * When nscd detects it's MIXED case, it calls __ns_ldap_self_gssapi_only_set
136*cb5caa98Sdjl  * to force libsldap to do sasl/GSSAPI bind only for per-user lookup.
137*cb5caa98Sdjl  *
138*cb5caa98Sdjl  * Return: NS_LDAP_SUCCESS
139*cb5caa98Sdjl  *         OTHERWISE - FAILURE
140*cb5caa98Sdjl  *
141*cb5caa98Sdjl  * Output: config. See comments above.
142*cb5caa98Sdjl  *
143*cb5caa98Sdjl  */
144*cb5caa98Sdjl int
145*cb5caa98Sdjl __ns_ldap_self_gssapi_config(ns_ldap_self_gssapi_config_t *config) {
146*cb5caa98Sdjl 	int	self = 0, other_level = 0, gssapi = 0, other_method = 0;
147*cb5caa98Sdjl 	ns_auth_t	**aMethod = NULL, **aNext = NULL;
148*cb5caa98Sdjl 	int		**cLevel = NULL, **cNext = NULL, rc;
149*cb5caa98Sdjl 	ns_ldap_error_t	*errp = NULL;
150*cb5caa98Sdjl 
151*cb5caa98Sdjl 	if (config == NULL)
152*cb5caa98Sdjl 		return (NS_LDAP_INVALID_PARAM);
153*cb5caa98Sdjl 	else
154*cb5caa98Sdjl 		*config = NS_LDAP_SELF_GSSAPI_CONFIG_NONE;
155*cb5caa98Sdjl 
156*cb5caa98Sdjl 	/* Get the credential level list */
157*cb5caa98Sdjl 	if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
158*cb5caa98Sdjl 		(void ***)&cLevel, &errp)) != NS_LDAP_SUCCESS) {
159*cb5caa98Sdjl 		if (errp)
160*cb5caa98Sdjl 			(void) __ns_ldap_freeError(&errp);
161*cb5caa98Sdjl 		if (cLevel)
162*cb5caa98Sdjl 			(void) __ns_ldap_freeParam((void ***)&cLevel);
163*cb5caa98Sdjl 		return (rc);
164*cb5caa98Sdjl 	}
165*cb5caa98Sdjl 	if (errp)
166*cb5caa98Sdjl 		(void) __ns_ldap_freeError(&errp);
167*cb5caa98Sdjl 	/* Get the authentication method list */
168*cb5caa98Sdjl 	if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
169*cb5caa98Sdjl 		(void ***)&aMethod, &errp)) != NS_LDAP_SUCCESS) {
170*cb5caa98Sdjl 		if (errp)
171*cb5caa98Sdjl 			(void) __ns_ldap_freeError(&errp);
172*cb5caa98Sdjl 		if (cLevel)
173*cb5caa98Sdjl 			(void) __ns_ldap_freeParam((void ***)&cLevel);
174*cb5caa98Sdjl 		if (aMethod)
175*cb5caa98Sdjl 			(void) __ns_ldap_freeParam((void ***)&aMethod);
176*cb5caa98Sdjl 		return (rc);
177*cb5caa98Sdjl 	}
178*cb5caa98Sdjl 	if (errp)
179*cb5caa98Sdjl 		(void) __ns_ldap_freeError(&errp);
180*cb5caa98Sdjl 
181*cb5caa98Sdjl 	if (cLevel == NULL || aMethod == NULL) {
182*cb5caa98Sdjl 		if (cLevel)
183*cb5caa98Sdjl 			(void) __ns_ldap_freeParam((void ***)&cLevel);
184*cb5caa98Sdjl 		if (aMethod)
185*cb5caa98Sdjl 			(void) __ns_ldap_freeParam((void ***)&aMethod);
186*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
187*cb5caa98Sdjl 	}
188*cb5caa98Sdjl 
189*cb5caa98Sdjl 	for (cNext = cLevel; *cNext != NULL; cNext++) {
190*cb5caa98Sdjl 		if (**cNext == NS_LDAP_CRED_SELF)
191*cb5caa98Sdjl 			self++;
192*cb5caa98Sdjl 		else
193*cb5caa98Sdjl 			other_level++;
194*cb5caa98Sdjl 	}
195*cb5caa98Sdjl 	for (aNext = aMethod; *aNext != NULL; aNext++) {
196*cb5caa98Sdjl 		if ((*aNext)->saslmech == NS_LDAP_SASL_GSSAPI)
197*cb5caa98Sdjl 			gssapi++;
198*cb5caa98Sdjl 		else
199*cb5caa98Sdjl 			other_method++;
200*cb5caa98Sdjl 	}
201*cb5caa98Sdjl 
202*cb5caa98Sdjl 	if (self > 0 && gssapi > 0) {
203*cb5caa98Sdjl 		if (other_level == 0 && other_method == 0)
204*cb5caa98Sdjl 			*config = NS_LDAP_SELF_GSSAPI_CONFIG_ONLY;
205*cb5caa98Sdjl 		else
206*cb5caa98Sdjl 			*config = NS_LDAP_SELF_GSSAPI_CONFIG_MIXED;
207*cb5caa98Sdjl 	}
208*cb5caa98Sdjl 
209*cb5caa98Sdjl 	if (cLevel)
210*cb5caa98Sdjl 		(void) __ns_ldap_freeParam((void ***)&cLevel);
211*cb5caa98Sdjl 	if (aMethod)
212*cb5caa98Sdjl 		(void) __ns_ldap_freeParam((void ***)&aMethod);
213*cb5caa98Sdjl 	return (NS_LDAP_SUCCESS);
214*cb5caa98Sdjl }
215*cb5caa98Sdjl 
216*cb5caa98Sdjl int
217*cb5caa98Sdjl __s_api_sasl_bind_callback(
218*cb5caa98Sdjl 	/* LINTED E_FUNC_ARG_UNUSED */
219*cb5caa98Sdjl 	LDAP		*ld,
220*cb5caa98Sdjl 	/* LINTED E_FUNC_ARG_UNUSED */
221*cb5caa98Sdjl 	unsigned	flags,
222*cb5caa98Sdjl 	void		*defaults,
223*cb5caa98Sdjl 	void		*in)
224*cb5caa98Sdjl {
225*cb5caa98Sdjl 	char		*ret = NULL;
226*cb5caa98Sdjl 	sasl_interact_t *interact = in;
227*cb5caa98Sdjl 	ns_sasl_cb_param_t	*cred = (ns_sasl_cb_param_t *)defaults;
228*cb5caa98Sdjl 
229*cb5caa98Sdjl 
230*cb5caa98Sdjl 	while (interact->id != SASL_CB_LIST_END) {
231*cb5caa98Sdjl 
232*cb5caa98Sdjl 		switch (interact->id) {
233*cb5caa98Sdjl 
234*cb5caa98Sdjl 		case SASL_CB_GETREALM:
235*cb5caa98Sdjl 			ret =   cred->realm;
236*cb5caa98Sdjl 			break;
237*cb5caa98Sdjl 		case SASL_CB_AUTHNAME:
238*cb5caa98Sdjl 			ret = cred->authid;
239*cb5caa98Sdjl 			break;
240*cb5caa98Sdjl 		case SASL_CB_PASS:
241*cb5caa98Sdjl 			ret = cred->passwd;
242*cb5caa98Sdjl 			break;
243*cb5caa98Sdjl 		case SASL_CB_USER:
244*cb5caa98Sdjl 			ret = cred->authzid;
245*cb5caa98Sdjl 			break;
246*cb5caa98Sdjl 		case SASL_CB_NOECHOPROMPT:
247*cb5caa98Sdjl 		case SASL_CB_ECHOPROMPT:
248*cb5caa98Sdjl 		default:
249*cb5caa98Sdjl 			break;
250*cb5caa98Sdjl 		}
251*cb5caa98Sdjl 
252*cb5caa98Sdjl 		if (ret) {
253*cb5caa98Sdjl 			interact->result = strdup(ret);
254*cb5caa98Sdjl 			if (interact->result == NULL)
255*cb5caa98Sdjl 				return (LDAP_NO_MEMORY);
256*cb5caa98Sdjl 
257*cb5caa98Sdjl 			interact->len = strlen(ret);
258*cb5caa98Sdjl 		} else {
259*cb5caa98Sdjl 			interact->result = NULL;
260*cb5caa98Sdjl 			interact->len = 0;
261*cb5caa98Sdjl 		}
262*cb5caa98Sdjl 		interact++;
263*cb5caa98Sdjl 	}
264*cb5caa98Sdjl 
265*cb5caa98Sdjl 	return (LDAP_SUCCESS);
266*cb5caa98Sdjl }
267*cb5caa98Sdjl 
268*cb5caa98Sdjl /*
269*cb5caa98Sdjl  * Find "dbase: service1 [...] services2" in fname and return
270*cb5caa98Sdjl  * " service1 [...] services2"
271*cb5caa98Sdjl  * e.g.
272*cb5caa98Sdjl  * Find "hosts: files dns" and return " files dns"
273*cb5caa98Sdjl  */
274*cb5caa98Sdjl static char *
275*cb5caa98Sdjl __ns_nsw_getconfig(const char *dbase, const char *fname, int *errp)
276*cb5caa98Sdjl {
277*cb5caa98Sdjl 	FILE *fp = NULL;
278*cb5caa98Sdjl 	char *linep, *retp = NULL;
279*cb5caa98Sdjl 	char lineq[BUFSIZ], db_colon[BUFSIZ];
280*cb5caa98Sdjl 
281*cb5caa98Sdjl 	if ((fp = fopen(fname, "rF")) == NULL) {
282*cb5caa98Sdjl 		*errp = NS_LDAP_CONFIG;
283*cb5caa98Sdjl 		return (NULL);
284*cb5caa98Sdjl 	}
285*cb5caa98Sdjl 	*errp = NS_LDAP_SUCCESS;
286*cb5caa98Sdjl 
287*cb5caa98Sdjl 	while (linep = fgets(lineq, BUFSIZ, fp)) {
288*cb5caa98Sdjl 		char			*tokenp, *comment;
289*cb5caa98Sdjl 
290*cb5caa98Sdjl 		/*
291*cb5caa98Sdjl 		 * Ignore portion of line following the comment character '#'.
292*cb5caa98Sdjl 		 */
293*cb5caa98Sdjl 		if ((comment = strchr(linep, '#')) != NULL) {
294*cb5caa98Sdjl 			*comment = '\0';
295*cb5caa98Sdjl 		}
296*cb5caa98Sdjl 		if ((*linep == '\0') || isspace(*linep)) {
297*cb5caa98Sdjl 			continue;
298*cb5caa98Sdjl 		}
299*cb5caa98Sdjl 		(void) snprintf(db_colon, BUFSIZ, "%s:", dbase);
300*cb5caa98Sdjl 		if ((tokenp = strstr(linep, db_colon)) == NULL) {
301*cb5caa98Sdjl 			continue; /* ignore this line */
302*cb5caa98Sdjl 		} else {
303*cb5caa98Sdjl 			/* skip "dbase:" */
304*cb5caa98Sdjl 			retp = strdup(tokenp + strlen(db_colon));
305*cb5caa98Sdjl 			if (retp == NULL)
306*cb5caa98Sdjl 				*errp = NS_LDAP_MEMORY;
307*cb5caa98Sdjl 		}
308*cb5caa98Sdjl 	}
309*cb5caa98Sdjl 
310*cb5caa98Sdjl 	(void) fclose(fp);
311*cb5caa98Sdjl 	return (retp);
312*cb5caa98Sdjl }
313*cb5caa98Sdjl /*
314*cb5caa98Sdjl  *  Test the configurations of the "hosts" and "ipnodes"
315*cb5caa98Sdjl  *  dns has to be present and appear before ldap
316*cb5caa98Sdjl  *  e.g.
317*cb5caa98Sdjl  *  "dns" , "dns files" "dns ldap files", "files dns" are allowed.
318*cb5caa98Sdjl  *
319*cb5caa98Sdjl  *  Kerberos requires dns or it'd fail.
320*cb5caa98Sdjl  */
321*cb5caa98Sdjl static int
322*cb5caa98Sdjl test_dns_nsswitch(int foreground,
323*cb5caa98Sdjl 		const char *fname,
324*cb5caa98Sdjl 		ns_ldap_error_t **errpp) {
325*cb5caa98Sdjl 	int	ldap, dns, i, pserr, rc = NS_LDAP_SUCCESS;
326*cb5caa98Sdjl 	char	*db[3] = {"hosts", "ipnodes", NULL};
327*cb5caa98Sdjl 	char	buf[MSGSIZE], *conf = NULL, *token = NULL, *last = NULL;
328*cb5caa98Sdjl 
329*cb5caa98Sdjl 	for (i = 0; db[i] != NULL; i++) {
330*cb5caa98Sdjl 		conf = __ns_nsw_getconfig(db[i], fname, &pserr);
331*cb5caa98Sdjl 
332*cb5caa98Sdjl 		if (conf == NULL) {
333*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
334*cb5caa98Sdjl 				gettext("Parsing %s to find \"%s:\" "
335*cb5caa98Sdjl 					"failed. err: %d"),
336*cb5caa98Sdjl 					fname, db[i], pserr);
337*cb5caa98Sdjl 			if (foreground) {
338*cb5caa98Sdjl 				(void) fprintf(stderr, "%s\n", buf);
339*cb5caa98Sdjl 			} else {
340*cb5caa98Sdjl 				MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG,
341*cb5caa98Sdjl 					strdup(buf), NS_LDAP_MEMORY);
342*cb5caa98Sdjl 			}
343*cb5caa98Sdjl 			return (pserr);
344*cb5caa98Sdjl 		}
345*cb5caa98Sdjl 		ldap = dns = 0;
346*cb5caa98Sdjl 		token = strtok_r(conf, " ", &last);
347*cb5caa98Sdjl 		while (token != NULL) {
348*cb5caa98Sdjl 			if (strncmp(token, "dns", 3) == 0) {
349*cb5caa98Sdjl 				if (ldap) {
350*cb5caa98Sdjl 					(void) snprintf(buf, MSGSIZE,
351*cb5caa98Sdjl 						gettext("%s: ldap can't appear "
352*cb5caa98Sdjl 						"before dns"), db[i]);
353*cb5caa98Sdjl 					if (foreground) {
354*cb5caa98Sdjl 						(void) fprintf(stderr,
355*cb5caa98Sdjl 								"start: %s\n",
356*cb5caa98Sdjl 								buf);
357*cb5caa98Sdjl 					} else {
358*cb5caa98Sdjl 						MKERROR(LOG_ERR, *errpp,
359*cb5caa98Sdjl 							NS_LDAP_CONFIG,
360*cb5caa98Sdjl 							strdup(buf),
361*cb5caa98Sdjl 							NS_LDAP_MEMORY);
362*cb5caa98Sdjl 					}
363*cb5caa98Sdjl 					free(conf);
364*cb5caa98Sdjl 					return (NS_LDAP_CONFIG);
365*cb5caa98Sdjl 				} else {
366*cb5caa98Sdjl 					dns++;
367*cb5caa98Sdjl 				}
368*cb5caa98Sdjl 			} else if (strncmp(token, "ldap", 4) == 0) {
369*cb5caa98Sdjl 				ldap++;
370*cb5caa98Sdjl 			}
371*cb5caa98Sdjl 			/* next token */
372*cb5caa98Sdjl 			token = strtok_r(NULL, " ", &last);
373*cb5caa98Sdjl 		}
374*cb5caa98Sdjl 		if (conf) {
375*cb5caa98Sdjl 			free(conf);
376*cb5caa98Sdjl 			conf = NULL;
377*cb5caa98Sdjl 		}
378*cb5caa98Sdjl 		if (!dns) {
379*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
380*cb5caa98Sdjl 				gettext("%s: dns is not defined in "
381*cb5caa98Sdjl 				"%s"), db[i], fname);
382*cb5caa98Sdjl 			if (foreground) {
383*cb5caa98Sdjl 				(void) fprintf(stderr, "start: %s\n", buf);
384*cb5caa98Sdjl 			} else {
385*cb5caa98Sdjl 				MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG,
386*cb5caa98Sdjl 					strdup(buf), NS_LDAP_MEMORY);
387*cb5caa98Sdjl 			}
388*cb5caa98Sdjl 			rc = NS_LDAP_CONFIG;
389*cb5caa98Sdjl 			break;
390*cb5caa98Sdjl 		}
391*cb5caa98Sdjl 	}
392*cb5caa98Sdjl 	return (rc);
393*cb5caa98Sdjl }
394*cb5caa98Sdjl 
395*cb5caa98Sdjl static boolean_t
396*cb5caa98Sdjl is_service(const char *fmri, const char *state) {
397*cb5caa98Sdjl 	char		*st;
398*cb5caa98Sdjl 	boolean_t	result = B_FALSE;
399*cb5caa98Sdjl 
400*cb5caa98Sdjl 	if ((st = smf_get_state(fmri)) != NULL) {
401*cb5caa98Sdjl 		if (strcmp(st, state) == 0)
402*cb5caa98Sdjl 			result = B_TRUE;
403*cb5caa98Sdjl 		free(st);
404*cb5caa98Sdjl 	}
405*cb5caa98Sdjl 	return (result);
406*cb5caa98Sdjl }
407*cb5caa98Sdjl 
408*cb5caa98Sdjl 
409*cb5caa98Sdjl /*
410*cb5caa98Sdjl  * This function checks dns prerequisites for sasl/GSSAPI bind.
411*cb5caa98Sdjl  * It's called only if config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY ||
412*cb5caa98Sdjl  *   config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED.
413*cb5caa98Sdjl  */
414*cb5caa98Sdjl int
415*cb5caa98Sdjl __ns_ldap_check_dns_preq(int foreground,
416*cb5caa98Sdjl 		int mode_verbose,
417*cb5caa98Sdjl 		int mode_quiet,
418*cb5caa98Sdjl 		const char *fname,
419*cb5caa98Sdjl 		ns_ldap_self_gssapi_config_t config,
420*cb5caa98Sdjl 		ns_ldap_error_t **errpp) {
421*cb5caa98Sdjl 
422*cb5caa98Sdjl 	char	buf[MSGSIZE];
423*cb5caa98Sdjl 	int	retcode = NS_LDAP_SUCCESS;
424*cb5caa98Sdjl 	int	loglevel;
425*cb5caa98Sdjl 
426*cb5caa98Sdjl 	if (errpp)
427*cb5caa98Sdjl 		*errpp = NULL;
428*cb5caa98Sdjl 	else
429*cb5caa98Sdjl 		return (NS_LDAP_INVALID_PARAM);
430*cb5caa98Sdjl 
431*cb5caa98Sdjl 	if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
432*cb5caa98Sdjl 		/* Shouldn't happen. Check this value just in case  */
433*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
434*cb5caa98Sdjl 
435*cb5caa98Sdjl 	if ((retcode = test_dns_nsswitch(foreground, fname, errpp)) !=
436*cb5caa98Sdjl 							NS_LDAP_SUCCESS)
437*cb5caa98Sdjl 		return (retcode);
438*cb5caa98Sdjl 
439*cb5caa98Sdjl 	if (is_service(DNS_FMRI, SCF_STATE_STRING_ONLINE)) {
440*cb5caa98Sdjl 		if (foreground) {
441*cb5caa98Sdjl 			CLIENT_FPRINTF(stdout, "start: %s\n",
442*cb5caa98Sdjl 					gettext("DNS client is enabled"));
443*cb5caa98Sdjl 		} else {
444*cb5caa98Sdjl 			syslog(LOG_INFO, "%s",
445*cb5caa98Sdjl 					gettext("DNS client is enabled"));
446*cb5caa98Sdjl 		}
447*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
448*cb5caa98Sdjl 	} else {
449*cb5caa98Sdjl 		if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) {
450*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
451*cb5caa98Sdjl 				gettext("%s: DNS client is not enabled. "
452*cb5caa98Sdjl 					"Run \"svcadm enable %s\". %s."),
453*cb5caa98Sdjl 					"Error", DNS_FMRI, "Abort");
454*cb5caa98Sdjl 			loglevel = LOG_ERR;
455*cb5caa98Sdjl 			retcode = NS_LDAP_CONFIG;
456*cb5caa98Sdjl 		} else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) {
457*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
458*cb5caa98Sdjl 				gettext("%s: DNS client is not enabled. "
459*cb5caa98Sdjl 					"Run \"svcadm enable %s\". %s."
460*cb5caa98Sdjl 					"Fall back to other cred level/bind. "),
461*cb5caa98Sdjl 					"Warning", DNS_FMRI, "Continue");
462*cb5caa98Sdjl 			loglevel = LOG_INFO;
463*cb5caa98Sdjl 			retcode = NS_LDAP_SUCCESS;
464*cb5caa98Sdjl 		}
465*cb5caa98Sdjl 
466*cb5caa98Sdjl 		if (foreground) {
467*cb5caa98Sdjl 			(void) fprintf(stderr, "start: %s\n", buf);
468*cb5caa98Sdjl 		} else {
469*cb5caa98Sdjl 			MKERROR(loglevel, *errpp, retcode, strdup(buf),
470*cb5caa98Sdjl 				NS_LDAP_MEMORY);
471*cb5caa98Sdjl 		}
472*cb5caa98Sdjl 		return (retcode);
473*cb5caa98Sdjl 	}
474*cb5caa98Sdjl }
475*cb5caa98Sdjl 
476*cb5caa98Sdjl /*
477*cb5caa98Sdjl  * Check if sasl/GSSAPI works
478*cb5caa98Sdjl  */
479*cb5caa98Sdjl int
480*cb5caa98Sdjl __ns_ldap_check_gssapi_preq(int foreground,
481*cb5caa98Sdjl 		int mode_verbose,
482*cb5caa98Sdjl 		int mode_quiet,
483*cb5caa98Sdjl 		ns_ldap_self_gssapi_config_t config,
484*cb5caa98Sdjl 		ns_ldap_error_t **errpp) {
485*cb5caa98Sdjl 
486*cb5caa98Sdjl 	int	rc;
487*cb5caa98Sdjl 	char	*attr[2] = {"dn", NULL}, buf[MSGSIZE];
488*cb5caa98Sdjl 	ns_cred_t	cred;
489*cb5caa98Sdjl 	ns_ldap_result_t *result = NULL;
490*cb5caa98Sdjl 	int	loglevel;
491*cb5caa98Sdjl 
492*cb5caa98Sdjl 	if (errpp)
493*cb5caa98Sdjl 		*errpp = NULL;
494*cb5caa98Sdjl 	else
495*cb5caa98Sdjl 		return (NS_LDAP_INVALID_PARAM);
496*cb5caa98Sdjl 
497*cb5caa98Sdjl 	if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
498*cb5caa98Sdjl 		/* Don't need to check */
499*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
500*cb5caa98Sdjl 
501*cb5caa98Sdjl 	(void) memset(&cred, 0, sizeof (ns_cred_t));
502*cb5caa98Sdjl 
503*cb5caa98Sdjl 	cred.auth.type = NS_LDAP_AUTH_SASL;
504*cb5caa98Sdjl 	cred.auth.tlstype = NS_LDAP_TLS_NONE;
505*cb5caa98Sdjl 	cred.auth.saslmech = NS_LDAP_SASL_GSSAPI;
506*cb5caa98Sdjl 
507*cb5caa98Sdjl 	rc = __ns_ldap_list(NULL, (const char *)"objectclass=*",
508*cb5caa98Sdjl 		NULL, (const char **)attr, &cred,
509*cb5caa98Sdjl 		NS_LDAP_SCOPE_BASE, &result, errpp, NULL, NULL);
510*cb5caa98Sdjl 	if (result)
511*cb5caa98Sdjl 		(void) __ns_ldap_freeResult(&result);
512*cb5caa98Sdjl 
513*cb5caa98Sdjl 	if (rc == NS_LDAP_SUCCESS) {
514*cb5caa98Sdjl 		if (foreground) {
515*cb5caa98Sdjl 			CLIENT_FPRINTF(stdout, "start: %s\n",
516*cb5caa98Sdjl 					gettext("sasl/GSSAPI bind works"));
517*cb5caa98Sdjl 		} else {
518*cb5caa98Sdjl 			syslog(LOG_INFO, "%s",
519*cb5caa98Sdjl 					gettext("sasl/GSSAPI bind works"));
520*cb5caa98Sdjl 		}
521*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
522*cb5caa98Sdjl 	} else {
523*cb5caa98Sdjl 		if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) {
524*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
525*cb5caa98Sdjl 				gettext("%s: sasl/GSSAPI bind is not "
526*cb5caa98Sdjl 					"working. %s."),
527*cb5caa98Sdjl 					"Error", "Abort");
528*cb5caa98Sdjl 			loglevel = LOG_ERR;
529*cb5caa98Sdjl 		} else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) {
530*cb5caa98Sdjl 			(void) snprintf(buf, MSGSIZE,
531*cb5caa98Sdjl 				gettext("%s: sasl/GSSAPI bind is not "
532*cb5caa98Sdjl 					"working. Fall back to other cred "
533*cb5caa98Sdjl 					"level/bind. %s."),
534*cb5caa98Sdjl 					"Warning", "Continue");
535*cb5caa98Sdjl 			loglevel = LOG_INFO;
536*cb5caa98Sdjl 			/* reset return code */
537*cb5caa98Sdjl 			rc = NS_LDAP_SUCCESS;
538*cb5caa98Sdjl 		}
539*cb5caa98Sdjl 
540*cb5caa98Sdjl 		if (foreground) {
541*cb5caa98Sdjl 			(void) fprintf(stderr, "start: %s\n", buf);
542*cb5caa98Sdjl 		} else {
543*cb5caa98Sdjl 			MKERROR(loglevel, *errpp, rc, strdup(buf),
544*cb5caa98Sdjl 				NS_LDAP_MEMORY);
545*cb5caa98Sdjl 		}
546*cb5caa98Sdjl 		return (rc);
547*cb5caa98Sdjl 	}
548*cb5caa98Sdjl }
549*cb5caa98Sdjl /*
550*cb5caa98Sdjl  * This is called by ldap_cachemgr to check dns and gssapi prequisites.
551*cb5caa98Sdjl  */
552*cb5caa98Sdjl int
553*cb5caa98Sdjl __ns_ldap_check_all_preq(int foreground,
554*cb5caa98Sdjl 		int mode_verbose,
555*cb5caa98Sdjl 		int mode_quiet,
556*cb5caa98Sdjl 		ns_ldap_self_gssapi_config_t config,
557*cb5caa98Sdjl 		ns_ldap_error_t **errpp) {
558*cb5caa98Sdjl 
559*cb5caa98Sdjl 	int	rc;
560*cb5caa98Sdjl 
561*cb5caa98Sdjl 	if (errpp)
562*cb5caa98Sdjl 		*errpp = NULL;
563*cb5caa98Sdjl 	else
564*cb5caa98Sdjl 		return (NS_LDAP_INVALID_PARAM);
565*cb5caa98Sdjl 
566*cb5caa98Sdjl 	if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
567*cb5caa98Sdjl 		/* Don't need to check */
568*cb5caa98Sdjl 		return (NS_LDAP_SUCCESS);
569*cb5caa98Sdjl 
570*cb5caa98Sdjl 	if ((rc = __ns_ldap_check_dns_preq(foreground,
571*cb5caa98Sdjl 			mode_verbose, mode_quiet, NSSWITCH_CONF,
572*cb5caa98Sdjl 			config, errpp)) != NS_LDAP_SUCCESS)
573*cb5caa98Sdjl 		return (rc);
574*cb5caa98Sdjl 	if ((rc = __ns_ldap_check_gssapi_preq(foreground,
575*cb5caa98Sdjl 			mode_verbose, mode_quiet, config, errpp)) !=
576*cb5caa98Sdjl 			NS_LDAP_SUCCESS)
577*cb5caa98Sdjl 		return (rc);
578*cb5caa98Sdjl 
579*cb5caa98Sdjl 	return (NS_LDAP_SUCCESS);
580*cb5caa98Sdjl }
581