1 /* SASL server API implementation
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 <stdlib.h>
49 #include <limits.h>
50 #include <ctype.h>
51 #include <string.h>
52 #include <sasl.h>
53 #include <saslplug.h>
54 #include "saslint.h"
55
56 #include "../common/plugin_common.h"
57
58 /***************************** Common Section *****************************/
59
60 /***************************** Server Section *****************************/
61
62 static int
external_server_mech_new(void * glob_context,sasl_server_params_t * sparams,const char * challenge,unsigned challen,void ** conn_context)63 external_server_mech_new(void *glob_context __attribute__((unused)),
64 sasl_server_params_t *sparams,
65 const char *challenge __attribute__((unused)),
66 unsigned challen __attribute__((unused)),
67 void **conn_context)
68 {
69 if (!conn_context
70 || !sparams
71 || !sparams->utils
72 || !sparams->utils->conn)
73 return SASL_BADPARAM;
74
75 if (!sparams->utils->conn->external.auth_id)
76 return SASL_NOMECH;
77
78 *conn_context = NULL;
79
80 return SASL_OK;
81 }
82
83 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)84 external_server_mech_step(void *conn_context __attribute__((unused)),
85 sasl_server_params_t *sparams,
86 const char *clientin,
87 unsigned clientinlen,
88 const char **serverout,
89 unsigned *serveroutlen,
90 sasl_out_params_t *oparams)
91 {
92 int result;
93
94 if (!sparams
95 || !sparams->utils
96 || !sparams->utils->conn
97 || !sparams->utils->getcallback
98 || !serverout
99 || !serveroutlen
100 || !oparams)
101 return SASL_BADPARAM;
102
103 if (!sparams->utils->conn->external.auth_id)
104 return SASL_BADPROT;
105
106 /* xxx arbitrary limit here */
107 if (clientinlen > 16384) return SASL_BADPROT;
108
109 if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
110 (!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
111 sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
112 return SASL_NOAUTHZ;
113 }
114
115 *serverout = NULL;
116 *serveroutlen = 0;
117
118 if (!clientin) {
119 /* No initial data; we're in a protocol which doesn't support it.
120 * So we let the server app know that we need some... */
121 return SASL_CONTINUE;
122 }
123
124 if (clientinlen) { /* if we have a non-zero authorization id */
125 /* The user's trying to authorize as someone they didn't
126 * authenticate as */
127 result = sparams->canon_user(sparams->utils->conn,
128 clientin, clientinlen,
129 SASL_CU_AUTHZID, oparams);
130 if(result != SASL_OK) return result;
131
132 result = sparams->canon_user(sparams->utils->conn,
133 sparams->utils->conn->external.auth_id, 0,
134 SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED, oparams);
135 } else {
136 result = sparams->canon_user(sparams->utils->conn,
137 sparams->utils->conn->external.auth_id, 0,
138 SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED | SASL_CU_AUTHZID, oparams);
139 }
140
141 if (result != SASL_OK) return result;
142
143 /* set oparams */
144 oparams->doneflag = 1;
145 oparams->mech_ssf = 0;
146 oparams->maxoutbuf = 0;
147 oparams->encode_context = NULL;
148 oparams->encode = NULL;
149 oparams->decode_context = NULL;
150 oparams->decode = NULL;
151 oparams->param_version = 0;
152
153 return SASL_OK;
154 }
155
156 static int
external_server_mech_avail(void * glob_context,sasl_server_params_t * sparams,void ** conn_context)157 external_server_mech_avail(void *glob_context __attribute__((unused)),
158 sasl_server_params_t *sparams,
159 void **conn_context __attribute__((unused)))
160 {
161 if (!sparams->utils->conn->external.auth_id) {
162 /* Return Temporary Failure */
163 return SASL_NOTDONE;
164 }
165
166 return SASL_OK;
167 }
168
169 static sasl_server_plug_t external_server_plugins[] =
170 {
171 {
172 "EXTERNAL", /* mech_name */
173 0, /* max_ssf */
174 SASL_SEC_NOPLAINTEXT
175 | SASL_SEC_NOANONYMOUS
176 | SASL_SEC_NODICTIONARY, /* security_flags */
177 SASL_FEAT_WANT_CLIENT_FIRST
178 | SASL_FEAT_ALLOWS_PROXY, /* features */
179 NULL, /* glob_context */
180 &external_server_mech_new, /* mech_new */
181 &external_server_mech_step, /* mech_step */
182 NULL, /* mech_dispose */
183 NULL, /* mech_free */
184 NULL, /* setpass */
185 NULL, /* user_query */
186 NULL, /* idle */
187 &external_server_mech_avail, /* mech_avail */
188 NULL /* spare */
189 }
190 };
191
external_server_plug_init(const sasl_utils_t * utils,int max_version,int * out_version,sasl_server_plug_t ** pluglist,int * plugcount)192 int external_server_plug_init(const sasl_utils_t *utils,
193 int max_version,
194 int *out_version,
195 sasl_server_plug_t **pluglist,
196 int *plugcount)
197 {
198 if (!out_version || !pluglist || !plugcount)
199 return SASL_BADPARAM;
200
201 if (max_version != SASL_SERVER_PLUG_VERSION) {
202 SETERROR( utils, "EXTERNAL version mismatch" );
203 return SASL_BADVERS;
204 }
205
206 *out_version = SASL_SERVER_PLUG_VERSION;
207 *pluglist = external_server_plugins;
208 *plugcount = 1;
209 return SASL_OK;
210 }
211
212 /***************************** Client Section *****************************/
213
214 typedef struct client_context
215 {
216 char *out_buf;
217 size_t out_buf_len;
218 } client_context_t;
219
external_client_mech_new(void * glob_context,sasl_client_params_t * params,void ** conn_context)220 static int external_client_mech_new(void *glob_context __attribute__((unused)),
221 sasl_client_params_t *params,
222 void **conn_context)
223 {
224 client_context_t *text;
225
226 if (!params
227 || !params->utils
228 || !params->utils->conn
229 || !conn_context)
230 return SASL_BADPARAM;
231
232 if (!params->utils->conn->external.auth_id)
233 return SASL_NOMECH;
234
235 text = sasl_ALLOC(sizeof(client_context_t));
236 if(!text) return SASL_NOMEM;
237
238 memset(text, 0, sizeof(client_context_t));
239
240 *conn_context = text;
241
242 return SASL_OK;
243 }
244
245 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)246 external_client_mech_step(void *conn_context,
247 sasl_client_params_t *params,
248 const char *serverin __attribute__((unused)),
249 unsigned serverinlen,
250 sasl_interact_t **prompt_need,
251 const char **clientout,
252 unsigned *clientoutlen,
253 sasl_out_params_t *oparams)
254 {
255 client_context_t *text = (client_context_t *)conn_context;
256 const char *user = NULL;
257 int user_result = SASL_OK;
258 int result;
259
260 if (!params
261 || !params->utils
262 || !params->utils->conn
263 || !params->utils->getcallback
264 || !clientout
265 || !clientoutlen
266 || !oparams)
267 return SASL_BADPARAM;
268
269 if (!params->utils->conn->external.auth_id)
270 return SASL_BADPROT;
271
272 if (serverinlen != 0)
273 return SASL_BADPROT;
274
275 *clientout = NULL;
276 *clientoutlen = 0;
277
278 /* try to get the userid */
279 if (user == NULL) {
280 user_result = _plug_get_userid(params->utils, &user, prompt_need);
281
282 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
283 return user_result;
284 }
285
286 /* free prompts we got */
287 if (prompt_need && *prompt_need) {
288 params->utils->free(*prompt_need);
289 *prompt_need = NULL;
290 }
291
292 /* if there are prompts not filled in */
293 if (user_result == SASL_INTERACT) {
294 /* make the prompt list */
295 int result =
296 _plug_make_prompts(params->utils, prompt_need,
297 "Please enter your authorization name",
298 "",
299 NULL, NULL,
300 NULL, NULL,
301 NULL, NULL, NULL,
302 NULL, NULL, NULL);
303 if (result != SASL_OK) return result;
304
305 return SASL_INTERACT;
306 }
307
308 *clientoutlen = user ? (unsigned) strlen(user) : 0;
309
310 result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
311
312 if (result != SASL_OK) return result;
313
314 if (user && *user) {
315 result = params->canon_user(params->utils->conn,
316 user, 0, SASL_CU_AUTHZID, oparams);
317 if (result != SASL_OK) return result;
318
319 result = params->canon_user(params->utils->conn,
320 params->utils->conn->external.auth_id, 0,
321 SASL_CU_AUTHID, oparams);
322 if (result != SASL_OK) return result;
323
324 memcpy(text->out_buf, user, *clientoutlen);
325 } else {
326 result = params->canon_user(params->utils->conn,
327 params->utils->conn->external.auth_id, 0,
328 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
329 if (result != SASL_OK) return result;
330 }
331
332 text->out_buf[*clientoutlen] = '\0';
333
334 *clientout = text->out_buf;
335
336 /* set oparams */
337 oparams->doneflag = 1;
338 oparams->mech_ssf = 0;
339 oparams->maxoutbuf = 0;
340 oparams->encode_context = NULL;
341 oparams->encode = NULL;
342 oparams->decode_context = NULL;
343 oparams->decode = NULL;
344 oparams->param_version = 0;
345
346 return SASL_OK;
347 }
348
349 static void
external_client_mech_dispose(void * conn_context,const sasl_utils_t * utils)350 external_client_mech_dispose(void *conn_context,
351 const sasl_utils_t *utils __attribute__((unused)))
352 {
353 client_context_t *text = (client_context_t *) conn_context;
354
355 if (!text) return;
356
357 if(text->out_buf) sasl_FREE(text->out_buf);
358
359 sasl_FREE(text);
360 }
361
362 static const unsigned long external_required_prompts[] = {
363 SASL_CB_LIST_END
364 };
365
366 static sasl_client_plug_t external_client_plugins[] =
367 {
368 {
369 "EXTERNAL", /* mech_name */
370 0, /* max_ssf */
371 SASL_SEC_NOPLAINTEXT
372 | SASL_SEC_NOANONYMOUS
373 | SASL_SEC_NODICTIONARY, /* security_flags */
374 SASL_FEAT_WANT_CLIENT_FIRST
375 | SASL_FEAT_ALLOWS_PROXY, /* features */
376 external_required_prompts, /* required_prompts */
377 NULL, /* glob_context */
378 &external_client_mech_new, /* mech_new */
379 &external_client_mech_step, /* mech_step */
380 &external_client_mech_dispose, /* mech_dispose */
381 NULL, /* mech_free */
382 NULL, /* idle */
383 NULL, /* spare */
384 NULL /* spare */
385 }
386 };
387
external_client_plug_init(const sasl_utils_t * utils,int max_version,int * out_version,sasl_client_plug_t ** pluglist,int * plugcount)388 int external_client_plug_init(const sasl_utils_t *utils,
389 int max_version,
390 int *out_version,
391 sasl_client_plug_t **pluglist,
392 int *plugcount)
393 {
394 if (!utils || !out_version || !pluglist || !plugcount)
395 return SASL_BADPARAM;
396
397 if (max_version != SASL_CLIENT_PLUG_VERSION) {
398 SETERROR( utils, "EXTERNAL version mismatch" );
399 return SASL_BADVERS;
400 }
401
402 *out_version = SASL_CLIENT_PLUG_VERSION;
403 *pluglist = external_client_plugins;
404 *plugcount = 1;
405
406 return SASL_OK;
407 }
408