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