1 /* Anonymous SASL plugin
2  * Rob Siemborski
3  * Tim Martin
4  */
5 /*
6  * Copyright (c) 1998-2016 Carnegie Mellon University.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The name "Carnegie Mellon University" must not be used to
21  *    endorse or promote products derived from this software without
22  *    prior written permission. For permission or any other legal
23  *    details, please contact
24  *      Carnegie Mellon University
25  *      Center for Technology Transfer and Enterprise Creation
26  *      4615 Forbes Avenue
27  *      Suite 302
28  *      Pittsburgh, PA  15213
29  *      (412) 268-7393, fax: (412) 268-7395
30  *      innovation@andrew.cmu.edu
31  *
32  * 4. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by Computing Services
35  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36  *
37  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44  */
45 
46 #include <config.h>
47 #include <stdio.h>
48 #include <string.h>
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <sasl.h>
53 #include <saslplug.h>
54 
55 #include "plugin_common.h"
56 
57 #ifdef macintosh
58 #include <sasl_anonymous_plugin_decl.h>
59 #endif
60 
61 /*****************************  Common Section  *****************************/
62 
63 static const char anonymous_id[] = "anonymous";
64 
65 /*****************************  Server Section  *****************************/
66 
67 static int
anonymous_server_mech_new(void * glob_context,sasl_server_params_t * sparams,const char * challenge,unsigned challen,void ** conn_context)68 anonymous_server_mech_new(void *glob_context __attribute__((unused)),
69 			  sasl_server_params_t *sparams,
70 			  const char *challenge __attribute__((unused)),
71 			  unsigned challen __attribute__((unused)),
72 			  void **conn_context)
73 {
74     /* holds state are in */
75     if (!conn_context) {
76 	PARAMERROR( sparams->utils );
77 	return SASL_BADPARAM;
78     }
79 
80     *conn_context = NULL;
81 
82     return SASL_OK;
83 }
84 
85 static int
anonymous_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)86 anonymous_server_mech_step(void *conn_context __attribute__((unused)),
87 			   sasl_server_params_t *sparams,
88 			   const char *clientin,
89 			   unsigned clientinlen,
90 			   const char **serverout,
91 			   unsigned *serveroutlen,
92 			   sasl_out_params_t *oparams)
93 {
94     char *clientdata;
95     int result;
96 
97     if (!sparams
98 	|| !serverout
99 	|| !serveroutlen
100 	|| !oparams) {
101 	if (sparams) PARAMERROR( sparams->utils );
102 	return SASL_BADPARAM;
103     }
104 
105     *serverout = NULL;
106     *serveroutlen = 0;
107 
108     if (!clientin) {
109 	return SASL_CONTINUE;
110     }
111 
112     /* We force a truncation 255 characters (specified by RFC 2245) */
113     if (clientinlen > 255) clientinlen = 255;
114 
115     /* NULL-terminate the clientin... */
116     clientdata = sparams->utils->malloc(clientinlen + 1);
117     if (!clientdata) {
118 	MEMERROR(sparams->utils);
119 	return SASL_NOMEM;
120     }
121 
122     strncpy(clientdata, clientin, clientinlen);
123     clientdata[clientinlen] = '\0';
124 
125     sparams->utils->log(sparams->utils->conn,
126 			SASL_LOG_NOTE,
127 			"ANONYMOUS login: \"%s\"",
128 			clientdata);
129 
130     if (clientdata != clientin)
131 	sparams->utils->free(clientdata);
132 
133     result = sparams->canon_user(sparams->utils->conn,
134 				 anonymous_id, 0,
135 				 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
136 
137     if (result != SASL_OK) return result;
138 
139     /* set oparams */
140     oparams->doneflag = 1;
141     oparams->mech_ssf = 0;
142     oparams->maxoutbuf = 0;
143     oparams->encode_context = NULL;
144     oparams->encode = NULL;
145     oparams->decode_context = NULL;
146     oparams->decode = NULL;
147     oparams->param_version = 0;
148 
149     return SASL_OK;
150 }
151 
152 static sasl_server_plug_t anonymous_server_plugins[] =
153 {
154     {
155 	"ANONYMOUS",			/* mech_name */
156 	0,				/* max_ssf */
157 	SASL_SEC_NOPLAINTEXT,		/* security_flags */
158 	SASL_FEAT_WANT_CLIENT_FIRST
159 	| SASL_FEAT_DONTUSE_USERPASSWD,	/* features */
160 	NULL,				/* glob_context */
161 	&anonymous_server_mech_new,	/* mech_new */
162 	&anonymous_server_mech_step,	/* mech_step */
163 	NULL,				/* mech_dispose */
164 	NULL,				/* mech_free */
165 	NULL,				/* setpass */
166 	NULL,				/* user_query */
167 	NULL,				/* idle */
168 	NULL,				/* mech_avail */
169 	NULL                        	/* spare */
170     }
171 };
172 
anonymous_server_plug_init(const sasl_utils_t * utils,int maxversion,int * out_version,sasl_server_plug_t ** pluglist,int * plugcount)173 int anonymous_server_plug_init(const sasl_utils_t *utils,
174 			       int maxversion,
175 			       int *out_version,
176 			       sasl_server_plug_t **pluglist,
177 			       int *plugcount)
178 {
179     if (maxversion < SASL_SERVER_PLUG_VERSION) {
180 	SETERROR( utils, "ANONYMOUS version mismatch" );
181 	return SASL_BADVERS;
182     }
183 
184     *out_version = SASL_SERVER_PLUG_VERSION;
185     *pluglist = anonymous_server_plugins;
186     *plugcount = 1;
187 
188     return SASL_OK;
189 }
190 
191 /*****************************  Client Section  *****************************/
192 
193 typedef struct client_context {
194     char *out_buf;
195     unsigned out_buf_len;
196 } client_context_t;
197 
198 static int
anonymous_client_mech_new(void * glob_context,sasl_client_params_t * cparams,void ** conn_context)199 anonymous_client_mech_new(void *glob_context __attribute__((unused)),
200 			  sasl_client_params_t *cparams,
201 			  void **conn_context)
202 {
203     client_context_t *text;
204 
205     if (!conn_context) {
206 	PARAMERROR(cparams->utils);
207 	return SASL_BADPARAM;
208     }
209 
210     /* holds state are in */
211     text = cparams->utils->malloc(sizeof(client_context_t));
212     if (text == NULL) {
213 	MEMERROR(cparams->utils);
214 	return SASL_NOMEM;
215     }
216 
217     memset(text, 0, sizeof(client_context_t));
218 
219     *conn_context = text;
220 
221     return SASL_OK;
222 }
223 
224 static int
anonymous_client_mech_step(void * conn_context,sasl_client_params_t * cparams,const char * serverin,unsigned serverinlen,sasl_interact_t ** prompt_need,const char ** clientout,unsigned * clientoutlen,sasl_out_params_t * oparams)225 anonymous_client_mech_step(void *conn_context,
226 			   sasl_client_params_t *cparams,
227 			   const char *serverin __attribute__((unused)),
228 			   unsigned serverinlen,
229 			   sasl_interact_t **prompt_need,
230 			   const char **clientout,
231 			   unsigned *clientoutlen,
232 			   sasl_out_params_t *oparams)
233 {
234     client_context_t *text = (client_context_t *) conn_context;
235     size_t userlen;
236     char hostname[256];
237     const char *user = NULL;
238     int user_result = SASL_OK;
239     int result;
240 
241     if (!cparams
242 	|| !clientout
243 	|| !clientoutlen
244 	|| !oparams) {
245 	if (cparams) PARAMERROR( cparams->utils );
246 	return SASL_BADPARAM;
247     }
248 
249     *clientout = NULL;
250     *clientoutlen = 0;
251 
252     if (serverinlen != 0) {
253 	SETERROR( cparams->utils,
254 		  "Nonzero serverinlen in ANONYMOUS continue_step" );
255 	return SASL_BADPROT;
256     }
257 
258     /* check if sec layer strong enough */
259     if (cparams->props.min_ssf > cparams->external_ssf) {
260 	SETERROR( cparams->utils, "SSF requested of ANONYMOUS plugin");
261 	return SASL_TOOWEAK;
262     }
263 
264     /* try to get the trace info */
265     if (user == NULL) {
266 	user_result = _plug_get_userid(cparams->utils, &user, prompt_need);
267 
268 	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
269 	    return user_result;
270 	}
271     }
272 
273     /* free prompts we got */
274     if (prompt_need && *prompt_need) {
275 	cparams->utils->free(*prompt_need);
276 	*prompt_need = NULL;
277     }
278 
279     /* if there are prompts not filled in */
280     if (user_result == SASL_INTERACT) {
281 	/* make the prompt list */
282 	result =
283 	    _plug_make_prompts(cparams->utils, prompt_need,
284 			       "Please enter anonymous identification",
285 			       "",
286 			       NULL, NULL,
287 			       NULL, NULL,
288 			       NULL, NULL, NULL,
289 			       NULL, NULL, NULL);
290 	if (result != SASL_OK) return result;
291 
292 	return SASL_INTERACT;
293     }
294 
295     if (!user || !*user) {
296 	user = anonymous_id;
297     }
298     userlen = strlen(user);
299 
300     result = cparams->canon_user(cparams->utils->conn,
301 				 anonymous_id, 0,
302 				 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
303     if (result != SASL_OK) return result;
304 
305     memset(hostname, 0, sizeof(hostname));
306     gethostname(hostname, sizeof(hostname));
307     hostname[sizeof(hostname)-1] = '\0';
308 
309     *clientoutlen = (unsigned) (userlen + strlen(hostname) + 1);
310 
311     result = _plug_buf_alloc(cparams->utils, &text->out_buf,
312 			     &text->out_buf_len, *clientoutlen);
313 
314     if (result != SASL_OK) return result;
315 
316     strcpy(text->out_buf, user);
317     text->out_buf[userlen] = '@';
318     /* use memcpy() instead of strcpy() so we don't add the NUL */
319     memcpy(text->out_buf + userlen + 1, hostname, strlen(hostname));
320 
321     *clientout = text->out_buf;
322 
323     /* set oparams */
324     oparams->doneflag = 1;
325     oparams->mech_ssf = 0;
326     oparams->maxoutbuf = 0;
327     oparams->encode_context = NULL;
328     oparams->encode = NULL;
329     oparams->decode_context = NULL;
330     oparams->decode = NULL;
331     oparams->param_version = 0;
332 
333     return SASL_OK;
334 }
335 
anonymous_client_dispose(void * conn_context,const sasl_utils_t * utils)336 static void anonymous_client_dispose(void *conn_context,
337 				     const sasl_utils_t *utils)
338 {
339     client_context_t *text = (client_context_t *) conn_context;
340 
341     if(!text) return;
342 
343     if (text->out_buf) utils->free(text->out_buf);
344 
345     utils->free(text);
346 }
347 
348 static const unsigned long anonymous_required_prompts[] = {
349     SASL_CB_LIST_END
350 };
351 
352 static sasl_client_plug_t anonymous_client_plugins[] =
353 {
354     {
355 	"ANONYMOUS",			/* mech_name */
356 	0,				/* max_ssf */
357 	SASL_SEC_NOPLAINTEXT,		/* security_flags */
358 	SASL_FEAT_WANT_CLIENT_FIRST,	/* features */
359 	anonymous_required_prompts,	/* required_prompts */
360 	NULL,				/* glob_context */
361 	&anonymous_client_mech_new, 	/* mech_new */
362 	&anonymous_client_mech_step,	/* mech_step */
363 	&anonymous_client_dispose,	/* mech_dispose */
364 	NULL,				/* mech_free */
365 	NULL,				/* idle */
366 	NULL,				/* spare */
367 	NULL                        	/* spare */
368     }
369 };
370 
anonymous_client_plug_init(const sasl_utils_t * utils,int maxversion,int * out_version,sasl_client_plug_t ** pluglist,int * plugcount)371 int anonymous_client_plug_init(const sasl_utils_t *utils,
372 			       int maxversion,
373 			       int *out_version,
374 			       sasl_client_plug_t **pluglist,
375 			       int *plugcount)
376 {
377     if (maxversion < SASL_CLIENT_PLUG_VERSION) {
378 	SETERROR( utils, "ANONYMOUS version mismatch" );
379 	return SASL_BADVERS;
380     }
381 
382     *out_version = SASL_CLIENT_PLUG_VERSION;
383     *pluglist = anonymous_client_plugins;
384     *plugcount = 1;
385 
386     return SASL_OK;
387 }
388