gsasl-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gsasl branch, master, updated. gsasl-1-7-1-26-g02126f0


From: Simon Josefsson
Subject: [SCM] GNU gsasl branch, master, updated. gsasl-1-7-1-26-g02126f0
Date: Tue, 27 Mar 2012 23:44:50 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gsasl".

http://git.savannah.gnu.org/cgit/gsasl.git/commit/?id=02126f02857777a9f128ce8bfcf8a296e671f8e5

The branch, master has been updated
       via  02126f02857777a9f128ce8bfcf8a296e671f8e5 (commit)
      from  1accb2b1283a2f20ed73f25165312ba1ff02bc9b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 02126f02857777a9f128ce8bfcf8a296e671f8e5
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 00:42:19 2012 +0200

    Add SMTP example server with OpenID 2.0 support.

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                    |    4 +
 configure.ac                                  |    1 +
 examples/Makefile.am                          |    2 +
 examples/{ => openid20}/Makefile.am           |   11 +-
 examples/openid20/README                      |   88 +++++
 examples/openid20/gsasl-openid20-redirect.php |   75 ++++
 examples/openid20/gsasl-openid20-rp.php       |   77 ++++
 examples/openid20/smtp-server-openid20.c      |  500 +++++++++++++++++++++++++
 8 files changed, 752 insertions(+), 6 deletions(-)
 copy examples/{ => openid20}/Makefile.am (74%)
 create mode 100644 examples/openid20/README
 create mode 100755 examples/openid20/gsasl-openid20-redirect.php
 create mode 100755 examples/openid20/gsasl-openid20-rp.php
 create mode 100644 examples/openid20/smtp-server-openid20.c

diff --git a/.gitignore b/.gitignore
index cc8f785..df2d054 100644
--- a/.gitignore
+++ b/.gitignore
@@ -100,6 +100,10 @@ examples/client-serverfirst.o
 examples/client-xmpp-saml20
 examples/client-xmpp-saml20.o
 examples/client.o
+examples/openid20/.deps/
+examples/openid20/.libs/
+examples/openid20/smtp-server-openid20
+examples/openid20/smtp-server-openid20.o
 examples/server-xmpp-saml20
 examples/server-xmpp-saml20.o
 examples/smtp-server
