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