gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

gsasl.c
Go to the documentation of this file.
1 /* gsasl.c --- Command line interface to libgsasl.
2  * Copyright (C) 2002-2021 Simon Josefsson
3  *
4  * This file is part of GNU SASL.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "internal.h"
22 #include "callbacks.h"
23 #include "imap.h"
24 #include "smtp.h"
25 
26 #include "sockets.h"
27 
28 #ifdef HAVE_LIBGNUTLS
29 #include <gnutls/gnutls.h>
30 #include <gnutls/x509.h>
31 gnutls_session_t session;
32 bool using_tls = false;
33 #endif
34 
36 
38 int sockfd = 0;
39 
40 #ifdef HAVE_LIBGNUTLS
41 static bool
42 _handle_tlserror (int error)
43 {
44  int rc;
45 
46  switch (error)
47  {
48  case GNUTLS_E_REHANDSHAKE:
49  for (;;)
50  {
51  rc = gnutls_handshake (session);
52  switch (rc)
53  {
54  case GNUTLS_E_INTERRUPTED:
55  case GNUTLS_E_AGAIN:
56  continue;
57 
58  case GNUTLS_E_GOT_APPLICATION_DATA:
59  /* TODO: signal this somehow? */
60  continue;
61 
62  case GNUTLS_E_WARNING_ALERT_RECEIVED:
63  fprintf (stderr, "ALERT: %s\n",
64  gnutls_alert_get_name (gnutls_alert_get (session)));
65  continue;
66 
67  default:
68  fprintf (stderr, "TLS rehandshake failed: %s\n",
69  gnutls_strerror (rc));
70  /* make every error fatal */
71  return false;
72  }
73 
74  return true;
75  }
76 
77  case GNUTLS_E_INTERRUPTED:
78  case GNUTLS_E_AGAIN:
79  /* not fatal */
80  return true;
81 
82  default:
83  fprintf (stderr, "TLS error: %s\n", gnutls_strerror (error));
84  return false;
85  }
86 }
87 #endif
88 
89 static ssize_t
90 _recv (void *dst, size_t cnt)
91 {
92 #ifdef HAVE_LIBGNUTLS
93  if (using_tls)
94  {
95  ssize_t l = 0;
96  do
97  {
98  l = gnutls_record_recv (session, dst, cnt);
99 
100  if (l < 0 && !_handle_tlserror (l))
101  break;
102  }
103  while (l < 0);
104 
105  return l;
106  }
107 #endif
108 
109  return recv (sockfd, dst, cnt, 0);
110 }
111 
112 static ssize_t
113 _send (void const *src, size_t cnt)
114 {
115 #ifdef HAVE_LIBGNUTLS
116  if (using_tls)
117  {
118  ssize_t l;
119  do
120  {
121  if (cnt > 0)
122  l = gnutls_record_send (session, src, cnt);
123  else
124  l = 0;
125 
126  if (l < 0 && !_handle_tlserror (l))
127  break;
128  }
129  while (l < 0);
130 
131  return l;
132  }
133 #endif
134 
135  return write (sockfd, src, cnt);
136 }
137 
138 int
139 writeln (const char *str)
140 {
141  printf ("%s\n", str);
142 
143  if (sockfd)
144  {
145  ssize_t len = strlen (str);
146 
147  len = _send (str, len);
148  if (len != (ssize_t) strlen (str))
149  return 0;
150 
151 #define CRLF "\r\n"
152 
153  len = _send (CRLF, strlen (CRLF));
154  if (len != strlen (CRLF))
155  return 0;
156  }
157 
158  return 1;
159 }
160 
161 int
162 readln (char **out)
163 {
164  if (sockfd)
165  {
166  size_t allocated = 0, used = 0;
167  char *input = NULL;
168 
169  /* FIXME: Read larger chunks. Problem: buffering too large reads? */
170 
171  do
172  {
173  ssize_t nread;
174 
175  if (used == allocated)
176  input = x2realloc (input, &allocated);
177 
178  nread = _recv (&input[used], 1);
179  if (nread <= 0)
180  return 0;
181 
182  used += nread;
183  }
184  while (input[used - 1] != '\n');
185 
186  if (used == allocated)
187  input = x2realloc (input, &allocated);
188 
189  input[used] = '\0';
190 
191  *out = input;
192 
193  printf ("%s", *out);
194  }
195  else
196  {
197  *out = readline ("");
198  if (*out == NULL)
199  return 0;
200  }
201 
202  return 1;
203 }
204 
205 static int
206 greeting (void)
207 {
208  if (args_info.imap_flag)
209  return imap_greeting ();
210  if (args_info.smtp_flag)
211  return smtp_greeting ();
212 
213  return 1;
214 }
215 
216 #ifdef HAVE_LIBGNUTLS
217 static int
218 has_starttls (void)
219 {
220  if (args_info.imap_flag)
221  return imap_has_starttls ();
222  if (args_info.smtp_flag)
223  return smtp_has_starttls ();
224 
225  return 0;
226 }
227 
228 static int
229 starttls (void)
230 {
231  if (args_info.imap_flag)
232  return imap_starttls ();
233  if (args_info.smtp_flag)
234  return smtp_starttls ();
235 
236  return 1;
237 }
238 #endif
239 
240 static int
241 select_mechanism (char **mechlist)
242 {
243  char *in;
244 
245  if (args_info.imap_flag)
246  return imap_select_mechanism (mechlist);
247  if (args_info.smtp_flag)
248  return smtp_select_mechanism (mechlist);
249 
251  *mechlist = args_info.mechanism_arg;
252  else if (args_info.server_flag)
253  {
254  if (!args_info.quiet_given)
255  fprintf (stderr, _("Input list of SASL mechanisms:\n"));
256  if (!readln (&in))
257  return 0;
258  *mechlist = in;
259  }
260  else /* if (args_info.client_flag) */
261  {
262  if (!args_info.quiet_given)
263  fprintf (stderr,
264  _("Input list of SASL mechanisms supported by server:\n"));
265  if (!readln (&in))
266  return 0;
267 
268  *mechlist = in;
269  }
270 
271  return 1;
272 }
273 
274 static int
275 authenticate (const char *mech)
276 {
277  if (args_info.imap_flag)
278  return imap_authenticate (mech);
279  if (args_info.smtp_flag)
280  return smtp_authenticate (mech);
281 
282  if (!args_info.quiet_given)
283  fprintf (stderr, _("Using mechanism:\n"));
284  puts (mech);
285 
286  return 1;
287 }
288 
289 static int
290 step_send (const char *data)
291 {
292  if (args_info.imap_flag)
293  return imap_step_send (data);
294  if (args_info.smtp_flag)
295  return smtp_step_send (data);
296 
297  if (!args_info.quiet_given)
298  {
300  fprintf (stderr, _("Output from server:\n"));
301  else
302  fprintf (stderr, _("Output from client:\n"));
303  }
304  fprintf (stdout, "%s\n", data);
305 
306  return 1;
307 }
308 
309 /* Return 1 on token, 2 on protocol success, 3 on protocol fail, 0 on
310  errors. */
311 static int
312 step_recv (char **data)
313 {
314  if (args_info.imap_flag)
315  return imap_step_recv (data);
316  if (args_info.smtp_flag)
317  return smtp_step_recv (data);
318 
319  if (!readln (data))
320  return 0;
321 
322  return 1;
323 }
324 
325 static int
326 logout (void)
327 {
328  if (args_info.imap_flag)
329  return imap_logout ();
330  if (args_info.smtp_flag)
331  return smtp_logout ();
332 
333  return 1;
334 }
335 
336 const char version_etc_copyright[] =
337  /* Do *not* mark this string for translation. %s is a copyright
338  symbol suitable for this locale, and %d is the copyright
339  year. */
340  "Copyright %s %d Simon Josefsson.";
341 
342 static void
343 usage (int status)
345 
346  static void usage (int status)
347 {
348  if (status != EXIT_SUCCESS)
349  fprintf (stderr, _("Try `%s --help' for more information.\n"),
350  program_name);
351  else
352  {
355  }
356  exit (status);
357 }
358 
359 #define DEFAULT_SALT_SIZE 12
360 
361 static void
362 mkpasswd (void)
363 {
364  char salt_buf[DEFAULT_SALT_SIZE];
365  char *salt;
366  size_t saltlen;
367  char *b64salt;
368  char saltedpassword[GSASL_HASH_MAX_SIZE];
369  char *hexsaltedpassword;
370  size_t hexsaltedpasswordlen;
371  int hash = 0;
372  size_t hashlen = 0;
373  char clientkey[GSASL_HASH_MAX_SIZE];
374  char serverkey[GSASL_HASH_MAX_SIZE];
375  char storedkey[GSASL_HASH_MAX_SIZE];
376  char *b64serverkey, *b64storedkey;
377  size_t b64serverkeylen, b64storedkeylen;
378  int res;
379 
381  error (EXIT_FAILURE, 0, _("required --mechanism missing"));
382 
383  if (strcmp (args_info.mechanism_arg, "SCRAM-SHA-1") == 0)
384  {
385  hash = GSASL_HASH_SHA1;
386  hashlen = GSASL_HASH_SHA1_SIZE;
387  }
388  else if (strcmp (args_info.mechanism_arg, "SCRAM-SHA-256") == 0)
389  {
390  hash = GSASL_HASH_SHA256;
391  hashlen = GSASL_HASH_SHA256_SIZE;
392  }
393  else
394  error (EXIT_FAILURE, 0, _("unsupported --mechanism for --mkpasswd: %s"),
396 
398  error (EXIT_FAILURE, 0, _("iteration count must be positive: %d"),
400 
401  if (args_info.salt_given)
402  {
403  b64salt = args_info.salt_arg;
404 
405  res = gsasl_base64_from (b64salt, strlen (b64salt), &salt, &saltlen);
406  if (res != GSASL_OK)
407  error (EXIT_FAILURE, 0, "%s: %s", gsasl_strerror (res), b64salt);
408  }
409  else
410  {
411  salt = salt_buf;
412  saltlen = sizeof (salt_buf);
413 
414  res = gsasl_nonce (salt, saltlen);
415  if (res != GSASL_OK)
416  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
417 
418  res = gsasl_base64_to (salt, saltlen, &b64salt, NULL);
419  if (res != GSASL_OK)
420  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
421  }
422 
423  if (args_info.password_arg == NULL)
424  args_info.password_arg = readutf8pass (_("Enter password: "));
425 
428  salt, saltlen,
429  saltedpassword,
430  clientkey, serverkey, storedkey);
431  if (res != GSASL_OK)
432  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
433 
434  res = gsasl_hex_to (saltedpassword, hashlen,
435  &hexsaltedpassword, &hexsaltedpasswordlen);
436  if (res != GSASL_OK)
437  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
438 
439  res = gsasl_base64_to (storedkey, hashlen, &b64storedkey, &b64storedkeylen);
440  if (res != GSASL_OK)
441  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
442 
443  res = gsasl_base64_to (serverkey, hashlen, &b64serverkey, &b64serverkeylen);
444  if (res != GSASL_OK)
445  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
446 
447  printf ("{%s}%d,%s,%s,%s", args_info.mechanism_arg,
448  args_info.iteration_count_arg, b64salt, b64storedkey, b64serverkey);
450  printf (",%s", hexsaltedpassword);
451  printf ("\n");
452 
453  if (salt != salt_buf)
454  free (salt);
455  if (b64salt != args_info.salt_arg)
456  free (b64salt);
457  free (b64serverkey);
458  free (b64storedkey);
459  free (hexsaltedpassword);
460 }
461 
462 
463 int
464 main (int argc, char *argv[])
465 {
466  Gsasl *ctx = NULL;
467  int res;
468  char *in;
469  char *connect_hostname = NULL;
470  char *connect_service = NULL;
471 #ifdef HAVE_LIBGNUTLS
472  gnutls_anon_client_credentials_t anoncred;
473  gnutls_certificate_credentials_t x509cred;
474 #endif
475 
476  set_program_name (argv[0]);
477  setlocale (LC_ALL, "");
480 
481  /* This is necessary for modern MinGW compilers that provide working
482  getaddrinfo function, which results in gnulib not detecting that
483  it is broken. The proper fix is for gnulib to wrap the
484  getaddrinfo call and initialize Windows sockets in the
485  wrapper. */
487 
488  if (cmdline_parser (argc, argv, &args_info) != 0)
489  return EXIT_FAILURE;
490 
492  {
493  const char *p = PACKAGE_NAME;
494  if (strcmp (gsasl_check_version (NULL), PACKAGE_VERSION) != 0)
495  p = PACKAGE_STRING;
496  version_etc (stdout, "gsasl", p, gsasl_check_version (NULL),
497  "Simon Josefsson", (char *) NULL);
498  return EXIT_SUCCESS;
499  }
500 
501  if (args_info.help_given)
503 
508  {
509  error (0, 0, _("missing argument"));
511  }
512 
515  error (EXIT_FAILURE, 0,
516  _("need both --x509-cert-file and --x509-key-file"));
517 
519  error (EXIT_FAILURE, 0,
520  _("cannot use both --starttls and --no-starttls"));
521 
523  error (EXIT_FAILURE, 0, _("cannot use both --smtp and --imap"));
524 
529  {
532  return EXIT_SUCCESS;
533  }
534 
536  {
537  if (strrchr (args_info.connect_arg, ':'))
538  {
539  connect_hostname = xstrdup (args_info.connect_arg);
540  *strrchr (connect_hostname, ':') = '\0';
541  connect_service =
542  xstrdup (strrchr (args_info.connect_arg, ':') + 1);
543  }
544  else
545  {
546  connect_hostname = xstrdup (args_info.connect_arg);
547  if (args_info.smtp_flag)
548  connect_service = xstrdup ("smtp");
549  else
550  connect_service = xstrdup ("imap");
551  }
552  }
553  else if (args_info.inputs_num > 0)
554  {
555  connect_hostname = args_info.inputs[0];
556  if (args_info.inputs_num > 1)
557  connect_service = args_info.inputs[1];
558  else if (args_info.smtp_flag)
559  connect_service = xstrdup ("smtp");
560  else
561  connect_service = xstrdup ("imap");
562  }
563 
564  if (connect_service && !args_info.smtp_flag && !args_info.imap_flag)
565  {
566  if (strcmp (connect_service, "25") == 0 ||
567  strcmp (connect_service, "smtp") == 0 ||
568  strcmp (connect_service, "587") == 0 ||
569  strcmp (connect_service, "submission") == 0)
570  args_info.smtp_flag = 1;
571  else if (strcmp (connect_service, "143") == 0 ||
572  strcmp (connect_service, "imap") == 0)
573  args_info.imap_flag = 1;
574  else
575  error (EXIT_FAILURE, 0,
576  _("cannot guess SASL profile (try --smtp or --imap)"));
577  }
578 
580  args_info.service_arg = xstrdup ("imap");
581 
583  args_info.service_arg = xstrdup ("smtp");
584 
587 
588  if (connect_hostname && !args_info.hostname_arg)
589  args_info.hostname_arg = xstrdup (connect_hostname);
590 
591  if (!isatty (STDOUT_FILENO))
592  setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
593 
594  res = gsasl_init (&ctx);
595  if (res != GSASL_OK)
596  error (EXIT_FAILURE, 0, _("initialization failure: %s"),
597  gsasl_strerror (res));
598 
600 
602  {
603  char *mechs;
604 
606  res = gsasl_client_mechlist (ctx, &mechs);
607  else
608  res = gsasl_server_mechlist (ctx, &mechs);
609 
610  if (res != GSASL_OK)
611  error (EXIT_FAILURE, 0, _("error listing mechanisms: %s"),
612  gsasl_strerror (res));
613 
614  if (!args_info.quiet_given)
615  {
617  fprintf (stderr,
618  _("This client supports the following mechanisms:\n"));
619  else
620  fprintf (stderr,
621  _("This server supports the following mechanisms:\n"));
622  }
623 
624  fprintf (stdout, "%s\n", mechs);
625 
626  free (mechs);
627 
628  goto done;
629  }
630 
632  {
633  mkpasswd ();
634  goto done;
635  }
636 
638  {
639  struct addrinfo hints;
640  struct addrinfo *ai0, *ai;
641 
642  memset (&hints, 0, sizeof (hints));
643  hints.ai_flags = AI_CANONNAME;
644  hints.ai_socktype = SOCK_STREAM;
645  res = getaddrinfo (connect_hostname, connect_service, &hints, &ai0);
646  if (res != 0)
647  error (EXIT_FAILURE, 0, "%s: %s", connect_hostname,
648  gai_strerror (res));
649 
650  for (ai = ai0; ai; ai = ai->ai_next)
651  {
652  fprintf (stderr, "Trying %s...\n", quote (ai->ai_canonname ?
653  ai->ai_canonname :
654  connect_hostname));
655 
656  sockfd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
657  if (sockfd < 0)
658  {
659  error (0, errno, "socket");
660  continue;
661  }
662 
663  if (connect (sockfd, ai->ai_addr, ai->ai_addrlen) < 0)
664  {
665  int save_errno = errno;
666  close (sockfd);
667  sockfd = -1;
668  error (0, save_errno, "connect");
669  continue;
670  }
671  break;
672  }
673 
674  if (sockfd < 0)
675  error (EXIT_FAILURE, errno, "socket");
676 
677  freeaddrinfo (ai);
678  }
679 
680  if (!greeting ())
681  return 1;
682 
683 #ifdef HAVE_LIBGNUTLS
685  (args_info.starttls_flag || has_starttls ()))
686  {
687  res = gnutls_global_init ();
688  if (res < 0)
689  error (EXIT_FAILURE, 0, _("GnuTLS global initialization failed: %s"),
690  gnutls_strerror (res));
691 
692  res = gnutls_init (&session, GNUTLS_CLIENT);
693  if (res < 0)
694  error (EXIT_FAILURE, 0, _("GnuTLS initialization failed: %s"),
695  gnutls_strerror (res));
696 
697  res = gnutls_set_default_priority (session);
698  if (res < 0)
699  error (EXIT_FAILURE, 0, _("setting GnuTLS defaults failed: %s"),
700  gnutls_strerror (res));
701 
702  res =
703  gnutls_server_name_set (session, GNUTLS_NAME_DNS, connect_hostname,
704  strlen (connect_hostname));
705  if (res < 0)
706  error (EXIT_FAILURE, 0, _("setting GnuTLS server name failed: %s"),
707  gnutls_strerror (res));
708 
709  res = gnutls_anon_allocate_client_credentials (&anoncred);
710  if (res < 0)
711  error (EXIT_FAILURE, 0,
712  _("allocating anonymous GnuTLS credential: %s"),
713  gnutls_strerror (res));
714 
715  res = gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
716  if (res < 0)
717  error (EXIT_FAILURE, 0, _("setting anonymous GnuTLS credential: %s"),
718  gnutls_strerror (res));
719 
720  res = gnutls_certificate_allocate_credentials (&x509cred);
721  if (res < 0)
722  error (EXIT_FAILURE, 0, _("allocating X.509 GnuTLS credential: %s"),
723  gnutls_strerror (res));
724 
726  res = gnutls_certificate_set_x509_key_file
727  (x509cred, args_info.x509_cert_file_arg,
728  args_info.x509_key_file_arg, GNUTLS_X509_FMT_PEM);
729  if (res != GNUTLS_E_SUCCESS)
730  error (EXIT_FAILURE, 0, _("loading X.509 GnuTLS credential: %s"),
731  gnutls_strerror (res));
732 
734  {
735  res = gnutls_certificate_set_x509_trust_file
736  (x509cred, args_info.x509_ca_file_arg, GNUTLS_X509_FMT_PEM);
737  if (res < 0)
738  error (EXIT_FAILURE, 0, _("no X.509 CAs found: %s"),
739  gnutls_strerror (res));
740  if (res == 0)
741  error (EXIT_FAILURE, 0, _("no X.509 CAs found"));
742  }
743  else if (!args_info.x509_ca_file_arg)
744  {
745  res = gnutls_certificate_set_x509_system_trust (x509cred);
746  if (res < 0)
747  error (EXIT_FAILURE, 0, _("setting GnuTLS system trust: %s"),
748  gnutls_strerror (res));
749  }
750 
751  res = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE,
752  x509cred);
753  if (res < 0)
754  error (EXIT_FAILURE, 0, _("setting X.509 GnuTLS credential: %s"),
755  gnutls_strerror (res));
756 
758  gnutls_session_set_verify_cert (session, connect_hostname, 0);
759 
761  {
762  const char *err_pos;
763 
764  res = gnutls_priority_set_direct (session, args_info.priority_arg,
765  &err_pos);
766  if (res < 0)
767  error (EXIT_FAILURE, 0,
768  _("setting GnuTLS cipher priority (%s): %s\n"),
769  gnutls_strerror (res), err_pos);
770  }
771 
772  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t)
773  (unsigned long) sockfd);
774 
775  if (!starttls ())
776  return 1;
777 
778  do
779  {
780  res = gnutls_handshake (session);
781  }
782  while (res < 0 && gnutls_error_is_fatal (res) == 0);
783 
784  if (!args_info.quiet_given)
785  {
786  int type;
787  unsigned status;
788  gnutls_datum_t out;
789 
790  type = gnutls_certificate_type_get (session);
791  status = gnutls_session_get_verify_cert_status (session);
792  gnutls_certificate_verification_status_print (status, type, &out,
793  0);
794  fprintf (stderr, _("TLS X.509 Verification: %s\n"), out.data);
795  gnutls_free (out.data);
796  }
797 
798  if (res < 0)
799  error (EXIT_FAILURE, 0, _("GnuTLS handshake failed: %s"),
800  gnutls_strerror (res));
801 
803  {
804  char *desc = gnutls_session_get_desc (session);
805  const gnutls_datum_t *cert_list;
806  unsigned int cert_list_size = 0, i;
807  gnutls_x509_crt_t cert;
808  gnutls_datum_t out;
809 
810  fprintf (stderr, _("TLS session info: %s\n"), desc);
811  gnutls_free (desc);
812  fflush (stderr);
813 
814  cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
815 
816  for (i = 0; i < cert_list_size; i++)
817  {
818  res = gnutls_x509_crt_init (&cert);
819  if (res < 0)
820  continue;
821 
822  res = gnutls_x509_crt_import (cert, &cert_list[i],
823  GNUTLS_X509_FMT_DER);
824  if (res < 0)
825  continue;
826 
827  res = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE,
828  &out);
829  if (res == 0)
830  {
831  fprintf (stderr, _("TLS X.509 Certificate %u: %s\n"), i,
832  out.data);
833  gnutls_free (out.data);
834  }
835 
836  gnutls_x509_crt_deinit (cert);
837  }
838  }
839 
841  {
842  unsigned int status;
843 
844  res = gnutls_certificate_verify_peers2 (session, &status);
845  if (res < 0)
846  error (EXIT_FAILURE, 0, _("verifying peer certificate: %s"),
847  gnutls_strerror (res));
848 
849  if (status & GNUTLS_CERT_INVALID)
850  error (EXIT_FAILURE, 0, _("server certificate is not trusted"));
851 
852  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
853  error (EXIT_FAILURE, 0,
854  _("server certificate hasn't got a known issuer"));
855 
856  if (status & GNUTLS_CERT_REVOKED)
857  error (EXIT_FAILURE, 0, _("server certificate has been revoked"));
858 
859  if (status != 0)
860  error (EXIT_FAILURE, 0,
861  _("could not verify server certificate (rc=%u)"), status);
862  }
863 
864 #if HAVE_GNUTLS_SESSION_CHANNEL_BINDING
865  if (!args_info.no_cb_flag)
866  {
867  gnutls_datum_t cb;
868 
869  res = gnutls_session_channel_binding (session,
870  GNUTLS_CB_TLS_UNIQUE, &cb);
871  if (res != GNUTLS_E_SUCCESS)
872  error (EXIT_FAILURE, 0, _("getting channel binding failed: %s"),
873  gnutls_strerror (res));
874 
875  res = gsasl_base64_to ((char *) cb.data, cb.size,
876  &b64cbtlsunique, NULL);
877  if (res != GSASL_OK)
878  error (EXIT_FAILURE, 0, "%s", gsasl_strerror (res));
879  }
880 #endif
881 
882  using_tls = true;
883  }
884 #endif
885 
888  {
889  char *out;
890  char *b64output;
891  size_t output_len;
892  size_t b64output_len;
893  const char *mech;
894  Gsasl_session *xctx = NULL;
895 
896  if (!select_mechanism (&in))
897  return 1;
898 
899  mech = gsasl_client_suggest_mechanism (ctx, in);
900  if (mech == NULL)
901  {
902  fprintf (stderr, _("Cannot find mechanism...\n"));
903  goto done;
904  }
905 
907  mech = args_info.mechanism_arg;
908 
909  if (!authenticate (mech))
910  return 1;
911 
912  /* Authenticate using mechanism */
913 
915  res = gsasl_server_start (ctx, mech, &xctx);
916  else
917  res = gsasl_client_start (ctx, mech, &xctx);
918  if (res != GSASL_OK)
919  error (EXIT_FAILURE, 0, _("mechanism unavailable: %s"),
920  gsasl_strerror (res));
921 
922  in = NULL;
923  out = NULL;
924 
926  {
928  goto no_client_first;
929  }
930 
931  do
932  {
933  int res2;
934 
935  res = gsasl_step64 (xctx, in, &out);
936  if (res != GSASL_NEEDS_MORE && res != GSASL_OK)
937  break;
938 
939  if (!step_send (out))
940  return 1;
941 
942  no_client_first:
943  if (!args_info.quiet_given &&
945  {
947  fprintf (stderr, _("Enter base64 authentication data "
948  "from client (press RET if none):\n"));
949  else
950  fprintf (stderr, _("Enter base64 authentication data "
951  "from server (press RET if none):\n"));
952  }
953 
954  /* Return 1 on token, 2 on protocol success, 3 on protocol fail, 0 on
955  errors. */
956  res2 = step_recv (&in);
957  if (!res2)
958  return 1;
959  if (res2 == 3)
960  error (EXIT_FAILURE, 0, _("server error"));
961  if (res2 == 2)
962  break;
963  }
965  || res == GSASL_NEEDS_MORE);
966 
967  if (res != GSASL_OK)
968  error (EXIT_FAILURE, 0, _("mechanism error: %s"),
969  gsasl_strerror (res));
970 
971  if (!args_info.quiet_given)
972  {
974  fprintf (stderr, _("Server authentication "
975  "finished (client trusted)...\n"));
976  else
977  fprintf (stderr, _("Client authentication "
978  "finished (server trusted)...\n"));
979  fflush (stderr);
980  }
981 
982  /* Transfer application payload */
984  {
985  struct pollfd pfd[2];
986  char *sockbuf = NULL;
987  /* we read chunks of 1000 bytes at a time */
988  size_t sockpos = 0, sockalloc = 0, sockalloc1 = 1000;
989 
990  /* Setup pollfd structs... */
991  pfd[0].fd = STDIN_FILENO;
992  pfd[0].events = POLLIN;
993  if (sockfd)
994  {
995  pfd[1].fd = sockfd;
996  pfd[1].events = POLLIN;
997  }
998 
999  if (!args_info.quiet_given)
1000  {
1001  fprintf (stderr,
1002  _("Enter application data (EOF to finish):\n"));
1003  fflush (stderr);
1004  }
1005 
1006  while (1)
1007  {
1008  int rc;
1009 
1010  pfd[0].revents = 0;
1011  pfd[1].revents = 0;
1012 
1013  rc = poll (pfd, sockfd ? 2 : 1, -1);
1014  if (rc < 0 && errno == EINTR)
1015  continue;
1016 
1017  /* Always check for errors */
1018  if (rc < 0)
1019  error (EXIT_FAILURE, errno, "poll");
1020 
1021  /* We got data to read from stdin.. */
1022  if ((pfd[0].revents & (POLLIN | POLLERR)) == POLLIN)
1023  {
1024  char *line = NULL;
1025  size_t n;
1026  ssize_t len;
1027 
1028  len = getline (&line, &n, stdin);
1029  if (len <= 0)
1030  break;
1031 
1033  {
1034  if (len < 2 || strcmp (&line[len - 2], "\r\n") != 0)
1035  {
1036  line = xrealloc (line, len + 2);
1037  line[len - 1] = '\r';
1038  line[len] = '\n';
1039  line[len + 1] = '\0';
1040  len++;
1041  }
1042  }
1043  else
1044  {
1045  len--;
1046  line[len] = '\0';
1047  }
1048 
1049  res = gsasl_encode (xctx, line, len, &out, &output_len);
1050  if (res != GSASL_OK)
1051  break;
1052 
1053  if (sockfd)
1054  {
1055  len = _send (out, output_len);
1056  if (len != (ssize_t) output_len)
1057  error (EXIT_FAILURE, errno, "write");
1058  }
1059  else if (!(strlen (line) == output_len &&
1060  memcmp (line, out, output_len) == 0))
1061  {
1062  res = gsasl_base64_to (out, output_len,
1063  &b64output, &b64output_len);
1064  if (res != GSASL_OK)
1065  break;
1066 
1067  if (!args_info.quiet_given)
1068  fprintf (stderr, _("Base64 encoded application "
1069  "data to send:\n"));
1070  fprintf (stdout, "%s\n", b64output);
1071 
1072  free (b64output);
1073  }
1074 
1075  free (line);
1076  free (out);
1077  }
1078  /* If there was an error, quit. */
1079  else if (pfd[0].revents & (POLLERR | POLLHUP))
1080  {
1081  error (0, 0, "poll stdin");
1082  break;
1083  }
1084 
1085  /* We got data to read from the socket.. */
1086  if (sockfd && (pfd[1].revents & (POLLIN | POLLERR)) == POLLIN)
1087  {
1088  ssize_t len;
1089 
1090  if (sockalloc == sockpos)
1091  sockbuf = x2realloc (sockbuf, &sockalloc1);
1092  sockalloc = sockalloc1;
1093 
1094  len = _recv (&sockbuf[sockpos], sockalloc - sockpos);
1095  if (len <= 0)
1096  break;
1097 
1098  sockpos += len;
1099 
1100  res = gsasl_decode (xctx, sockbuf, sockpos,
1101  &out, &output_len);
1102  if (res == GSASL_NEEDS_MORE)
1103  {
1104 #define MAX_INPUT_SIZE 0x100000
1105  if (sockpos > MAX_INPUT_SIZE)
1106  error (EXIT_FAILURE, 0,
1107  _("SASL record too large: %zu\n"), sockpos);
1108  continue;
1109  }
1110  if (res != GSASL_OK)
1111  break;
1112 
1113  free (sockbuf);
1114  sockbuf = NULL;
1115  sockpos = 0;
1116  sockalloc = 0;
1117  sockalloc1 = 1000;
1118 
1119  printf ("%.*s", (int) output_len, out);
1120  free (out);
1121  }
1122  /* If there was an error, quit. */
1123  else if (pfd[1].revents & (POLLERR | POLLHUP))
1124  {
1125  error (0, 0, "poll socket");
1126  break;
1127  }
1128  }
1129 
1130  if (res != GSASL_OK)
1131  error (EXIT_FAILURE, 0, _("encoding error: %s"),
1132  gsasl_strerror (res));
1133  }
1134 
1135  if (!args_info.quiet_given)
1136  fprintf (stderr, _("Session finished...\n"));
1137 
1138  if (!logout ())
1139  return 1;
1140 
1141  gsasl_finish (xctx);
1142  }
1143 
1144  if (sockfd)
1145  {
1146 #ifdef HAVE_LIBGNUTLS
1147  if (using_tls)
1148  {
1149  res = gnutls_bye (session, GNUTLS_SHUT_RDWR);
1150  if (res < 0)
1151  error (EXIT_FAILURE, 0,
1152  _("terminating GnuTLS session failed: %s"),
1153  gnutls_strerror (res));
1154 
1155  }
1156 #endif
1157  shutdown (sockfd, SHUT_RDWR);
1158  close (sockfd);
1159  }
1160 
1161 done:
1162  gsasl_done (ctx);
1163 
1164 #ifdef HAVE_LIBGNUTLS
1165  if (using_tls)
1166  {
1167  gnutls_deinit (session);
1168  gnutls_anon_free_client_credentials (anoncred);
1169  gnutls_certificate_free_credentials (x509cred);
1170  gnutls_global_deinit ();
1171  }
1172 #endif
1173 
1174  return EXIT_SUCCESS;
1175 }
_W64 int ssize_t
Definition: ac-stdint.h:18
void gsasl_callback_set(Gsasl *ctx, Gsasl_callback_function cb)
Definition: callback.c:44
char * readutf8pass(const char *prompt)
Definition: callbacks.c:61
int callback(Gsasl *ctx _GL_UNUSED, Gsasl_session *sctx, Gsasl_property prop)
Definition: callbacks.c:69
#define LOCALEDIR
Definition: config.h:8
#define PACKAGE
Definition: config.h:7
int gsasl_nonce(char *data, size_t datalen)
Definition: crypto.c:38
int gsasl_scram_secrets_from_password(Gsasl_hash hash, const char *password, unsigned int iteration_count, const char *salt, size_t saltlen, char *salted_password, char *client_key, char *server_key, char *stored_key)
Definition: crypto.c:155
void gsasl_done(Gsasl *ctx)
Definition: done.c:33
const char * gai_strerror(int code)
Definition: gai_strerror.c:80
void freeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.c:394
int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
Definition: getaddrinfo.c:189
#define _
Definition: arpa_inet.in.h:50
void error(int status, int errnum, const char *message,...)
Definition: error.c:295
#define program_name
Definition: error.c:122
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
Definition: getline.c:24
#define textdomain(Domainname)
Definition: gettext.h:86
#define bindtextdomain(Domainname, Dirname)
Definition: gettext.h:88
int gl_sockets_startup(int version _GL_UNUSED)
Definition: sockets.c:116
#define SOCKETS_1_1
Definition: sockets.h:24
#define NULL
Definition: stddef.in.h:72
#define EXIT_SUCCESS
Definition: stdlib.in.h:123
#define EXIT_FAILURE
Definition: stdlib.in.h:128
#define STDOUT_FILENO
Definition: unistd.in.h:244
#define STDIN_FILENO
Definition: unistd.in.h:241
const char version_etc_copyright[]
Definition: gsasl.c:336
int main(int argc, char *argv[])
Definition: gsasl.c:464
#define DEFAULT_SALT_SIZE
Definition: gsasl.c:359
static void mkpasswd(void)
Definition: gsasl.c:362
char * b64cbtlsunique
Definition: gsasl.c:35
static void usage(int status)
Definition: gsasl.c:346
#define MAX_INPUT_SIZE
static ssize_t _send(void const *src, size_t cnt)
Definition: gsasl.c:113
static int step_send(const char *data)
Definition: gsasl.c:290
static ssize_t _recv(void *dst, size_t cnt)
Definition: gsasl.c:90
#define CRLF
static int logout(void)
Definition: gsasl.c:326
static int select_mechanism(char **mechlist)
Definition: gsasl.c:241
int readln(char **out)
Definition: gsasl.c:162
static int greeting(void)
Definition: gsasl.c:206
int writeln(const char *str)
Definition: gsasl.c:139
int sockfd
Definition: gsasl.c:38
static int authenticate(const char *mech)
Definition: gsasl.c:275
struct gengetopt_args_info args_info
Definition: gsasl.c:37
static int step_recv(char **data)
Definition: gsasl.c:312
void gsasl_finish(Gsasl_session *sctx)
Definition: xfinish.c:33
int gsasl_decode(Gsasl_session *sctx, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: xcode.c:96
const char * gsasl_check_version(const char *req_version)
Definition: version.c:45
@ GSASL_HASH_SHA1
Definition: gsasl.h:473
@ GSASL_HASH_SHA256
Definition: gsasl.h:474
int gsasl_client_start(Gsasl *ctx, const char *mech, Gsasl_session **sctx)
Definition: xstart.c:119
@ GSASL_OK
Definition: gsasl.h:171
@ GSASL_NEEDS_MORE
Definition: gsasl.h:172
int gsasl_server_start(Gsasl *ctx, const char *mech, Gsasl_session **sctx)
Definition: xstart.c:137
const char * gsasl_client_suggest_mechanism(Gsasl *ctx, const char *mechlist)
Definition: suggest.c:38
@ GSASL_HASH_SHA1_SIZE
Definition: gsasl.h:480
@ GSASL_HASH_MAX_SIZE
Definition: gsasl.h:482
@ GSASL_HASH_SHA256_SIZE
Definition: gsasl.h:481
int gsasl_init(Gsasl **ctx)
Definition: init.c:167
int gsasl_encode(Gsasl_session *sctx, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: xcode.c:64
int gsasl_step64(Gsasl_session *sctx, const char *b64input, char **b64output)
Definition: xstep.c:86
int gsasl_client_mechlist(Gsasl *ctx, char **out)
Definition: listmech.c:74
int gsasl_server_mechlist(Gsasl *ctx, char **out)
Definition: listmech.c:93
int cmdline_parser(int argc, char **argv, struct gengetopt_args_info *args_info)
Definition: gsasl_cmd.c:518
void cmdline_parser_print_help(void)
Definition: gsasl_cmd.c:272
int imap_step_send(const char *data)
Definition: imap.c:128
int imap_select_mechanism(char **mechlist)
Definition: imap.c:69
int imap_authenticate(const char *mech)
Definition: imap.c:101
int imap_greeting(void)
Definition: imap.c:24
int imap_starttls(void)
Definition: imap.c:55
int imap_step_recv(char **data)
Definition: imap.c:151
int imap_logout(void)
Definition: imap.c:200
int imap_has_starttls(void)
Definition: imap.c:35
const char * gsasl_strerror(int err)
Definition: error.c:228
int rc
Definition: error.c:42
int res
Definition: mbrtowc-impl.h:45
const char * p
Definition: mbrtowc-impl.h:42
int poll(struct pollfd *pfd, nfds_t nfd, int timeout)
Definition: poll.c:368
#define POLLHUP
Definition: poll.in.h:71
#define POLLIN
Definition: poll.in.h:67
#define POLLERR
Definition: poll.in.h:70
void set_program_name(const char *argv0)
Definition: progname.c:39
char const * quote(char const *arg)
Definition: quotearg.c:1072
char * readline(const char *prompt)
Definition: readline.c:36
int smtp_has_starttls(void)
Definition: smtp.c:35
int smtp_step_send(const char *data)
Definition: smtp.c:135
int smtp_step_recv(char **data)
Definition: smtp.c:158
int smtp_greeting(void)
Definition: smtp.c:24
int smtp_starttls(void)
Definition: smtp.c:58
int smtp_select_mechanism(char **mechlist)
Definition: smtp.c:72
int smtp_authenticate(const char *mech)
Definition: smtp.c:108
int smtp_logout(void)
Definition: smtp.c:198
int gsasl_base64_from(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:74
int gsasl_base64_to(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:44
int gsasl_hex_to(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:106
#define GSASL_ATTR_NO_RETRUN
Definition: internal.h:73
Definition: internal.h:41
Where the command line options are stored.
Definition: gsasl_cmd.h:43
unsigned int service_given
Whether service was given.
Definition: gsasl_cmd.h:152
char * salt_arg
Indicate PBKDF2 salt as base64-encoded string (SCRAM only)..
Definition: gsasl_cmd.h:107
char * priority_arg
Cipher priority string..
Definition: gsasl_cmd.h:125
int client_flag
Act as client. (default=on).
Definition: gsasl_cmd.h:46
unsigned int client_given
Whether client was given.
Definition: gsasl_cmd.h:135
char * connect_arg
Connect to TCP server and negotiate on stream instead of stdin/stdout. PORT is the protocol service,...
Definition: gsasl_cmd.h:56
char * service_arg
Set the requested service name (should be a registered GSSAPI host based service name)....
Definition: gsasl_cmd.h:88
char * password_arg
Password for authentication (insecure for non-testing purposes)..
Definition: gsasl_cmd.h:79
unsigned inputs_num
unamed options number
Definition: gsasl_cmd.h:171
int no_starttls_flag
Unconditionally disable STARTTLS. (default=off).
Definition: gsasl_cmd.h:112
int server_mechanisms_flag
Write name of supported server mechanisms separated by space to stdout. (default=off).
Definition: gsasl_cmd.h:52
int server_flag
Act as server. (default=off).
Definition: gsasl_cmd.h:48
char * hostname_arg
Set the name of the server with the requested service..
Definition: gsasl_cmd.h:91
int imap_flag
Use a IMAP-like logon procedure (client only). Also sets the –service default to 'imap'....
Definition: gsasl_cmd.h:61
int no_client_first_flag
Disallow client to send data first (client only). (default=off).
Definition: gsasl_cmd.h:68
char ** inputs
unamed options (options without names)
Definition: gsasl_cmd.h:170
int application_data_flag
After authentication, read data from stdin and run it through the mechanism's security layer and prin...
Definition: gsasl_cmd.h:59
char * x509_ca_file_arg
File containing one or more X.509 Certificate Authorities certificates in PEM format,...
Definition: gsasl_cmd.h:116
int no_cb_flag
Don't use channel bindings from TLS. (default=off).
Definition: gsasl_cmd.h:114
unsigned int help_given
Whether help was given.
Definition: gsasl_cmd.h:133
int iteration_count_arg
Indicate PBKDF2 hash iteration count (SCRAM only). (default='65536').
Definition: gsasl_cmd.h:104
unsigned int connect_given
Whether connect was given.
Definition: gsasl_cmd.h:140
unsigned int quiet_given
Whether quiet was given.
Definition: gsasl_cmd.h:168
int smtp_flag
Use a SMTP-like logon procedure (client only). Also sets the –service default to 'smtp'....
Definition: gsasl_cmd.h:63
int starttls_flag
Force use of STARTTLS. The default is to use STARTTLS when available. (default=off).
Definition: gsasl_cmd.h:110
char * x509_cert_file_arg
File containing client X.509 certificate in PEM format. Used together with –x509-key-file to specify ...
Definition: gsasl_cmd.h:119
char * mechanism_arg
Mechanism to use..
Definition: gsasl_cmd.h:65
int client_mechanisms_flag
Write name of supported client mechanisms separated by space to stdout. (default=off).
Definition: gsasl_cmd.h:50
unsigned int version_given
Whether version was given.
Definition: gsasl_cmd.h:134
unsigned int salt_given
Whether salt was given.
Definition: gsasl_cmd.h:159
char * x509_key_file_arg
Private key for the client X.509 certificate in PEM format. Used together with –x509-key-file to spec...
Definition: gsasl_cmd.h:122
unsigned int mkpasswd_given
Whether mkpasswd was given.
Definition: gsasl_cmd.h:139
unsigned int verbose_given
Whether verbose was given.
Definition: gsasl_cmd.h:167
unsigned int server_given
Whether server was given.
Definition: gsasl_cmd.h:136
Definition: poll.in.h:81
int fd
Definition: poll.in.h:82
short revents
Definition: poll.in.h:84
short events
Definition: poll.in.h:83
void version_etc(FILE *stream, const char *command_name, const char *package, const char *version,...)
Definition: version-etc.c:230
void emit_bug_reporting_address(void)
Definition: version-etc.c:242
void * xrealloc(void *p, size_t n)
Definition: xmalloc.c:63
char * xstrdup(char const *string)
Definition: xmalloc.c:130
void * x2realloc(void *p, size_t *pn)
Definition: xmalloc.c:85