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