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