xref: /illumos-gate/usr/src/lib/libsasl/lib/external.c (revision 7c478bd9)
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
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
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
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 
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 
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
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
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 
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