source: trunk/third/cyrus-sasl/sample/sample-server.c @ 17977

Revision 17977, 14.0 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17976, which included commits to RCS files with non-trunk default branches.
Line 
1/* sample-server.c -- sample SASL server
2 * Rob Earhart
3 * $Id: sample-server.c,v 1.1.1.1 2002-10-13 18:00:17 ghudson Exp $
4 */
5/*
6 * Copyright (c) 2001 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 *      Office of Technology Transfer
25 *      Carnegie Mellon University
26 *      5000 Forbes Avenue
27 *      Pittsburgh, PA  15213-3890
28 *      (412) 268-4387, fax: (412) 268-7395
29 *      tech-transfer@andrew.cmu.edu
30 *
31 * 4. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by Computing Services
34 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 *
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.
43 */
44
45#include <config.h>
46#include <limits.h>
47#include <stdio.h>
48#ifdef WIN32
49# include <winsock.h>
50__declspec(dllimport) char *optarg;
51__declspec(dllimport) int optind;
52__declspec(dllimport) int getsubopt(char **optionp, const char * const *tokens, char **valuep);
53#else /* WIN32 */
54# include <netinet/in.h>
55#endif /* WIN32 */
56#include <sasl.h>
57#include <saslutil.h>
58
59#ifdef HAVE_GETOPT_H
60#include <getopt.h>
61#endif
62#ifdef HAVE_UNISTD_H
63#include <unistd.h>
64#endif
65
66#ifndef HAVE_GETSUBOPT
67int getsubopt(char **optionp, const char * const *tokens, char **valuep);
68#endif
69
70static const char
71build_ident[] = "$Build: sample-server " PACKAGE "-" VERSION " $";
72
73static const char *progname = NULL;
74static int verbose;
75
76/* Note: if this is changed, change it in samp_read(), too. */
77#define SAMPLE_SEC_BUF_SIZE (2048)
78
79static const char
80message[] = "Come here Watson, I want you.";
81
82char buf[SAMPLE_SEC_BUF_SIZE];
83
84static const char *bit_subopts[] = {
85#define OPT_MIN (0)
86  "min",
87#define OPT_MAX (1)
88  "max",
89  NULL
90};
91
92static const char *ext_subopts[] = {
93#define OPT_EXT_SSF (0)
94  "ssf",
95#define OPT_EXT_ID (1)
96  "id",
97  NULL
98};
99
100static const char *flag_subopts[] = {
101#define OPT_NOPLAIN (0)
102  "noplain",
103#define OPT_NOACTIVE (1)
104  "noactive",
105#define OPT_NODICT (2)
106  "nodict",
107#define OPT_FORWARDSEC (3)
108  "forwardsec",
109#define OPT_NOANONYMOUS (4)
110  "noanonymous",
111#define OPT_PASSCRED (5)
112  "passcred",
113  NULL
114};
115
116static const char *ip_subopts[] = {
117#define OPT_IP_LOCAL (0)
118  "local",
119#define OPT_IP_REMOTE (1)
120  "remote",
121  NULL
122};
123
124char *mech = NULL,
125  *iplocal = NULL,
126  *ipremote = NULL,
127  *searchpath = NULL,
128  *service = "rcmd",
129  *localdomain = NULL,
130  *userdomain = NULL;
131sasl_conn_t *conn = NULL;
132
133static void
134free_conn(void)
135{
136  if (conn)
137    sasl_dispose(&conn);
138}
139
140static int
141sasl_my_log(void *context __attribute__((unused)),
142            int priority,
143            const char *message)
144{
145  const char *label;
146
147  if (! message)
148    return SASL_BADPARAM;
149
150  switch (priority) {
151  case SASL_LOG_ERR:
152    label = "Error";
153    break;
154  case SASL_LOG_NOTE:
155    label = "Info";
156    break;
157  default:
158    label = "Other";
159    break;
160  }
161
162  fprintf(stderr, "%s: SASL %s: %s\n",
163          progname, label, message);
164
165  return SASL_OK;
166}
167
168static int
169getpath(void *context __attribute__((unused)),
170        char ** path)
171{
172  if (! path)
173    return SASL_BADPARAM;
174
175  if (searchpath) {
176    *path = searchpath;
177  } else {
178    *path = PLUGINDIR;
179  }
180
181  return SASL_OK;
182}
183
184static sasl_callback_t callbacks[] = {
185  {
186    SASL_CB_LOG, &sasl_my_log, NULL
187  }, {
188    SASL_CB_GETPATH, &getpath, NULL
189  }, {
190    SASL_CB_LIST_END, NULL, NULL
191  }
192};
193
194static void
195sasldebug(int why, const char *what, const char *errstr)
196{
197  fprintf(stderr, "%s: %s: %s",
198          progname,
199          what,
200          sasl_errstring(why, NULL, NULL));
201  if (errstr)
202    fprintf(stderr, " (%s)\n", errstr);
203  else
204    putc('\n', stderr);
205}
206
207static void
208saslfail(int why, const char *what, const char *errstr)
209{
210  sasldebug(why, what, errstr);
211  exit(EXIT_FAILURE);
212}
213
214static void
215fail(const char *what)
216{
217  fprintf(stderr, "%s: %s\n",
218          progname, what);
219  exit(EXIT_FAILURE);
220}
221
222static void
223osfail()
224{
225  perror(progname);
226  exit(EXIT_FAILURE);
227}
228
229static void
230samp_send(const char *buffer,
231          unsigned length)
232{
233  char *buf;
234  unsigned len, alloclen;
235  int result;
236
237  alloclen = ((length / 3) + 1) * 4 + 1;
238  buf = malloc(alloclen);
239  if (! buf)
240    osfail();
241
242  result = sasl_encode64(buffer, length, buf, alloclen, &len);
243  if (result != SASL_OK)
244    saslfail(result, "Encoding data in base64", NULL);
245  printf("S: %s\n", buf);
246  free(buf);
247}
248
249static unsigned
250samp_recv()
251{
252  unsigned len;
253  int result;
254 
255  if (! fgets(buf, SAMPLE_SEC_BUF_SIZE, stdin))
256    fail("Unable to parse input");
257
258  if (strncmp(buf, "C: ", 3)!=0)
259    fail("Line must start with 'C: '");
260   
261  result = sasl_decode64(buf + 3, strlen(buf + 3), buf,
262                         SAMPLE_SEC_BUF_SIZE, &len);
263  if (result != SASL_OK)
264    saslfail(result, "Decoding data from base64", NULL);
265  buf[len] = '\0';
266  printf("got '%s'\n", buf);
267  return len;
268}
269
270
271int
272main(int argc, char *argv[])
273{
274  int c = 0;
275  int errflag = 0;
276  int result;
277  sasl_security_properties_t secprops;
278  sasl_ssf_t extssf = 0;
279  const char *ext_authid = NULL;
280  char *options, *value;
281  unsigned len, count;
282  const char *data;
283  int serverlast = 0;
284  sasl_ssf_t *ssf;
285
286  progname = strrchr(argv[0], '/');
287  if (progname)
288    progname++;
289  else
290    progname = argv[0];
291
292  /* Init defaults... */
293  memset(&secprops, 0L, sizeof(secprops));
294  secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE;
295  secprops.max_ssf = UINT_MAX;
296
297  verbose = 0;
298  while ((c = getopt(argc, argv, "vlhb:e:m:f:i:p:s:d:u:?")) != EOF)
299    switch (c) {
300    case 'v':
301        verbose = 1;
302        break;
303    case 'b':
304      options = optarg;
305      while (*options != '\0')
306        switch(getsubopt(&options, (const char * const *)bit_subopts, &value)) {
307        case OPT_MIN:
308          if (! value)
309            errflag = 1;
310          else
311            secprops.min_ssf = atoi(value);
312          break;
313        case OPT_MAX:
314          if (! value)
315            errflag = 1;
316          else
317            secprops.max_ssf = atoi(value);
318          break;
319        default:
320          errflag = 1;
321          break;
322          }
323      break;
324
325    case 'e':
326      options = optarg;
327      while (*options != '\0')
328        switch(getsubopt(&options, (const char * const *)ext_subopts, &value)) {
329        case OPT_EXT_SSF:
330          if (! value)
331            errflag = 1;
332          else
333            extssf = atoi(value);
334          break;
335        case OPT_MAX:
336          if (! value)
337            errflag = 1;
338          else
339            ext_authid = value;
340          break;
341        default:
342          errflag = 1;
343          break;
344          }
345      break;
346
347    case 'm':
348      mech = optarg;
349      break;
350
351    case 'f':
352      options = optarg;
353      while (*options != '\0') {
354        switch(getsubopt(&options, (const char * const *)flag_subopts, &value)) {
355        case OPT_NOPLAIN:
356          secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
357          break;
358        case OPT_NOACTIVE:
359          secprops.security_flags |= SASL_SEC_NOACTIVE;
360          break;
361        case OPT_NODICT:
362          secprops.security_flags |= SASL_SEC_NODICTIONARY;
363          break;
364        case OPT_FORWARDSEC:
365          secprops.security_flags |= SASL_SEC_FORWARD_SECRECY;
366          break;
367        case OPT_NOANONYMOUS:
368          secprops.security_flags |= SASL_SEC_NOANONYMOUS;
369          break;
370        case OPT_PASSCRED:
371          secprops.security_flags |= SASL_SEC_PASS_CREDENTIALS;
372          break;
373        default:
374          errflag = 1;
375          break;
376          }
377        if (value) errflag = 1;
378        }
379      break;
380
381    case 'l':
382        serverlast = SASL_SUCCESS_DATA;
383        break;
384
385    case 'i':
386      options = optarg;
387      while (*options != '\0')
388        switch(getsubopt(&options, (const char * const *)ip_subopts, &value)) {
389        case OPT_IP_LOCAL:
390          if (! value)
391            errflag = 1;
392          else
393            iplocal = value;
394          break;
395        case OPT_IP_REMOTE:
396          if (! value)
397            errflag = 1;
398          else
399            ipremote = value;
400          break;
401        default:
402          errflag = 1;
403          break;
404          }
405      break;
406
407    case 'p':
408      searchpath = optarg;
409      break;
410
411    case 's':
412      service = optarg;
413      break;
414
415    case 'd':
416      localdomain = optarg;
417      break;
418
419    case 'u':
420      userdomain = optarg;
421      break;
422
423    default:           
424      errflag = 1;
425      break;
426    }
427
428  if (optind != argc) {
429   
430    errflag = 1;
431  }
432
433  if (errflag) {
434    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"
435            "\t-b ...\t#bits to use for encryption\n"
436            "\t\tmin=N\tminumum #bits to use (1 => integrity)\n"
437            "\t\tmax=N\tmaximum #bits to use\n"
438            "\t-e ...\tassume external encryption\n"
439            "\t\tssf=N\texternal mech provides N bits of encryption\n"
440            "\t\tid=ID\texternal mech provides authentication id ID\n"
441            "\t-m MECH\tforce use of MECH for security\n"
442            "\t-f ...\tset security flags\n"
443            "\t\tnoplain\t\trequire security vs. passive attacks\n"
444            "\t\tnoactive\trequire security vs. active attacks\n"
445            "\t\tnodict\t\trequire security vs. passive dictionary attacks\n"
446            "\t\tforwardsec\trequire forward secrecy\n"
447            "\t\tmaximum\t\trequire all security flags\n"
448            "\t\tpasscred\tattempt to receive client credentials\n"
449            "\t-i ...\tset IP addresses (required by some mechs)\n"
450            "\t\tlocal=IP;PORT\tset local address to IP, port PORT\n"
451            "\t\tremote=IP;PORT\tset remote address to IP, port PORT\n"
452            "\t-p PATH\tcolon-seperated search path for mechanisms\n"
453            "\t-s NAME\tservice name to pass to mechanisms\n"
454            "\t-d DOM\tlocal server domain\n"
455            "\t-u DOM\tuser domain\n"
456            "\t-l\tenable server-send-last\n",
457            progname, progname);
458    exit(EXIT_FAILURE);
459  }
460
461  result = sasl_server_init(callbacks, "sample");
462  if (result != SASL_OK)
463    saslfail(result, "Initializing libsasl", NULL);
464
465  atexit(&sasl_done);
466
467  result = sasl_server_new(service,
468                           localdomain,
469                           userdomain,
470                           iplocal,
471                           ipremote,
472                           NULL,
473                           serverlast,
474                           &conn);
475  if (result != SASL_OK)
476    saslfail(result, "Allocating sasl connection state", NULL);
477 
478  atexit(&free_conn);
479
480  if(extssf) {
481      result = sasl_setprop(conn,
482                            SASL_SSF_EXTERNAL,
483                            &extssf);
484
485      if (result != SASL_OK)
486          saslfail(result, "Setting external SSF", NULL);
487  }
488 
489  if(ext_authid) {
490      result = sasl_setprop(conn,
491                            SASL_AUTH_EXTERNAL,
492                            &ext_authid);
493
494      if (result != SASL_OK)
495          saslfail(result, "Setting external authid", NULL);
496  }
497
498  result = sasl_setprop(conn,
499                        SASL_SEC_PROPS,
500                        &secprops);
501
502  if (result != SASL_OK)
503    saslfail(result, "Setting security properties", NULL);
504
505  if (mech) {
506    printf("Forcing use of mechanism %s\n", mech);
507    data = strdup(mech);
508    if (! data)
509      osfail();
510    len = strlen(data);
511    count = 1;
512  } else {
513    puts("Generating client mechanism list...");
514    result = sasl_listmech(conn,
515                           ext_authid,
516                           NULL,
517                           " ",
518                           NULL,
519                           &data,
520                           &len,
521                           &count);
522    if (result != SASL_OK)
523      saslfail(result, "Generating client mechanism list", NULL);
524  }
525 
526  printf("Sending list of %d mechanism(s)\n", count);
527  samp_send(data, len);
528
529  if(mech) {
530      free((void *)data);
531  }
532
533  puts("Waiting for client mechanism...");
534  len = samp_recv();
535  if (mech && strcasecmp(mech, buf))
536    fail("Client chose something other than the mandatory mechanism");
537  if (strlen(buf) < len) {
538    /* Hmm, there's an initial response here */
539    data = buf + strlen(buf) + 1;
540    len = len - strlen(buf) - 1;
541  } else {
542    data = NULL;
543    len = 0;
544  }
545  result = sasl_server_start(conn,
546                             buf,
547                             data,
548                             len,
549                             &data,
550                             &len);
551  if (result != SASL_OK && result != SASL_CONTINUE)
552    saslfail(result, "Starting SASL negotiation", sasl_errstring(result,NULL,NULL));
553
554  while (result == SASL_CONTINUE) {
555    if (data) {
556      puts("Sending response...");
557      samp_send(data, len);
558    } else
559      fail("No data to send--something's wrong");
560    puts("Waiting for client reply...");
561    len = samp_recv();
562    data = NULL;
563    result = sasl_server_step(conn, buf, len,
564                              &data, &len);
565    if (result != SASL_OK && result != SASL_CONTINUE)
566      saslfail(result, "Performing SASL negotiation", sasl_errstring(result,NULL,NULL));
567  }
568  puts("Negotiation complete");
569
570  if(serverlast&&data) {
571      printf("might need additional send:\n");
572      samp_send(data,len);
573  }
574
575  result = sasl_getprop(conn, SASL_USERNAME, (const void **)&data);
576  if (result != SASL_OK)
577    sasldebug(result, "username", NULL);
578  else
579    printf("Username: %s\n", data);
580
581  result = sasl_getprop(conn, SASL_DEFUSERREALM, (const void **)&data);
582  if (result != SASL_OK)
583    sasldebug(result, "realm", NULL);
584  else
585    printf("Realm: %s\n", data);
586
587  result = sasl_getprop(conn, SASL_SSF, (const void **)&ssf);
588  if (result != SASL_OK)
589    sasldebug(result, "ssf", NULL);
590  else
591    printf("SSF: %d\n", *ssf);
592#define CLIENT_MSG1 "client message 1"
593#define SERVER_MSG1 "srv message 1"
594  result=sasl_encode(conn,SERVER_MSG1,sizeof(SERVER_MSG1),
595        &data,&len);
596  if (result != SASL_OK)
597      saslfail(result, "sasl_encode", NULL);
598  printf("sending encrypted message '%s'\n",SERVER_MSG1);
599  samp_send(data,len);
600  printf("Waiting for encrypted message...\n");
601  len=samp_recv();
602 {
603        unsigned int recv_len;
604        const char *recv_data;
605        result=sasl_decode(conn,buf,len,&recv_data,&recv_len);
606        if (result != SASL_OK)
607      saslfail(result, "sasl_encode", NULL);
608    printf("recieved decoded message '%s'\n",recv_data);
609    if(strcmp(recv_data,CLIENT_MSG1)!=0)
610        saslfail(1,"recive decoded server message",NULL);
611 }
612
613  return (EXIT_SUCCESS);
614}
Note: See TracBrowser for help on using the repository browser.