diff --git a/configure.ac b/configure.ac
index 76dc806..212e286 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,6 +141,7 @@ AC_CONFIG_FILES([
   doc/reference/Makefile
   doc/reference/version.xml
   examples/Makefile
+  examples/openid20/Makefile
   gl/Makefile
   gltests/Makefile
   po/Makefile.in
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 8313d63..13473c9 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -16,6 +16,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+SUBDIRS = openid20
+
 AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
 AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I../lib/src
 LDADD = ../lib/src/libgsasl.la
diff --git a/examples/Makefile.am b/examples/openid20/Makefile.am
similarity index 74%
copy from examples/Makefile.am
copy to examples/openid20/Makefile.am
index 8313d63..5d92c65 100644
--- a/examples/Makefile.am
+++ b/examples/openid20/Makefile.am
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
-# Copyright (C) 2002-2012 Simon Josefsson
+# Copyright (C) 2012 Simon Josefsson
 #
 # This file is part of GNU SASL.
 #
@@ -17,10 +17,9 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I../lib/src
-LDADD = ../lib/src/libgsasl.la
+AM_CPPFLAGS = -I$(top_srcdir)/lib/src -I$(top_builddir)/lib/src
+LDADD = $(top_builddir)/lib/src/libgsasl.la
 
-EXTRA_DIST = README
+EXTRA_DIST = README gsasl-openid20-redirect.php gsasl-openid20-rp.php
 
-noinst_PROGRAMS = client client-serverfirst client-mech smtp-server \
-       client-callback client-xmpp-saml20 server-xmpp-saml20
+noinst_PROGRAMS = smtp-server-openid20
diff --git a/examples/openid20/README b/examples/openid20/README
new file mode 100644
index 0000000..292be08
--- /dev/null
+++ b/examples/openid20/README
@@ -0,0 +1,88 @@
+GNU SASL examples/openid20/README -- Explanation of OpenID 2.0 example.
+Copyright (C) 2012 Simon Josefsson
+See the end for copying conditions.
+
+This directory holds a GNU SASL example application that implements a
+SMTP server with OpenID 2.0 authentication support.
+
+There is one simple SMTP server and two helper tools that implement
+the actual OpenID 2.0 protocol part:
+
+  smtp-server-openid20.c:
+
+      The actual SMTP server, based on ../smtp-server.c.
+
+  gsasl-openid20-redirect.php:
+
+      Given a user-supplied identifier it performs discovery and
+      prints a user redirect URL.  Invoked by smtp-server-openid20.c.
+
+  gsasl-openid20-rp.php:
+
+      OpenID 2.0 Relying-Party, receives the return_to URL.  Intended
+      to be invoked via a webserver.
+
+These three tools communicate with each other using a simple
+file-based IPC interface via /tmp/gsasl-openid20-store/.
+
+Here is the normal process:
+
+1) Start smtp-server-openid20, for example when running it on the
+   interop.josefsson.org server the following is used:
+
+     www-data$ ./smtp-server-openid20 2000 /tmp/gsasl-openid20-store 
http://interop.josefsson.org/ http://interop.josefsson.org/gsasl-openid20-rp.php
+
+   For permission reasons, you should run the server under the same
+   user as the webserver runs gsasl-openid20-rp.php.
+
+   The first parameter is the path to the IPC root.  The second
+   parameter is the OpenID "realm".  The third parameter is the
+   "return_to" URL to where the gsasl-openid20-rp.php helper is found.
+
+   For testing, it actually works fine to run the server on
+   "localhost" and be able to complete OpenID 2.0 authentication:
+
+   PATH=$PWD LD_PRELOAD=../../lib/src/.libs/libgsasl.so 
./.libs/smtp-server-openid20 2000 /tmp/gsasl-openid20-store http://localhost/ 
http://localhost/gsasl-openid20-rp.php
+
+2) The smtp-server-openid20 receives incoming connections from
+   clients.  The client sends its user-supplied identifier.  You may
+   use the gsasl command line tool to act as a client.  For example:
+
+   gsasl -a 
https://openidp.feide.no/simplesaml/module.php/openidProvider/user.php/jas4711 
-z user --smtp -m OPENID20 localhost 2000
+
+3) smtp-server-openid20 generate a per-connection NONCE (a 64-byte
+   long hex string) and create the following files:
+
+   /tmp/gsasl-openid20-store/state/NONCE/openid_url: holds the URL above
+   /tmp/gsasl-openid20-store/state/NONCE/realm: holds the realm URL
+   /tmp/gsasl-openid20-store/state/NONCE/return_to: holds the return_to URL
+
+4) smtp-server-openid20 invokes "gsasl-openid20-redirect.php" to get
+   the redirect URL, in the following file:
+
+   /tmp/gsasl-openid20-store/state/NONCE/redirect_url: holds the redirect URL
+
+5) smtp-server-openid20 waits for one of the following files to appear:
+
+   /tmp/gsasl-openid20-store/state/NONCE/fail
+   /tmp/gsasl-openid20-store/state/NONCE/success
+
+6) Meanwhile the user will receive the redirect URL over the SMTP
+   connection and will access the URL in his browser.  Eventually,
+   after IdP approval, the user will be redirected to the "return_to"
+   URL in his browser.
+
+7) The gsasl-openid20-rp.php return_to URL handler verify the OpenID
+   2.0 authentication and writes the following files:
+
+   /tmp/gsasl-openid20-store/state/NONCE/sreg: SREG values provided
+   /tmp/gsasl-openid20-store/state/NONCE/claimed: claimed identity
+
+8) smtp-server-openid20 notice that the stamp file is present and
+   proceeds by reading the files and returning success/fail to the
+   client as appropriate.
+
+----------------------------------------------------------------------
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/examples/openid20/gsasl-openid20-redirect.php 
b/examples/openid20/gsasl-openid20-redirect.php
new file mode 100755
index 0000000..6cbd6ec
--- /dev/null
+++ b/examples/openid20/gsasl-openid20-redirect.php
@@ -0,0 +1,75 @@
+#!/usr/bin/php5
+<?php # -*- mode: php -*-
+
+// gsasl-openid20-redirect.php --- OpenID redirector helper.
+// Copyright (C) 2012  Simon Josefsson
+//
+// This file is part of GNU SASL.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+require_once "Auth/OpenID/Consumer.php";
+require_once "Auth/OpenID/FileStore.php";
+require_once "Auth/OpenID/SReg.php";
+session_start ();
+
+$store_path = $argv[1];
+$nonce = $argv[2];
+$openid_url = file_get_contents ($store_path . "/state/$nonce/openid_url");
+$realm = file_get_contents ($store_path . "/state/$nonce/realm");
+$return_to = file_get_contents ($store_path . "/state/$nonce/return_to");
+
+print "nonce: ". $nonce ."\n";
+print "openid_url: ". $openid_url ."\n";
+print "realm: ". $realm ."\n";
+print "return_to: ". $return_to ."\n";
+
+$store = new Auth_OpenID_FileStore($store_path);
+if (!$store) {
+  print "error: Auth_OpenID_FileStore.\n";
+  exit (1);
+}
+
+$consumer = new Auth_OpenID_Consumer($store);
+if (!$consumer) {
+  print "error: Auth_OpenID_Consumer.\n";
+  exit (1);
+}
+
+$request = $consumer->begin($openid_url);
+if (!$request) {
+  print "error: Auth_OpenID_Consumer->begin.\n";
+  exit (1);
+}
+
+$sreg = Auth_OpenID_SRegRequest::build(array(),
+                               array('nickname', 'fullname', 'email'));
+if (!$sreg) {
+  print "error: Auth_OpenID_SRegRequest::build\n";
+  exit (1);
+}
+
+$request->addExtension($sreg);
+
+$redirect_url = $request->redirectURL($realm, $return_to);
+if (Auth_OpenID::isFailure($redirect_url)) {
+  print ("error: Auth_OpenID_Consumer->redirectURL: " . 
$redirect_url->message);
+  exit (1);
+}
+
+file_put_contents ($store_path . "/state/$nonce/redirect_url", $redirect_url);
+
+print "redirect_url: ". $redirect_url ."\n";
+
+?>
diff --git a/examples/openid20/gsasl-openid20-rp.php 
b/examples/openid20/gsasl-openid20-rp.php
new file mode 100755
index 0000000..36cade3
--- /dev/null
+++ b/examples/openid20/gsasl-openid20-rp.php
@@ -0,0 +1,77 @@
+<?php # -*- mode: php -*-
+
+// gsasl-openid20-rp.php --- OpenID RP for smtp-server-openid20.c.
+// Copyright (C) 2012  Simon Josefsson
+//
+// This file is part of GNU SASL.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+require_once "Auth/OpenID/Consumer.php";
+require_once "Auth/OpenID/FileStore.php";
+require_once "Auth/OpenID/SReg.php";
+session_start ();
+
+$store_path = '/tmp/gsasl-openid20-store';
+$store = new Auth_OpenID_FileStore($store_path);
+$consumer = new Auth_OpenID_Consumer($store);
+
+$matches = array();
+if (preg_match (",^/([A-Za-z0-9]+)$,", $_SERVER['PATH_INFO'], $matches) == 1) {
+  $nonce = $matches[1];
+}
+
+$return_to = file_get_contents ("$store_path/state/$nonce/return_to");
+
+$response = $consumer->complete($return_to);
+
+if ($response->status == Auth_OpenID_CANCEL) {
+
+  file_put_contents ("$store_path/state/$nonce/fail",
+                    "openid.error=cancel");
+
+  print "OpenID authentication cancelled";
+
+} else if ($response->status == Auth_OpenID_FAILURE) {
+
+  file_put_contents ("$store_path/state/$nonce/fail",
+                    "openid.error=failure");
+
+  print "OpenID authentication failed: " . $response->message;
+
+} else if ($response->status == Auth_OpenID_SUCCESS) {
+
+  $claimed = $response->identity_url;
+
+  $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
+  $sreg = $sreg_resp->contents();
+  $outcome = "";
+  if (@$sreg['email']) {
+    $outcome .= "&email=" . urlencode($sreg['email']);
+  }
+  if (@$sreg['nickname']) {
+    $outcome .= "&nickname=" . urlencode($sreg['nickname']);
+  }
+  if (@$sreg['fullname']) {
+    $outcome .= "&fullname=" . urlencode($sreg['fullname']);
+  }
+  $outcome = trim ($outcome, "&");
+
+  file_put_contents ("$store_path/state/$nonce/sreg", $outcome);
+  file_put_contents ("$store_path/state/$nonce/success", $claimed);
+
+  print "Congratulations!  You are authenticated as: " . $claimed;
+}
+
+?>
diff --git a/examples/openid20/smtp-server-openid20.c 
b/examples/openid20/smtp-server-openid20.c
new file mode 100644
index 0000000..c3e56a8
--- /dev/null
+++ b/examples/openid20/smtp-server-openid20.c
@@ -0,0 +1,500 @@
+/* smtp-server-openid20.c --- Example SMTP server with OpenID 2.0 support
+ * Copyright (C) 2012  Simon Josefsson
+ *
+ * This file is part of GNU SASL.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+/* This is based on ../smtp-server.c but adds support for OpenID 2.0.
+   See README for instructions. */
+
+/* This is a minimal SMTP server with GNU SASL authentication support.
+   The only valid password is "sesam".  This server will complete
+   authentications using LOGIN, PLAIN, DIGEST-MD5, CRAM-MD5, and
+   SCRAM-SHA-1.  It accepts an optional command line parameter
+   specifying the service name (i.e., a numerical port number or
+   /etc/services name).  By default it listens on port "2000".  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <signal.h>
+
+#include <gsasl.h>
+
+static char *store_path;
+static char *realm;
+static char *return_to;
+
+static void
+hex_encode (char *dst, const char *src, size_t len)
+{
+  static const char trans[] = "0123456789abcdef";
+
+  while (len--)
+    {
+      *dst++ = trans[(*src >> 4) & 0xf];
+      *dst++ = trans[*src++ & 0xf];
+    }
+
+  *dst = '\0';
+}
+
+static int
+write_file (const char *filename, const char *data)
+{
+  FILE *fh;
+
+  fh = fopen (filename, "w");
+  if (!fh)
+    {
+      perror ("fopen");
+      return -1;
+    }
+
+  if (fputs (data, fh) <= 0)
+    return -1;
+
+  if (fclose (fh) != 0)
+    return -1;
+
+  return 0;
+}
+
+static char *
+get_redirect_url (Gsasl_session * sctx)
+{
+  FILE *fh;
+  char *tmp, *tmp2;
+  char *line = NULL;
+  size_t n = 0;
+  const char *nonce = gsasl_session_hook_get (sctx);
+
+  asprintf (&tmp, "%s", store_path);
+  mkdir (tmp, 0777);
+  free (tmp);
+
+  asprintf (&tmp, "%s/state", store_path);
+  mkdir (tmp, 0777);
+  free (tmp);
+
+  asprintf (&tmp, "%s/state/%s", store_path, nonce);
+  mkdir (tmp, 0777);
+  free (tmp);
+
+  asprintf (&tmp, "%s/state/%s/openid_url", store_path, nonce);
+  if (write_file (tmp, gsasl_property_fast (sctx, GSASL_AUTHID)))
+    return NULL;
+  free (tmp);
+
+  asprintf (&tmp, "%s/state/%s/realm", store_path, nonce);
+  if (write_file (tmp, realm))
+    return NULL;
+  free (tmp);
+
+  asprintf (&tmp, "%s/state/%s/return_to", store_path, nonce);
+  asprintf (&tmp2, "%s/%s", return_to, nonce);
+  if (write_file (tmp, tmp2))
+    return NULL;
+  free (tmp);
+  free (tmp2);
+
+  asprintf (&tmp, "gsasl-openid20-redirect.php %s %s", store_path, nonce);
+  fh = popen (tmp, "r");
+  free (tmp);
+  if (!fh)
+    {
+      perror ("popen");
+      return NULL;
+    }
+  while (getline (&line, &n, fh) >= 0)
+    printf ("gsasl-openid20-redirect.php: %s", line);
+  pclose (fh);
+
+  asprintf (&tmp, "%s/state/%s/redirect_url", store_path, nonce);
+  fh = fopen (tmp, "r");
+  if (!fh)
+    {
+      perror ("fopen");
+      return NULL;
+    }
+  if (getline (&line, &n, fh) <= 0)
+    {
+      perror ("getline");
+      return NULL;
+    }
+  fclose (fh);
+
+  return line;
+}
+
+static int
+callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
+{
+  int rc = GSASL_NO_CALLBACK;
+  FILE *fh;
+  char *line = NULL;
+  size_t n = 0;
+  const char *nonce = gsasl_session_hook_get (sctx);
+  char *tmp;
+
+  switch (prop)
+    {
+    case GSASL_OPENID20_REDIRECT_URL:
+      {
+       line = get_redirect_url (sctx);
+
+       gsasl_property_set (sctx, prop, line);
+       rc = GSASL_OK;
+      }
+      break;
+
+    case GSASL_VALIDATE_OPENID20:
+      {
+       time_t start = time (NULL);
+
+       rc = GSASL_AUTHENTICATION_ERROR;
+       do
+         {
+           sleep (1);
+           
+           asprintf (&tmp, "%s/state/%s/success", store_path, nonce);
+           fh = fopen (tmp, "r");
+           free (tmp);
+           if (!fh)
+             {
+               asprintf (&tmp, "%s/state/%s/fail", store_path, nonce);
+               fh = fopen (tmp, "r");
+               free (tmp);
+               if (!fh)
+                 {
+                   puts ("waiting");
+                   continue;
+                 }
+
+               if (getline (&line, &n, fh) > 0)
+                 printf ("fail: %s\n", line);
+               fclose (fh);
+
+               rc = GSASL_AUTHENTICATION_ERROR;
+               break;
+             }
+
+           if (getline (&line, &n, fh) > 0)
+             printf ("claimed id: %s\n", line);
+           fclose (fh);
+
+           gsasl_property_set (sctx, GSASL_AUTHID, line);
+
+           asprintf (&tmp, "%s/state/%s/sreg", store_path, nonce);
+           fh = fopen (tmp, "r");
+           free (tmp);
+           if (fh)
+             {
+               if (getline (&line, &n, fh) > 0)
+                 {
+                   printf ("sreg: %s\n", line);
+                   gsasl_property_set (sctx, GSASL_OPENID20_OUTCOME_DATA,
+                                       line);
+                 }
+               fclose (fh);
+             }
+
+           rc = GSASL_OK;
+           break;
+         }
+       while (time (NULL) - start < 30);
+      }
+      break;
+
+    case GSASL_PASSWORD:
+      gsasl_property_set (sctx, prop, "sesam");
+      rc = GSASL_OK;
+      break;
+
+    default:
+      /* You may want to log (at debug verbosity level) that an
+         unknown property was requested here, possibly after filtering
+         known rejected property requests. */
+      break;
+    }
+
+  return rc;
+}
+
+static ssize_t
+gettrimline (char **line, size_t * n, FILE * fh)
+{
+  ssize_t s = getline (line, n, fh);
+
+  if (s >= 2)
+    {
+      if ((*line)[strlen (*line) - 1] == '\n')
+       (*line)[strlen (*line) - 1] = '\0';
+      if ((*line)[strlen (*line) - 1] == '\r')
+       (*line)[strlen (*line) - 1] = '\0';
+    }
+
+  printf ("C: %s\n", *line);
+
+  return s;
+}
+
+#define print(fh, ...)                                                 \
+  printf ("S: "), printf (__VA_ARGS__), fprintf (fh, __VA_ARGS__)
+
+static void
+server_auth (FILE * fh, Gsasl_session * session)
+{
+  char *line = NULL;
+  size_t n = 0;
+  char *p;
+  int rc;
+  /* The nonce value MUST be at least 2^32 large and large enough to
+     handle well in excess of the number of concurrent transactions a
+     SASL server shall see. */
+  char bin_nonce[32];
+  char nonce[2*sizeof(bin_nonce) + 1];
+
+  gsasl_nonce (bin_nonce, sizeof (bin_nonce));
+  hex_encode (nonce, bin_nonce, sizeof (bin_nonce));
+  gsasl_session_hook_set (session, nonce);
+
+  /* The ordering and the type of checks in the following loop has to
+     be adapted for each protocol depending on its SASL properties.
+     SMTP is a "server-first" SASL protocol.  This implementation do
+     not support piggy-backing of the initial client challenge nor
+     piggy-backing of the terminating server response.  See RFC 2554
+     and RFC 4422 for terminology.  That profile results in the
+     following loop structure.  Ask on the help-gsasl list if you are
+     uncertain.  */
+  do
+    {
+      rc = gsasl_step64 (session, line, &p);
+      if (rc == GSASL_NEEDS_MORE || (rc == GSASL_OK && p && *p))
+       {
+         print (fh, "334 %s\n", p);
+         gsasl_free (p);
+
+         if (gettrimline (&line, &n, fh) < 0)
+           {
+             print (fh, "221 localhost getline failure\n");
+             goto done;
+           }
+       }
+    }
+  while (rc == GSASL_NEEDS_MORE);
+
+  if (rc != GSASL_OK)
+    {
+      print (fh, "535 gsasl_step64 (%d): %s\n", rc, gsasl_strerror (rc));
+      goto done;
+    }
+
+  {
+    const char *authid = gsasl_property_fast (session, GSASL_AUTHID);
+    const char *authzid = gsasl_property_fast (session, GSASL_AUTHZID);
+    print (fh, "235 OK [authid: %s authzid: %s]\n",
+          authid ? authid : "N/A", authzid ? authzid : "N/A");
+  }
+
+done:
+  free (line);
+}
+
+static void
+smtp (FILE * fh, Gsasl * ctx)
+{
+  char *line = NULL;
+  size_t n = 0;
+  int rc;
+
+  print (fh, "220 localhost ESMTP GNU SASL smtp-server\n");
+
+  while (gettrimline (&line, &n, fh) >= 0)
+    {
+      if (strncmp (line, "EHLO ", 5) == 0 || strncmp (line, "ehlo ", 5) == 0)
+       {
+         char *mechlist;
+
+         rc = gsasl_server_mechlist (ctx, &mechlist);
+         if (rc != GSASL_OK)
+           {
+             print (fh, "221 localhost gsasl_server_mechlist (%d): %s\n",
+                    rc, gsasl_strerror (rc));
+             goto done;
+           }
+
+         print (fh, "250-localhost\n");
+         print (fh, "250 AUTH %s\n", mechlist);
+
+         gsasl_free (mechlist);
+       }
+      else if (strncmp (line, "AUTH ", 5) == 0
+              || strncmp (line, "auth ", 5) == 0)
+       {
+         Gsasl_session *session = NULL;
+
+         if ((rc = gsasl_server_start (ctx, line + 5, &session)) != GSASL_OK)
+           {
+             print (fh, "221 localhost gsasl_server_start (%d): %s\n",
+                    rc, gsasl_strerror (rc));
+             goto done;
+           }
+
+         server_auth (fh, session);
+
+         gsasl_finish (session);
+       }
+      else if (strncmp (line, "QUIT", 4) == 0
+              || strncmp (line, "quit", 4) == 0)
+       {
+         print (fh, "221 localhost QUIT\n");
+         goto done;
+       }
+      else
+       print (fh, "500 unrecognized command\n");
+    }
+
+  print (fh, "221 localhost getline failure\n");
+
+done:
+  free (line);
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char *service = argc > 1 ? argv[1] : "2000";
+  volatile int run = 1;
+  struct addrinfo hints, *addrs;
+  int sockfd;
+  int rc;
+  int yes = 1;
+  Gsasl *ctx;
+
+  if (argc != 5)
+    {
+      printf ("Usage: %s PORT STORE-PATH REALM RETURN-TO\n", argv[0]);
+      exit (EXIT_FAILURE);
+    }
+  store_path = argv[2];
+  realm = argv[3];
+  return_to = argv[4];
+
+  rc = gsasl_init (&ctx);
+  if (rc < 0)
+    {
+      printf ("gsasl_init (%d): %s\n", rc, gsasl_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  printf ("%s [gsasl header %s library %s]\n",
+         argv[0], GSASL_VERSION, gsasl_check_version (NULL));
+
+  gsasl_callback_set (ctx, callback);
+
+  memset (&hints, 0, sizeof (hints));
+  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+  hints.ai_socktype = SOCK_STREAM;
+
+  rc = getaddrinfo (NULL, service, &hints, &addrs);
+  if (rc < 0)
+    {
+      printf ("getaddrinfo: %s\n", gai_strerror (rc));
+      exit (EXIT_FAILURE);
+    }
+
+  sockfd = socket (addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
+  if (sockfd < 0)
+    {
+      perror ("socket");
+      exit (EXIT_FAILURE);
+    }
+
+  if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)) < 0)
+    {
+      perror ("setsockopt");
+      exit (EXIT_FAILURE);
+    }
+
+  rc = bind (sockfd, addrs->ai_addr, addrs->ai_addrlen);
+  if (rc < 0)
+    {
+      perror ("bind");
+      exit (EXIT_FAILURE);
+    }
+
+  freeaddrinfo (addrs);
+
+  rc = listen (sockfd, SOMAXCONN);
+  if (rc < 0)
+    {
+      perror ("listen");
+      exit (EXIT_FAILURE);
+    }
+
+  signal (SIGPIPE, SIG_IGN);
+
+  while (run)
+    {
+      struct sockaddr from;
+      socklen_t fromlen = sizeof (from);
+      char host[NI_MAXHOST];
+      int fd;
+      FILE *fh;
+
+      fd = accept (sockfd, &from, &fromlen);
+      if (fd < 0)
+       {
+         perror ("accept");
+         continue;
+       }
+
+      rc = getnameinfo (&from, fromlen, host, sizeof (host),
+                       NULL, 0, NI_NUMERICHOST);
+      if (rc == 0)
+       printf ("connection from %s\n", host);
+      else
+       printf ("getnameinfo: %s\n", gai_strerror (rc));
+
+      fh = fdopen (fd, "w+");
+      if (!fh)
+       {
+         perror ("fdopen");
+         close (fd);
+         continue;
+       }
+
+      smtp (fh, ctx);
+
+      fclose (fh);
+    }
+
+  close (sockfd);
+  gsasl_done (ctx);
+
+  return 0;
+}


hooks/post-receive
-- 
GNU gsasl



reply via email to

[Prev in Thread] Current Thread [Next in Thread]