1 /* sample-server.c -- sample SASL server
3 * $Id: sample-server.c,v 1.31 2004/10/26 11:14:34 mel Exp $
6 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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 * Office of Technology Transfer
25 * Carnegie Mellon University
27 * Pittsburgh, PA 15213-3890
28 * (412) 268-4387, fax: (412) 268-7395
29 * tech-transfer@andrew.cmu.edu
31 * 4. Redistributions of any form whatsoever must retain the following
33 * "This product includes software developed by Computing Services
34 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 # include <winsock2.h>
58 __declspec(dllimport) char *optarg;
59 __declspec(dllimport) int optind;
60 __declspec(dllimport) int getsubopt(char **optionp, const char * const *tokens, char **valuep);
61 #define HAVE_GETSUBOPT
63 # include <netinet/in.h>
68 #ifndef HAVE_GETSUBOPT
69 int getsubopt(char **optionp, const char * const *tokens, char **valuep);
73 build_ident[] = "$Build: sample-server " PACKAGE "-" VERSION " $";
75 static const char *progname = NULL;
78 /* Note: if this is changed, change it in samp_read(), too. */
79 #define SAMPLE_SEC_BUF_SIZE (2048)
82 message[] = "Come here Watson, I want you.";
84 char buf[SAMPLE_SEC_BUF_SIZE];
86 static const char *bit_subopts[] = {
94 static const char *ext_subopts[] = {
95 #define OPT_EXT_SSF (0)
97 #define OPT_EXT_ID (1)
102 static const char *flag_subopts[] = {
103 #define OPT_NOPLAIN (0)
105 #define OPT_NOACTIVE (1)
107 #define OPT_NODICT (2)
109 #define OPT_FORWARDSEC (3)
111 #define OPT_NOANONYMOUS (4)
113 #define OPT_PASSCRED (5)
118 static const char *ip_subopts[] = {
119 #define OPT_IP_LOCAL (0)
121 #define OPT_IP_REMOTE (1)
133 sasl_conn_t *conn = NULL;
143 sasl_my_log(void *context __attribute__((unused)),
150 return SASL_BADPARAM;
164 fprintf(stderr, "%s: SASL %s: %s\n",
165 progname, label, message);
171 getpath(void *context __attribute__((unused)),
175 return SASL_BADPARAM;
186 static sasl_callback_t callbacks[] = {
188 SASL_CB_LOG, &sasl_my_log, NULL
190 SASL_CB_GETPATH, &getpath, NULL
192 SASL_CB_LIST_END, NULL, NULL
197 sasldebug(int why, const char *what, const char *errstr)
199 fprintf(stderr, "%s: %s: %s",
202 sasl_errstring(why, NULL, NULL));
204 fprintf(stderr, " (%s)\n", errstr);
210 saslfail(int why, const char *what, const char *errstr)
212 sasldebug(why, what, errstr);
217 fail(const char *what)
219 fprintf(stderr, "%s: %s\n",
232 samp_send(const char *buffer,
236 unsigned len, alloclen;
239 alloclen = ((length / 3) + 1) * 4 + 1;
240 buf = malloc(alloclen);
244 result = sasl_encode64(buffer, length, buf, alloclen, &len);
245 if (result != SASL_OK)
246 saslfail(result, "Encoding data in base64", NULL);
247 printf("S: %s\n", buf);
257 if (! fgets(buf, SAMPLE_SEC_BUF_SIZE, stdin))
258 fail("Unable to parse input");
260 if (strncmp(buf, "C: ", 3)!=0)
261 fail("Line must start with 'C: '");
263 result = sasl_decode64(buf + 3, (unsigned) strlen(buf + 3), buf,
264 SAMPLE_SEC_BUF_SIZE, &len);
265 if (result != SASL_OK)
266 saslfail(result, "Decoding data from base64", NULL);
268 printf("got '%s'\n", buf);
274 main(int argc, char *argv[])
279 sasl_security_properties_t secprops;
280 sasl_ssf_t extssf = 0;
281 const char *ext_authid = NULL;
282 char *options, *value;
289 /* initialize winsock */
292 result = WSAStartup( MAKEWORD(2, 0), &wsaData );
294 saslfail(SASL_FAIL, "Initializing WinSockets", NULL);
298 progname = strrchr(argv[0], HIER_DELIMITER);
304 /* Init defaults... */
305 memset(&secprops, 0L, sizeof(secprops));
306 secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE;
307 secprops.max_ssf = UINT_MAX;
310 while ((c = getopt(argc, argv, "vlhb:e:m:f:i:p:s:d:u:?")) != EOF)
317 while (*options != '\0')
318 switch(getsubopt(&options, (const char * const *)bit_subopts, &value)) {
323 secprops.min_ssf = atoi(value);
329 secprops.max_ssf = atoi(value);
339 while (*options != '\0')
340 switch(getsubopt(&options, (const char * const *)ext_subopts, &value)) {
345 extssf = atoi(value);
365 while (*options != '\0') {
366 switch(getsubopt(&options, (const char * const *)flag_subopts, &value)) {
368 secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
371 secprops.security_flags |= SASL_SEC_NOACTIVE;
374 secprops.security_flags |= SASL_SEC_NODICTIONARY;
377 secprops.security_flags |= SASL_SEC_FORWARD_SECRECY;
379 case OPT_NOANONYMOUS:
380 secprops.security_flags |= SASL_SEC_NOANONYMOUS;
383 secprops.security_flags |= SASL_SEC_PASS_CREDENTIALS;
389 if (value) errflag = 1;
394 serverlast = SASL_SUCCESS_DATA;
399 while (*options != '\0')
400 switch(getsubopt(&options, (const char * const *)ip_subopts, &value)) {
428 localdomain = optarg;
440 if (optind != argc) {
446 fprintf(stderr, "%s: Usage: %s [-b min=N,max=N] [-e ssf=N,id=ID] [-m MECH] [-f FLAGS] [-i local=IP,remote=IP] [-p PATH] [-d DOM] [-u DOM] [-s NAME]\n"
447 "\t-b ...\t#bits to use for encryption\n"
448 "\t\tmin=N\tminumum #bits to use (1 => integrity)\n"
449 "\t\tmax=N\tmaximum #bits to use\n"
450 "\t-e ...\tassume external encryption\n"
451 "\t\tssf=N\texternal mech provides N bits of encryption\n"
452 "\t\tid=ID\texternal mech provides authentication id ID\n"
453 "\t-m MECH\tforce use of MECH for security\n"
454 "\t-f ...\tset security flags\n"
455 "\t\tnoplain\t\trequire security vs. passive attacks\n"
456 "\t\tnoactive\trequire security vs. active attacks\n"
457 "\t\tnodict\t\trequire security vs. passive dictionary attacks\n"
458 "\t\tforwardsec\trequire forward secrecy\n"
459 "\t\tmaximum\t\trequire all security flags\n"
460 "\t\tpasscred\tattempt to receive client credentials\n"
461 "\t-i ...\tset IP addresses (required by some mechs)\n"
462 "\t\tlocal=IP;PORT\tset local address to IP, port PORT\n"
463 "\t\tremote=IP;PORT\tset remote address to IP, port PORT\n"
464 "\t-p PATH\tcolon-seperated search path for mechanisms\n"
465 "\t-s NAME\tservice name to pass to mechanisms\n"
466 "\t-d DOM\tlocal server domain\n"
467 "\t-u DOM\tuser domain\n"
468 "\t-l\tenable server-send-last\n",
473 result = sasl_server_init(callbacks, "sample");
474 if (result != SASL_OK)
475 saslfail(result, "Initializing libsasl", NULL);
479 result = sasl_server_new(service,
487 if (result != SASL_OK)
488 saslfail(result, "Allocating sasl connection state", NULL);
493 result = sasl_setprop(conn,
497 if (result != SASL_OK)
498 saslfail(result, "Setting external SSF", NULL);
502 result = sasl_setprop(conn,
506 if (result != SASL_OK)
507 saslfail(result, "Setting external authid", NULL);
510 result = sasl_setprop(conn,
514 if (result != SASL_OK)
515 saslfail(result, "Setting security properties", NULL);
518 printf("Forcing use of mechanism %s\n", mech);
522 len = (unsigned) strlen(data);
525 puts("Generating client mechanism list...");
526 result = sasl_listmech(conn,
534 if (result != SASL_OK)
535 saslfail(result, "Generating client mechanism list", NULL);
538 printf("Sending list of %d mechanism(s)\n", count);
539 samp_send(data, len);
545 puts("Waiting for client mechanism...");
547 if (mech && strcasecmp(mech, buf))
548 fail("Client chose something other than the mandatory mechanism");
549 if (strlen(buf) < len) {
550 /* Hmm, there's an initial response here */
551 data = buf + strlen(buf) + 1;
552 len = len - strlen(buf) - 1;
557 result = sasl_server_start(conn,
563 if (result != SASL_OK && result != SASL_CONTINUE)
564 saslfail(result, "Starting SASL negotiation", sasl_errstring(result,NULL,NULL));
566 while (result == SASL_CONTINUE) {
568 puts("Sending response...");
569 samp_send(data, len);
571 fail("No data to send--something's wrong");
572 puts("Waiting for client reply...");
575 result = sasl_server_step(conn, buf, len,
577 if (result != SASL_OK && result != SASL_CONTINUE)
578 saslfail(result, "Performing SASL negotiation", sasl_errstring(result,NULL,NULL));
580 puts("Negotiation complete");
582 if(serverlast&&data) {
583 printf("might need additional send:\n");
587 result = sasl_getprop(conn, SASL_USERNAME, (const void **)&data);
588 if (result != SASL_OK)
589 sasldebug(result, "username", NULL);
591 printf("Username: %s\n", data ? data : "(NULL)");
593 result = sasl_getprop(conn, SASL_DEFUSERREALM, (const void **)&data);
594 if (result != SASL_OK)
595 sasldebug(result, "realm", NULL);
597 printf("Realm: %s\n", data ? data : "(NULL)");
599 result = sasl_getprop(conn, SASL_SSF, (const void **)&ssf);
600 if (result != SASL_OK)
601 sasldebug(result, "ssf", NULL);
603 printf("SSF: %d\n", *ssf);
604 #define CLIENT_MSG1 "client message 1"
605 #define SERVER_MSG1 "srv message 1"
606 result=sasl_encode(conn,SERVER_MSG1,sizeof(SERVER_MSG1),
608 if (result != SASL_OK)
609 saslfail(result, "sasl_encode", NULL);
610 printf("sending encrypted message '%s'\n",SERVER_MSG1);
612 printf("Waiting for encrypted message...\n");
615 unsigned int recv_len;
616 const char *recv_data;
617 result=sasl_decode(conn,buf,len,&recv_data,&recv_len);
618 if (result != SASL_OK)
619 saslfail(result, "sasl_encode", NULL);
620 printf("recieved decoded message '%s'\n",recv_data);
621 if(strcmp(recv_data,CLIENT_MSG1)!=0)
622 saslfail(1,"recive decoded server message",NULL);
629 return (EXIT_SUCCESS);