1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * File for ldaptool routines for SASL
8  */
9 
10 #include <ldap.h>
11 #include "ldaptool-sasl.h"
12 #ifdef SOLARIS_LDAP_CMD
13 #include <sasl/sasl.h>
14 #include <locale.h>
15 #include "ldaptool.h"
16 #else
17 #include <sasl.h>
18 #endif	/* SOLARIS_LDAP_CMD */
19 #include <stdio.h>
20 
21 #ifndef SOLARIS_LDAP_CMD
22 #define gettext(s) s
23 #endif
24 
25 #ifdef HAVE_SASL_OPTIONS
26 
27 #define SASL_PROMPT	"SASL"
28 
29 typedef struct {
30         char *mech;
31         char *authid;
32         char *username;
33         char *passwd;
34         char *realm;
35 } ldaptoolSASLdefaults;
36 
37 static int get_default(ldaptoolSASLdefaults *defaults, sasl_interact_t *interact);
38 static int get_new_value(sasl_interact_t *interact, unsigned flags);
39 
40 void *
41 ldaptool_set_sasl_defaults ( LDAP *ld, char *mech, char *authid, char *username,
42 				 char *passwd, char *realm )
43 {
44         ldaptoolSASLdefaults *defaults;
45 
46         if ((defaults = calloc(sizeof(defaults[0]), 1)) == NULL)
47 		return NULL;
48 
49 	if (mech)
50 		defaults->mech = mech;
51 	else
52 		ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &defaults->mech);
53 
54 	if (authid)
55 		defaults->authid = authid;
56 	else
57 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authid);
58 
59 	if (username)
60 		defaults->username = username;
61 	else
62 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->username);
63 
64         defaults->passwd = passwd;
65 
66 	if (realm)
67 		defaults->realm = realm;
68 	else
69 		ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &defaults->realm);
70 
71         return defaults;
72 }
73 
74 int
75 ldaptool_sasl_interact( LDAP *ld, unsigned flags, void *defaults, void *prompts ) {
76 	sasl_interact_t		*interact;
77 	ldaptoolSASLdefaults	*sasldefaults = defaults;
78 	int			rc;
79 
80 	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
81 		return (LDAP_PARAM_ERROR);
82 
83 	for (interact = prompts; interact->id != SASL_CB_LIST_END; interact++) {
84 		/* Obtain the default value */
85 		if ((rc = get_default(sasldefaults, interact)) != LDAP_SUCCESS)
86 			return (rc);
87 
88 		/* If no default, get the new value from stdin */
89 		if (interact->result == NULL) {
90 			if ((rc = get_new_value(interact, flags)) != LDAP_SUCCESS)
91 				return (rc);
92 		}
93 
94 	}
95 	return (LDAP_SUCCESS);
96 }
97 
98 static int
99 get_default(ldaptoolSASLdefaults *defaults, sasl_interact_t *interact) {
100 	const char	*defvalue = interact->defresult;
101 
102 	if (defaults != NULL) {
103 		switch( interact->id ) {
104         	case SASL_CB_AUTHNAME:
105 			defvalue = defaults->authid;
106 			break;
107         	case SASL_CB_USER:
108 			defvalue = defaults->username;
109 			break;
110         	case SASL_CB_PASS:
111 			defvalue = defaults->passwd;
112 			break;
113         	case SASL_CB_GETREALM:
114 			defvalue = defaults->realm;
115 			break;
116 		}
117 	}
118 
119 	if (defvalue != NULL) {
120 		interact->result = (char *)malloc(strlen(defvalue)+1);
121 		if ((char *)interact->result != NULL) {
122 			strcpy((char *)interact->result,defvalue);
123 			interact->len = strlen((char *)(interact->result));
124 		}
125 
126 		/* Clear passwd */
127 		if (interact->id == SASL_CB_PASS && defaults != NULL) {
128 			/* At this point defaults->passwd is not NULL */
129             		memset( defaults->passwd, '\0', strlen(defaults->passwd));
130 		}
131 
132 		if ((char *)interact->result == NULL) {
133 			return (LDAP_NO_MEMORY);
134 		}
135 	}
136 	return (LDAP_SUCCESS);
137 }
138 
139 static int
140 get_new_value(sasl_interact_t *interact, unsigned flags) {
141 	char	*newvalue, str[1024];
142 	int	len;
143 
144 #ifdef SOLARIS_LDAP_CMD
145 	char	*tmpstr;
146 #endif
147 
148 	if (interact->id == SASL_CB_ECHOPROMPT || interact->id == SASL_CB_NOECHOPROMPT) {
149 		if (interact->challenge)
150 			fprintf(stderr, gettext("Challenge:%s\n"), interact->challenge);
151 	}
152 
153 #ifdef SOLARIS_LDAP_CMD
154 	tmpstr = ldaptool_UTF82local(interact->prompt);
155 	snprintf(str, sizeof(str), "%s:", tmpstr?tmpstr:SASL_PROMPT);
156 	if (tmpstr != NULL)
157 		free(tmpstr);
158 #else
159 #ifdef HAVE_SNPRINTF
160 	snprintf(str, sizeof(str), "%s:", interact->prompt?interact->prompt:SASL_PROMPT);
161 #else
162 	sprintf(str, "%s:", interact->prompt?interact->prompt:SASL_PROMPT);
163 #endif
164 #endif	/* SOLARIS_LDAP_CMD */
165 
166 	/* Get the new value */
167 	if (interact->id == SASL_CB_PASS || interact->id == SASL_CB_NOECHOPROMPT) {
168 #if defined(_WIN32)
169 		char pbuf[257];
170 		fputs(str,stdout);
171 		fflush(stdout);
172 		if (fgets(pbuf,256,stdin) == NULL) {
173 			newvalue = NULL;
174 		} else {
175 			char *tmp;
176 
177 			tmp = strchr(pbuf,'\n');
178 			if (tmp) *tmp = '\0';
179 			tmp = strchr(pbuf,'\r');
180 			if (tmp) *tmp = '\0';
181 			newvalue = strdup(pbuf);
182 		}
183 		if ( newvalue == NULL) {
184 #else
185 #if defined(SOLARIS)
186 		if ((newvalue = (char *)getpassphrase(str)) == NULL) {
187 #else
188 		if ((newvalue = (char *)getpass(str)) == NULL) {
189 #endif
190 #endif
191 			return (LDAP_UNAVAILABLE);
192 		}
193 		len = strlen(newvalue);
194 	} else {
195 		fputs(str, stderr);
196 		if ((newvalue = fgets(str, sizeof(str), stdin)) == NULL)
197 			return (LDAP_UNAVAILABLE);
198 		len = strlen(str);
199 		if (len > 0 && str[len - 1] == '\n')
200 			str[len - 1] = 0;
201 	}
202 
203 	interact->result = (char *) strdup(newvalue);
204 	memset(newvalue, '\0', len);
205 	if (interact->result == NULL)
206 		return (LDAP_NO_MEMORY);
207 	interact->len = len;
208 	return (LDAP_SUCCESS);
209 }
210 #endif	/* HAVE_SASL_OPTIONS */
211