1#include "portable.h"
2#include <stdio.h>
3#include <string.h>		//used for strcpy, etc.
4#include <stdlib.h>		//used for malloc
5#include <stdarg.h>
6#include <errno.h>
7
8#include <unistd.h>
9
10#include <syslog.h>
11
12#include "psauth.h"
13#include <sasl.h>
14#include "saslutil.h"
15#include "saslplug.h"
16#include <lber.h>
17#include "slap.h"
18
19#undef calloc
20#undef free
21
22/* In sasl.c */
23extern int slap_sasl_log( void *context, int priority, const char *message);
24extern int slap_sasl_getopt( void *context, const char *plugin_name, const char *option, const char **result, unsigned *len);
25extern int pws_auxprop_init( const sasl_utils_t *utils, int max_version, int *out_version, sasl_auxprop_plug_t **plug, const char *plugname);
26static const char *slap_propnames[] = {
27    "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN",
28    "*slapAuthzDNlen", "*slapAuthzDN", NULL };
29#define SLAP_SASL_PROP_CONN 0
30#define SLAP_SASL_PROP_AUTHCLEN 1
31#define SLAP_SASL_PROP_AUTHC    2
32#define SLAP_SASL_PROP_AUTHZLEN 3
33#define SLAP_SASL_PROP_AUTHZ    4
34#define SLAP_SASL_PROP_COUNT    5   /* Number of properties we used */
35
36typedef struct sSASLContext {
37	sasl_secret_t *secret;
38	char username[35];
39} sSASLContext;
40
41typedef struct sSASLCanonCtx {
42	Connection *conn;
43	const char *dn;
44} sSASLCanonCtx;
45
46int getrealm(void *context /*__attribute__((unused))*/,
47		    int id,
48		    const char **availrealms,
49		    const char **result);
50int ol_simple(void *context /*__attribute__((unused))*/,
51		  int id,
52		  const char **result,
53		  unsigned *len);
54int
55ol_getsecret(sasl_conn_t *conn,
56	  void *context /*__attribute__((unused))*/,
57	  int id,
58	  sasl_secret_t **psecret);
59
60//-------------
61int getrealm(void *context /*__attribute__((unused))*/,
62            int id,
63            const char **availrealms,
64            const char **result)
65{
66    /* paranoia check */
67    if (id != SASL_CB_GETREALM) return SASL_BADPARAM;
68    if (!result) return SASL_BADPARAM;
69
70    if ( availrealms ) {
71        *result = *availrealms;
72    }
73
74    return SASL_OK;
75}
76
77int ol_simple(void *context /*__attribute__((unused))*/,
78		  int id,
79		  const char **result,
80		  unsigned *len)
81{
82#ifdef DEBUG_PRINTFS
83    printf("in simple\n");
84#endif
85
86    /* paranoia check */
87    if (! result)
88        return SASL_BADPARAM;
89
90    switch (id) {
91        case SASL_CB_USER:
92        case SASL_CB_AUTHNAME:
93            //printf("please enter an authorization id: ");
94            *result = ((sSASLContext *)context)->username;
95            if (len != NULL)
96                *len = strlen(((sSASLContext *)context)->username);
97#ifdef DEBUG_PRINTFS
98            printf("simple - user = %s (len = %d)\n", *result, *len);
99#endif
100            break;
101
102        default:
103            return SASL_BADPARAM;
104    }
105
106    return SASL_OK;
107}
108
109
110int
111ol_getsecret(sasl_conn_t *conn,
112	  void *context /*__attribute__((unused))*/,
113	  int id,
114	  sasl_secret_t **psecret)
115{
116#ifdef DEBUG_PRINTFS
117    printf("in getsecret\n");
118#endif
119    /* paranoia check */
120    if (! conn || ! psecret || id != SASL_CB_PASS)
121        return SASL_BADPARAM;
122
123    *psecret = ((sSASLContext *)context)->secret;
124    return SASL_OK;
125}
126
127int CheckAuthType(char* inAuthAuthorityData, char* authType)
128{
129    char* temp;
130    temp = strchr(inAuthAuthorityData, ';');
131    return ((temp != NULL) && (strncmp(temp+1, authType, strlen(authType)) == 0));
132}
133
134int
135pws_canonicalize(
136    sasl_conn_t *sconn,
137    void *context,
138    const char *in,
139    unsigned inlen,
140    unsigned flags,
141    const char *user_realm,
142    char *out,
143    unsigned out_max,
144    unsigned *out_len)
145{
146	sSASLCanonCtx *ctx = (sSASLCanonCtx*)context;
147	struct propctx *props = sasl_auxprop_getctx( sconn );
148	struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
149	const char *names[2];
150	ber_len_t blen;
151
152	prop_getnames(props, slap_propnames, auxvals);
153	if(!auxvals[0].name)
154		prop_request(props, slap_propnames);
155
156	names[0] = slap_propnames[SLAP_SASL_PROP_CONN];
157	names[1] = NULL;
158	prop_set(props, names[0], (char*)&ctx->conn, sizeof(ctx->conn));
159
160	names[0] = slap_propnames[SLAP_SASL_PROP_AUTHCLEN];
161
162	blen = strlen(ctx->dn);
163	prop_set(props, names[0], (char*)&blen, sizeof(blen));
164
165	names[0] = slap_propnames[SLAP_SASL_PROP_AUTHC];
166	prop_set(props, names[0], ctx->dn, blen);
167
168	if(out_max < (inlen+1)) return SASL_BADPARAM;
169	memcpy(out, in, inlen);
170	out[inlen] = '\0';
171	*out_len = inlen;
172	return SASL_OK;
173}
174
175int DoPSAuth(char* userName, char* password, char* inAuthAuthorityData, Connection* conn, const char* dn)
176{
177	int result = -1;
178	sasl_conn_t *client_conn;
179	sasl_security_properties_t secprops = {0,65535,4096,0,NULL,NULL};
180	sasl_callback_t callbacks[5];
181	const char *data = NULL;
182	unsigned int len = 0;
183	const char *chosenmech = NULL;
184	sSASLContext saslContext;
185	sasl_conn_t *server_conn = NULL;
186	const char *serverOut = NULL;
187	unsigned int serverOutLen = 0;
188	sasl_security_properties_t server_secprops = {0, 65536, 4096, SASL_SEC_NOPLAINTEXT, NULL, NULL};
189    static sasl_callback_t server_callbacks[] = {
190        { SASL_CB_LOG, &slap_sasl_log, NULL },
191        { SASL_CB_GETOPT, &slap_sasl_getopt, NULL },
192        { SASL_CB_LIST_END, NULL, NULL }
193    };
194	sasl_callback_t server_session_callbacks[5];
195	struct propctx *props = NULL;
196	struct propval auxvals[SLAP_SASL_PROP_COUNT] = {{0}};
197	const char *names[2];
198	ber_len_t blen;
199	sSASLCanonCtx canonctx;
200
201	canonctx.conn = conn;
202	canonctx.dn = dn;
203
204	/* server session callbacks */
205	server_session_callbacks[0].id = SASL_CB_LOG;
206	server_session_callbacks[0].proc = &slap_sasl_log;
207	server_session_callbacks[0].context = conn;
208	server_session_callbacks[1].id = SASL_CB_CANON_USER;
209	server_session_callbacks[1].proc = &pws_canonicalize;
210	server_session_callbacks[1].context = &canonctx;
211	server_session_callbacks[2].id = SASL_CB_LIST_END;
212	server_session_callbacks[2].proc = NULL;
213	server_session_callbacks[2].context = NULL;
214
215	memset(&saslContext, 0, sizeof(saslContext));
216	strncpy(saslContext.username, userName, 35);
217	saslContext.secret = (sasl_secret_t*)calloc(1, sizeof(sasl_secret_t) + strlen(password) + 1);
218	saslContext.secret->len = strlen(password);
219	strcpy((char*)saslContext.secret->data, password);
220
221	/* client side callbacks */
222    callbacks[0].id = SASL_CB_GETREALM;
223    callbacks[0].proc = &getrealm;
224    callbacks[0].context = &saslContext;
225
226    callbacks[1].id = SASL_CB_USER;
227    callbacks[1].proc = &ol_simple;
228    callbacks[1].context = &saslContext;
229
230    callbacks[2].id = SASL_CB_AUTHNAME;
231    callbacks[2].proc = &ol_simple;
232    callbacks[2].context = &saslContext;
233
234    callbacks[3].id = SASL_CB_PASS;
235    callbacks[3].proc = &ol_getsecret;
236    callbacks[3].context = &saslContext;
237
238    callbacks[4].id = SASL_CB_LIST_END;
239    callbacks[4].proc = NULL;
240    callbacks[4].context = NULL;
241
242	result = sasl_client_init(NULL);
243	if(result != SASL_OK) {
244		syslog(LOG_ERR, "sasl_client_init returned: %d", result);
245		goto out;
246	}
247
248	result = sasl_client_new("slapd", "localhost", NULL, NULL, callbacks, 0, &client_conn);
249	if ( result != SASL_OK ) {
250		syslog(LOG_ERR, "sasl_client_new returned: %d", result);
251		goto out;
252	}
253
254	result = sasl_setprop(client_conn, SASL_SEC_PROPS, &secprops);
255
256	result = sasl_client_start(client_conn, "CRAM-MD5", NULL, &data, &len, &chosenmech);
257	if(result != SASL_CONTINUE) {
258		syslog(LOG_ERR, "sasl_client_start returned: %d", result);
259		goto out;
260	}
261
262	result = sasl_auxprop_add_plugin( "appleldap", pws_auxprop_init );
263	if( result != SASL_OK ) {
264		syslog(LOG_ERR, "sasl_auxprop_add_plugin returned: %d", result);
265		goto out;
266	}
267
268	result = sasl_set_path(SASL_PATH_TYPE_PLUGIN, "/usr/lib/sasl2/openldap");
269	if(result != SASL_OK) {
270		syslog(LOG_ERR, "sasl_set_path returned: %d", result);
271		goto out;
272	}
273
274	result = sasl_server_init(server_callbacks, "slapd");
275	if(result != SASL_OK) {
276		syslog(LOG_ERR, "sasl_server_init_alt returned: %d", result);
277		goto out;
278	}
279
280	result = sasl_server_new("slapd", "localhost", NULL, NULL, NULL, server_session_callbacks, SASL_SUCCESS_DATA, &server_conn);
281	if(result != SASL_OK) {
282		syslog(LOG_ERR, "sasl_server_new returned: %d", result);
283		goto out;
284	}
285
286	result = sasl_setprop(server_conn, SASL_SEC_PROPS, &server_secprops);
287
288	result = sasl_server_start(server_conn, "CRAM-MD5", data, len, &serverOut, &serverOutLen);
289	if(result != SASL_CONTINUE) {
290		syslog(LOG_ERR, "sasl_server_start returned: %d", result);
291		goto out;
292	}
293
294	result = sasl_client_step(client_conn, serverOut, serverOutLen, NULL, &data, &len);
295	if(result != SASL_OK) {
296		syslog(LOG_ERR, "sasl_client_step returned: %d", result);
297		goto out;
298	}
299
300	result = sasl_server_step(server_conn, data, len, &serverOut, &serverOutLen);
301
302out:
303	if(client_conn) sasl_dispose(&client_conn);
304	if(server_conn) sasl_dispose(&server_conn);
305	if(saslContext.secret) free(saslContext.secret);
306
307	return result;
308}
309