1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* SASL server API implementation
7 * Rob Siemborski
8 * Tim Martin
9 * $Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $
10 */
11 /*
12 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in
23 * the documentation and/or other materials provided with the
24 * distribution.
25 *
26 * 3. The name "Carnegie Mellon University" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For permission or any other legal
29 * details, please contact
30 * Office of Technology Transfer
31 * Carnegie Mellon University
32 * 5000 Forbes Avenue
33 * Pittsburgh, PA 15213-3890
34 * (412) 268-4387, fax: (412) 268-7395
35 * tech-transfer@andrew.cmu.edu
36 *
37 * 4. Redistributions of any form whatsoever must retain the following
38 * acknowledgment:
39 * "This product includes software developed by Computing Services
40 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
41 *
42 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
43 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
44 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
45 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
47 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
48 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 */
50
51 #include <config.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <limits.h>
55 #include <ctype.h>
56 #include <string.h>
57 #include <sasl.h>
58 #include <saslplug.h>
59 #include "saslint.h"
60
61 #include <plugin_common.h>
62
63 /***************************** Common Section *****************************/
64
65 #ifndef _SUN_SDK_
66 static const char plugin_id[] = "$Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $";
67 #endif /* !_SUN_SDK_ */
68
69 /***************************** Server Section *****************************/
70
71 static int
external_server_mech_new(void * glob_context,sasl_server_params_t * sparams,const char * challenge,unsigned challen,void ** conn_context)72 external_server_mech_new(void *glob_context __attribute__((unused)),
73 sasl_server_params_t *sparams,
74 const char *challenge __attribute__((unused)),
75 unsigned challen __attribute__((unused)),
76 void **conn_context)
77 {
78 if (!conn_context
79 || !sparams
80 || !sparams->utils
81 || !sparams->utils->conn)
82 return SASL_BADPARAM;
83
84 if (!sparams->utils->conn->external.auth_id)
85 return SASL_NOMECH;
86
87 *conn_context = NULL;
88
89 return SASL_OK;
90 }
91
92 static int
external_server_mech_step(void * conn_context,sasl_server_params_t * sparams,const char * clientin,unsigned clientinlen,const char ** serverout,unsigned * serveroutlen,sasl_out_params_t * oparams)93 external_server_mech_step(void *conn_context __attribute__((unused)),
94 sasl_server_params_t *sparams,
95 const char *clientin,
96 unsigned clientinlen,
97 const char **serverout,
98 unsigned *serveroutlen,
99 sasl_out_params_t *oparams)
100 {
101 int result;
102
103 if (!sparams
104 || !sparams->utils
105 || !sparams->utils->conn
106 || !sparams->utils->getcallback
107 || !serverout
108 || !serveroutlen
109 || !oparams)
110 return SASL_BADPARAM;
111
112 if (!sparams->utils->conn->external.auth_id)
113 return SASL_BADPROT;
114
115 if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
116 (!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
117 #ifdef _INTEGRATED_SOLARIS_
118 sasl_seterror(sparams->utils->conn,0,
119 gettext("anonymous login not allowed"));
120 #else
121 sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
122 #endif /* _INTEGRATED_SOLARIS_ */
123 return SASL_NOAUTHZ;
124 }
125
126 *serverout = NULL;
127 *serveroutlen = 0;
128
129 if (!clientin) {
130 /* No initial data; we're in a protocol which doesn't support it.
131 * So we let the server app know that we need some... */
132 return SASL_CONTINUE;
133 }
134
135 if (clientinlen) { /* if we have a non-zero authorization id */
136 /* The user's trying to authorize as someone they didn't
137 * authenticate as */
138 result = sparams->canon_user(sparams->utils->conn,
139 clientin, 0, SASL_CU_AUTHZID, oparams);
140 if(result != SASL_OK) return result;
141
142 result = sparams->canon_user(sparams->utils->conn,
143 sparams->utils->conn->external.auth_id, 0,
144 SASL_CU_AUTHID, oparams);
145 } else {
146 result = sparams->canon_user(sparams->utils->conn,
147 sparams->utils->conn->external.auth_id, 0,
148 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
149 }
150
151 if (result != SASL_OK) return result;
152
153 /* set oparams */
154 oparams->doneflag = 1;
155 oparams->mech_ssf = 0;
156 oparams->maxoutbuf = 0;
157 oparams->encode_context = NULL;
158 oparams->encode = NULL;
159 oparams->decode_context = NULL;
160 oparams->decode = NULL;
161 oparams->param_version = 0;
162
163 return SASL_OK;
164 }
165
166 static int
external_server_mech_avail(void * glob_context,sasl_server_params_t * sparams,void ** conn_context)167 external_server_mech_avail(void *glob_context __attribute__((unused)),
168 sasl_server_params_t *sparams,
169 void **conn_context __attribute__((unused)))
170 {
171 if (!sparams->utils->conn->external.auth_id)
172 return SASL_NOMECH;
173 return SASL_OK;
174 }
175
176 static sasl_server_plug_t external_server_plugins[] =
177 {
178 {
179 "EXTERNAL", /* mech_name */
180 0, /* max_ssf */
181 SASL_SEC_NOPLAINTEXT
182 | SASL_SEC_NOANONYMOUS
183 | SASL_SEC_NODICTIONARY, /* security_flags */
184 SASL_FEAT_WANT_CLIENT_FIRST
185 | SASL_FEAT_ALLOWS_PROXY, /* features */
186 NULL, /* glob_context */
187 &external_server_mech_new, /* mech_new */
188 &external_server_mech_step, /* mech_step */
189 NULL, /* mech_dispose */
190 NULL, /* mech_free */
191 NULL, /* setpass */
192 NULL, /* user_query */
193 NULL, /* idle */
194 &external_server_mech_avail, /* mech_avail */
195 NULL /* spare */
196 }
197 };
198
external_server_plug_init(const sasl_utils_t * utils,int max_version,int * out_version,sasl_server_plug_t ** pluglist,int * plugcount)199 int external_server_plug_init(const sasl_utils_t *utils,
200 int max_version,
201 int *out_version,
202 sasl_server_plug_t **pluglist,
203 int *plugcount)
204 {
205 if (!out_version || !pluglist || !plugcount)
206 return SASL_BADPARAM;
207
208 if (max_version != SASL_SERVER_PLUG_VERSION) {
209 #ifdef _SUN_SDK_
210 utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch");
211 #else
212 SETERROR( utils, "EXTERNAL version mismatch" );
213 #endif /* _SUN_SDK_ */
214 return SASL_BADVERS;
215 }
216
217 *out_version = SASL_SERVER_PLUG_VERSION;
218 *pluglist = external_server_plugins;
219 *plugcount = 1;
220 return SASL_OK;
221 }
222
223 /***************************** Client Section *****************************/
224
225 typedef struct client_context
226 {
227 char *out_buf;
228 #ifdef _SUN_SDK_
229 unsigned out_buf_len;
230 #else
231 size_t out_buf_len;
232 #endif /* _SUN_SDK_ */
233 #ifdef _INTEGRATED_SOLARIS_
234 void *h;
235 #endif /* _INTEGRATED_SOLARIS_ */
236 } client_context_t;
237
external_client_mech_new(void * glob_context,sasl_client_params_t * params,void ** conn_context)238 static int external_client_mech_new(void *glob_context __attribute__((unused)),
239 sasl_client_params_t *params,
240 void **conn_context)
241 {
242 client_context_t *text;
243
244 if (!params
245 || !params->utils
246 || !params->utils->conn
247 || !conn_context)
248 return SASL_BADPARAM;
249
250 if (!params->utils->conn->external.auth_id)
251 return SASL_NOMECH;
252
253 #ifdef _SUN_SDK_
254 text = params->utils->malloc(sizeof(client_context_t));
255 #else
256 text = sasl_ALLOC(sizeof(client_context_t));
257 #endif /* _SUN_SDK_ */
258 if(!text) return SASL_NOMEM;
259
260 memset(text, 0, sizeof(client_context_t));
261
262 *conn_context = text;
263
264 return SASL_OK;
265 }
266
267 static int
external_client_mech_step(void * conn_context,sasl_client_params_t * params,const char * serverin,unsigned serverinlen,sasl_interact_t ** prompt_need,const char ** clientout,unsigned * clientoutlen,sasl_out_params_t * oparams)268 external_client_mech_step(void *conn_context,
269 sasl_client_params_t *params,
270 const char *serverin __attribute__((unused)),
271 unsigned serverinlen,
272 sasl_interact_t **prompt_need,
273 const char **clientout,
274 unsigned *clientoutlen,
275 sasl_out_params_t *oparams)
276 {
277 client_context_t *text = (client_context_t *)conn_context;
278 const char *user = NULL;
279 int user_result = SASL_OK;
280 int result;
281
282 if (!params
283 || !params->utils
284 || !params->utils->conn
285 || !params->utils->getcallback
286 || !clientout
287 || !clientoutlen
288 || !oparams)
289 return SASL_BADPARAM;
290
291 if (!params->utils->conn->external.auth_id)
292 return SASL_BADPROT;
293
294 if (serverinlen != 0)
295 return SASL_BADPROT;
296
297 *clientout = NULL;
298 *clientoutlen = 0;
299
300 /* try to get the userid */
301 if (user == NULL) {
302 user_result = _plug_get_userid(params->utils, &user, prompt_need);
303
304 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
305 return user_result;
306 }
307
308 /* free prompts we got */
309 if (prompt_need && *prompt_need) {
310 params->utils->free(*prompt_need);
311 *prompt_need = NULL;
312 }
313
314 /* if there are prompts not filled in */
315 if (user_result == SASL_INTERACT) {
316 /* make the prompt list */
317 int result =
318 #ifdef _INTEGRATED_SOLARIS_
319 _plug_make_prompts(params->utils, &text->h, prompt_need,
320 user_result == SASL_INTERACT ?
321 convert_prompt(params->utils, &text->h,
322 gettext("Please enter your authorization name"))
323 : NULL,
324 #else
325 _plug_make_prompts(params->utils, prompt_need,
326 user_result == SASL_INTERACT ?
327 "Please enter your authorization name" : NULL,
328 #endif /* _INTEGRATED_SOLARIS_ */
329 "",
330 NULL, NULL,
331 NULL, NULL,
332 NULL, NULL, NULL,
333 NULL, NULL, NULL);
334 if (result != SASL_OK) return result;
335
336 return SASL_INTERACT;
337 }
338
339 *clientoutlen = user ? strlen(user) : 0;
340
341 #ifdef _SUN_SDK_
342 result = _plug_buf_alloc(params->utils, &text->out_buf,
343 &text->out_buf_len, *clientoutlen + 1);
344 #else
345 result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
346 #endif /* _SUN_SDK_ */
347
348 if (result != SASL_OK) return result;
349
350 if (user && *user) {
351 result = params->canon_user(params->utils->conn,
352 user, 0, SASL_CU_AUTHZID, oparams);
353 if (result != SASL_OK) return result;
354
355 result = params->canon_user(params->utils->conn,
356 params->utils->conn->external.auth_id, 0,
357 SASL_CU_AUTHID, oparams);
358 if (result != SASL_OK) return result;
359
360 memcpy(text->out_buf, user, *clientoutlen);
361 } else {
362 result = params->canon_user(params->utils->conn,
363 params->utils->conn->external.auth_id, 0,
364 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
365 if (result != SASL_OK) return result;
366 }
367
368 text->out_buf[*clientoutlen] = '\0';
369
370 *clientout = text->out_buf;
371
372 /* set oparams */
373 oparams->doneflag = 1;
374 oparams->mech_ssf = 0;
375 oparams->maxoutbuf = 0;
376 oparams->encode_context = NULL;
377 oparams->encode = NULL;
378 oparams->decode_context = NULL;
379 oparams->decode = NULL;
380 oparams->param_version = 0;
381
382 return SASL_OK;
383 }
384
385 static void
external_client_mech_dispose(void * conn_context,const sasl_utils_t * utils)386 external_client_mech_dispose(void *conn_context,
387 const sasl_utils_t *utils __attribute__((unused)))
388 {
389 client_context_t *text = (client_context_t *) conn_context;
390
391 if (!text) return;
392
393 #ifdef _INTEGRATED_SOLARIS_
394 convert_prompt(utils, &text->h, NULL);
395 #endif /* _INTEGRATED_SOLARIS_ */
396
397 #ifdef _SUN_SDK_
398 if(text->out_buf) utils->free(text->out_buf);
399
400 utils->free(text);
401 #else
402 if(text->out_buf) sasl_FREE(text->out_buf);
403
404 sasl_FREE(text);
405 #endif /* _SUN_SDK_ */
406 }
407
408 #ifdef _SUN_SDK_
409 static const unsigned long external_required_prompts[] = {
410 #else
411 static const long external_required_prompts[] = {
412 #endif /* _SUN_SDK_ */
413 SASL_CB_LIST_END
414 };
415
416 static sasl_client_plug_t external_client_plugins[] =
417 {
418 {
419 "EXTERNAL", /* mech_name */
420 0, /* max_ssf */
421 SASL_SEC_NOPLAINTEXT
422 | SASL_SEC_NOANONYMOUS
423 | SASL_SEC_NODICTIONARY, /* security_flags */
424 SASL_FEAT_WANT_CLIENT_FIRST
425 | SASL_FEAT_ALLOWS_PROXY, /* features */
426 external_required_prompts, /* required_prompts */
427 NULL, /* glob_context */
428 &external_client_mech_new, /* mech_new */
429 &external_client_mech_step, /* mech_step */
430 &external_client_mech_dispose, /* mech_dispose */
431 NULL, /* mech_free */
432 NULL, /* idle */
433 NULL, /* spare */
434 NULL /* spare */
435 }
436 };
437
external_client_plug_init(const sasl_utils_t * utils,int max_version,int * out_version,sasl_client_plug_t ** pluglist,int * plugcount)438 int external_client_plug_init(const sasl_utils_t *utils,
439 int max_version,
440 int *out_version,
441 sasl_client_plug_t **pluglist,
442 int *plugcount)
443 {
444 if (!utils || !out_version || !pluglist || !plugcount)
445 return SASL_BADPARAM;
446
447 if (max_version != SASL_CLIENT_PLUG_VERSION) {
448 #ifdef _SUN_SDK_
449 utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch");
450 #else
451 SETERROR( utils, "EXTERNAL version mismatch" );
452 #endif /* _SUN_SDK_ */
453 return SASL_BADVERS;
454 }
455
456 *out_version = SASL_CLIENT_PLUG_VERSION;
457 *pluglist = external_client_plugins;
458 *plugcount = 1;
459
460 return SASL_OK;
461 }
462