Ejemplo n.º 1
0
virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED,
                                                const char *service,
                                                const char *localAddr,
                                                const char *remoteAddr)
{
    virNetSASLSessionPtr sasl = NULL;
    int err;

    if (!(sasl = virObjectLockableNew(virNetSASLSessionClass)))
        return NULL;

    /* Arbitrary size for amount of data we can encode in a single block */
    sasl->maxbufsize = 1 << 16;

    err = sasl_server_new(service,
                          NULL,
                          NULL,
                          localAddr,
                          remoteAddr,
                          NULL,
                          SASL_SUCCESS_DATA,
                          &sasl->conn);
    if (err != SASL_OK) {
        virReportError(VIR_ERR_AUTH_FAILED,
                       _("Failed to create SASL client context: %d (%s)"),
                       err, sasl_errstring(err, NULL, NULL));
        goto cleanup;
    }

    return sasl;

cleanup:
    virObjectUnref(sasl);
    return NULL;
}
Ejemplo n.º 2
0
	virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
		CString const user(Auth->GetUsername());
		CString const pass(Auth->GetPassword());
		CUser* pUser(CZNC::Get().FindUser(user));
		sasl_conn_t *sasl_conn(0);

		if (!pUser) { // @todo Will want to do some sort of && !m_bAllowCreate in the future
			Auth->RefuseLogin("Invalid User - Halting SASL Authentication");
			return HALT;
		}

		CString const key(CString(user + ":" + pass).MD5());
		if (m_Cache.HasItem(key)) {
			Auth->AcceptLogin(*pUser);
			DEBUG("+++ Found in cache");
		}
		else if (sasl_server_new("znc", NULL, NULL, NULL, NULL, cbs, 0, &sasl_conn) == SASL_OK &&
		         sasl_checkpass(sasl_conn, user.c_str(), user.size(), pass.c_str(), pass.size()) == SASL_OK) {
			Auth->AcceptLogin(*pUser);
			m_Cache.AddItem(key);
			DEBUG("+++ Successful SASL password check");
		}
		else {
			Auth->RefuseLogin("SASL Authentication failed");
			DEBUG("--- FAILED SASL password check");
		}

		sasl_dispose(&sasl_conn);
		return HALT;
	}
Ejemplo n.º 3
0
/* conn = cyrussasl.server_new("serice_name", "host FQDN", "user realm",
 *                             "iplocal", "ipremote")
 *
 * conn: an opaque data structure (from Lua's perspective) related to this 
 *       specific authentication attempt.
 * service_name: the name of the service that's being protected by SASL (e.g.
 *               xmpp, smtp, ...)
 * host FQDN: the fully-qualified domain name of the server that users 
 *            are connecting to. May be nil.
 * user realm: the authentication user realm to use for AuthN purposes. 
 *             May be nil.
 * iplocal: Either nil or a string of the form "a.b.c.d;port" (for IPv4). 
 *          Used to tell the SASL library what the local side of the connection
 *          is using.
 * ipremote: Either nil or a string denoting the remote side of the connection.
 *
 * On error, this throws Lua error exceptions. (It is not the typical
 * case that this method might cause an error, except when attempting
 * to set up SASL initially during development.)
 */
static int cyrussasl_sasl_server_new(lua_State *l)
{
  const char *service_name, *fqdn, *realm, *iplocal, *ipremote;
  int numargs = lua_gettop(l);
  int err;
  sasl_conn_t *conn = NULL;
  struct _sasl_ctx **ctxp = NULL;

  if (numargs != 5) {
    lua_pushstring(l, 
		   "usage: "
		   "conn = "
		   "cyrussasl.server_new(service_name, fqdn, realm, "
		   "iplocal, ipremote)");
    lua_error(l);
    return 0;
  }

  service_name = tostring(l, 1);
  fqdn = tostring(l, 2);
  realm = tostring(l, 3);
  iplocal = tostring(l, 4);
  ipremote = tostring(l, 5);

  ctxp = new_context(l);
  if (!ctxp) {
    lua_pushstring(l, "Unable to allocate a new context");
    lua_error(l);
    return 0;
  }

  _init_server_callbacks(*ctxp);

  err = sasl_server_new( service_name,       /* service name (passed in) */
			 fqdn,               /* serverFQDN               */
			 realm,              /* user_realm               */
			 iplocal,            /* iplocalport              */
			 ipremote,           /* ipremoteport             */
			 (*ctxp)->callbacks, /* per-connection callbacks */
			 0,                  /* flags                    */
			 &conn );            /* returned connection ptr  */

  (*ctxp)->conn = conn;

  if ( err != SASL_OK ) {
    lua_pushstring(l, "sasl_server_new failed");
    lua_error(l);
    return 0;
  }

  /* Return 1 item on the stack (a userdata pointer to our state struct).
   * It was already pushed on the stack by new_context(). */

  return 1; /* return # of arguments returned on stack */
}
Ejemplo n.º 4
0
/*
 * per SASL session initialization.
 * We keep session data in Connection layer.
 */
DWORD
VmDirSASLSessionInit(
    PVDIR_SASL_BIND_INFO    pSaslBindInfo
    )
{
    DWORD               dwError = 0;
    sasl_conn_t*        pLocalSaslCtx = NULL;

    // start new sasl context
    dwError = sasl_server_new(  "ldap", // service protocol
                                NULL,   // need realm here?
                                NULL,
                                NULL,
                                NULL,
                                NULL,   // per session CB
                                0,      // default security flag
                                &pLocalSaslCtx);
    BAIL_ON_SASL_ERROR(dwError)


    // default security properties
    dwError = sasl_setprop( pLocalSaslCtx,
                            SASL_SEC_PROPS,
                            &gSASLSecurityProps );
    BAIL_ON_SASL_ERROR(dwError);

    pSaslBindInfo->pSaslCtx   = pLocalSaslCtx;

cleanup:

    return dwError;

sasl_error:

    if (pLocalSaslCtx)
    {
        sasl_dispose(&pLocalSaslCtx);
    }

    memset(pSaslBindInfo, 0, sizeof(*pSaslBindInfo));

    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SASLSessionInit: sasl error (%d)", dwError );

    dwError = _VmDirSASLToLDAPError(dwError);

    goto cleanup;
}
Ejemplo n.º 5
0
virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED,
                                                const char *service,
                                                const char *localAddr,
                                                const char *remoteAddr)
{
    virNetSASLSessionPtr sasl = NULL;
    int err;

    if (VIR_ALLOC(sasl) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    if (virMutexInit(&sasl->lock) < 0) {
        virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to initialized mutex"));
        VIR_FREE(sasl);
        return NULL;
    }

    sasl->refs = 1;
    /* Arbitrary size for amount of data we can encode in a single block */
    sasl->maxbufsize = 1 << 16;

    err = sasl_server_new(service,
                          NULL,
                          NULL,
                          localAddr,
                          remoteAddr,
                          NULL,
                          SASL_SUCCESS_DATA,
                          &sasl->conn);
    if (err != SASL_OK) {
        virNetError(VIR_ERR_AUTH_FAILED,
                    _("Failed to create SASL client context: %d (%s)"),
                    err, sasl_errstring(err, NULL, NULL));
        goto cleanup;
    }

    return sasl;

cleanup:
    virNetSASLSessionFree(sasl);
    return NULL;
}
Ejemplo n.º 6
0
TSaslServer::TSaslServer(const string& service, const string& serverFQDN,
                         const string& userRealm,
                         unsigned flags, sasl_callback_t* callbacks) {
    conn = NULL;
    int result = sasl_server_new(service.c_str(),
                                 serverFQDN.size() == 0 ? NULL : serverFQDN.c_str(),
                                 userRealm.size() == 0 ? NULL :userRealm.c_str(),
                                 NULL, NULL, callbacks, flags, &conn);
    if (result != SASL_OK) {
        if (conn) {
            throw SaslServerImplException(sasl_errdetail(conn));
        } else {
            throw SaslServerImplException(sasl_errstring(result, NULL, NULL));
        }
    }

    authComplete = false;
    serverStarted = false;
}
Ejemplo n.º 7
0
bool pni_init_server(pn_transport_t* transport)
{
  pni_sasl_t *sasl = transport->sasl;
  int result;
  sasl_conn_t *cyrus_conn = NULL;
  do {
    if (sasl->config_dir) {
        result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
        if (result!=SASL_OK) break;
    }

    result = sasl_server_init(NULL, sasl->config_name ? sasl->config_name : "proton-server");
    if (result!=SASL_OK) break;

    result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, &cyrus_conn);
    if (result!=SASL_OK) break;
    sasl->impl_context = cyrus_conn;

    sasl_security_properties_t secprops = {0};
    secprops.security_flags =
      ( sasl->allow_insecure_mechs ? 0 : SASL_SEC_NOPLAINTEXT ) |
      ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ;
    secprops.min_ssf = 0;
    secprops.max_ssf = 2048;
    secprops.maxbufsize = PN_SASL_MAX_BUFFSIZE;

    result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops);
    if (result!=SASL_OK) break;

    sasl_ssf_t ssf = sasl->external_ssf;
    result = sasl_setprop(cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
    if (result!=SASL_OK) break;

    const char *extid = sasl->external_auth;
    if (extid) {
    result = sasl_setprop(cyrus_conn, SASL_AUTH_EXTERNAL, extid);
    }
  } while (false);
  cyrus_conn = (sasl_conn_t*) sasl->impl_context;
  return pni_check_sasl_result(cyrus_conn, result, transport);
}
Ejemplo n.º 8
0
	bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)
	{
		resetState();

		g->appname = name;
		if(!g->server_init) {
			sasl_server_init(NULL, QFile::encodeName(g->appname));
			g->server_init = true;
		}

		callbacks = new sasl_callback_t[2];

		callbacks[0].id = SASL_CB_PROXY_POLICY;
		callbacks[0].proc = (int(*)())scb_checkauth;
		callbacks[0].context = this;

		callbacks[1].id = SASL_CB_LIST_END;
		callbacks[1].proc = 0;
		callbacks[1].context = 0;

		int r = sasl_server_new(service.toLatin1().data(), host.toLatin1().data(), realm.toLatin1().data(), localAddr.isEmpty() ? 0 : localAddr.toLatin1().data(), remoteAddr.isEmpty() ? 0 : remoteAddr.toLatin1().data(), callbacks, 0, &con);
		if(r != SASL_OK) {
			err = saslErrorCond(r);
			return false;
		}

		if(!setsecprops())
			return false;

		const char *ml;
		r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0);
		if(r != SASL_OK)
			return false;
		*mechlist = QString(ml).split(' ', QString::SkipEmptyParts);
		servermode = true;
		step = 0;
		ca_done = false;
		ca_skip = false;
		return true;
	}
Ejemplo n.º 9
0
int main(int argc, char *argv[])
{
    int c;
    char *port = "12345";
    char *service = "rcmd";
    char *hostname = NULL;
    int *l, maxfd=0;
    int r, i;
    sasl_conn_t *conn;
    int cb_flag = 0;

    while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) {
	switch(c) {
	case 'C':
	    cb_flag = 2;        /* channel bindings are critical */
	    break;

	case 'c':
	    cb_flag = 1;        /* channel bindings are present */
	    break;

	case 'h':
	    hostname = optarg;
	    break;

	case 'p':
	    port = optarg;
	    break;

	case 's':
	    service = optarg;
	    break;

	case 'm':
	    mech = optarg;
	    break;

	default:
	    usage();
	    break;
	}
    }

    /* initialize the sasl library */
    r = sasl_server_init(NULL, "sample");
    if (r != SASL_OK) saslfail(r, "initializing libsasl");

    /* get a listening socket */
    if ((l = listensock(port, PF_UNSPEC)) == NULL) {
	saslfail(SASL_FAIL, "allocating listensock");
    }

    for (i = 1; i <= l[0]; i++) {
       if (l[i] > maxfd)
           maxfd = l[i];
    }

    for (;;) {
	char localaddr[NI_MAXHOST | NI_MAXSERV],
	     remoteaddr[NI_MAXHOST | NI_MAXSERV];
	char myhostname[1024+1];
	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
	struct sockaddr_storage local_ip, remote_ip;
	int niflags, error;
	socklen_t salen;
	int nfds, fd = -1;
	FILE *in, *out;
	fd_set readfds;
	sasl_channel_binding_t cb;

	FD_ZERO(&readfds);
	for (i = 1; i <= l[0]; i++)
	    FD_SET(l[i], &readfds);

	nfds = select(maxfd + 1, &readfds, 0, 0, 0);
	if (nfds <= 0) {
	    if (nfds < 0 && errno != EINTR)
		perror("select");
	    continue;
	}

       for (i = 1; i <= l[0]; i++) 
           if (FD_ISSET(l[i], &readfds)) {
               fd = accept(l[i], NULL, NULL);
               break;
           }

	if (fd < 0) {
	    if (errno != EINTR)
		perror("accept");
	    continue;
	}

	printf("accepted new connection\n");

	/* set ip addresses */
	salen = sizeof(local_ip);
	if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
	    perror("getsockname");
	}
	niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
#ifdef NI_WITHSCOPEID
	if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
	    niflags |= NI_WITHSCOPEID;
#endif
	error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf,
			    sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
	if (error != 0) {
	    fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
	    strcpy(hbuf, "unknown");
	    strcpy(pbuf, "unknown");
	}
        snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);

	salen = sizeof(remote_ip);
	if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
	    perror("getpeername");
	}

	niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
#ifdef NI_WITHSCOPEID
	if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
	    niflags |= NI_WITHSCOPEID;
#endif
	error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf,
			    sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
	if (error != 0) {
	    fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
	    strcpy(hbuf, "unknown");
	    strcpy(pbuf, "unknown");
	}
	snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);

	if (hostname == NULL) {
	    r = gethostname(myhostname, sizeof(myhostname)-1);
	    if(r == -1) saslfail(r, "getting hostname");
	    hostname = myhostname;
	}

	r = sasl_server_new(service, hostname, NULL, localaddr, remoteaddr,
			    NULL, 0, &conn);
	if (r != SASL_OK) saslfail(r, "allocating connection state");

	cb.name = "sasl-sample";
	cb.critical = cb_flag > 1;
	cb.data = "this is a test of channel binding";
	cb.len = strlen(cb.data);

	if (cb_flag) {
	    sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
	}

	/* set external properties here
	sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */

	/* set required security properties here
	sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */

	in = fdopen(fd, "r");
	out = fdopen(fd, "w");

	r = mysasl_negotiate(in, out, conn);
	if (r == SASL_OK) {
	    /* send/receive data */


	}

	printf("closing connection\n");
	fclose(in);
	fclose(out);
	close(fd);
	sasl_dispose(&conn);
    }

    sasl_done();
}
Ejemplo n.º 10
0
	virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
		const CString& sUsername = Auth->GetUsername();
		const CString& sPassword = Auth->GetPassword();
		CUser *pUser(CZNC::Get().FindUser(sUsername));
		sasl_conn_t *sasl_conn(NULL);
		bool bSuccess = false;

		if (!pUser && !CreateUser()) {
			return CONTINUE;
		}

		const CString sCacheKey(CString(sUsername + ":" + sPassword).MD5());
		if (m_Cache.HasItem(sCacheKey)) {
			bSuccess = true;
			DEBUG("saslauth: Found [" + sUsername + "] in cache");
		} else if (sasl_server_new("znc", NULL, NULL, NULL, NULL, m_cbs, 0, &sasl_conn) == SASL_OK &&
				sasl_checkpass(sasl_conn, sUsername.c_str(), sUsername.size(), sPassword.c_str(), sPassword.size()) == SASL_OK) {
			m_Cache.AddItem(sCacheKey);

			DEBUG("saslauth: Successful SASL authentication [" + sUsername + "]");

			bSuccess = true;
		}

		sasl_dispose(&sasl_conn);

		if (bSuccess) {
			if (!pUser) {
				CString sErr;
				pUser = new CUser(sUsername);

				if (ShouldCloneUser()) {
					CUser *pBaseUser = CZNC::Get().FindUser(CloneUser());

					if (!pBaseUser) {
						DEBUG("saslauth: Clone User [" << CloneUser() << "] User not found");
						delete pUser;
						pUser = NULL;
					}

					if (pUser && !pUser->Clone(*pBaseUser, sErr)) {
						DEBUG("saslauth: Clone User [" << CloneUser() << "] failed: " << sErr);
						delete pUser;
						pUser = NULL;
					}
				}

				if (pUser) {
					// "::" is an invalid MD5 hash, so user won't be able to login by usual method
					pUser->SetPass("::", CUser::HASH_MD5, "::");
				}

				if (pUser && !CZNC::Get().AddUser(pUser, sErr)) {
					DEBUG("saslauth: Add user [" << sUsername << "] failed: " << sErr);
					delete pUser;
					pUser = NULL;
				}
			}

			if (pUser) {
				Auth->AcceptLogin(*pUser);
				return HALT;
			}
		}

		return CONTINUE;
	}
Ejemplo n.º 11
0
svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                server_baton_t *b,
                                enum access_type required,
                                svn_boolean_t needs_username)
{
  sasl_conn_t *sasl_ctx;
  apr_pool_t *subpool;
  apr_status_t apr_err;
  const char *localaddrport = NULL, *remoteaddrport = NULL;
  const char *mechlist, *val;
  char hostname[APRMAXHOSTLEN + 1];
  sasl_security_properties_t secprops;
  svn_boolean_t success, no_anonymous;
  int mech_count, result = SASL_OK;

  SVN_ERR(svn_ra_svn__get_addresses(&localaddrport, &remoteaddrport,
                                        conn, pool));
  apr_err = apr_gethostname(hostname, sizeof(hostname), pool);
  if (apr_err)
    {
      svn_error_t *err = svn_error_wrap_apr(apr_err, _("Can't get hostname"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn_flush(conn, pool);
    }

  /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol
     supports sending data along with the final "success" message. */
  result = sasl_server_new(SVN_RA_SVN_SASL_NAME,
                           hostname, b->realm,
                           localaddrport, remoteaddrport,
                           NULL, SASL_SUCCESS_DATA,
                           &sasl_ctx);
  if (result != SASL_OK)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          sasl_errstring(result, NULL, NULL));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn_flush(conn, pool);
    }

  /* Make sure the context is always destroyed. */
  apr_pool_cleanup_register(b->pool, sasl_ctx, sasl_dispose_cb,
                            apr_pool_cleanup_null);

  /* Initialize security properties. */
  svn_ra_svn__default_secprops(&secprops);

  /* Don't allow ANONYMOUS if a username is required. */
  no_anonymous = needs_username || get_access(b, UNAUTHENTICATED) < required;
  if (no_anonymous)
    secprops.security_flags |= SASL_SEC_NOANONYMOUS;

  svn_config_get(b->cfg, &val,
                 SVN_CONFIG_SECTION_SASL,
                 SVN_CONFIG_OPTION_MIN_SSF,
                 "0");
  SVN_ERR(svn_cstring_atoui(&secprops.min_ssf, val));

  svn_config_get(b->cfg, &val,
                 SVN_CONFIG_SECTION_SASL,
                 SVN_CONFIG_OPTION_MAX_SSF,
                 "256");
  SVN_ERR(svn_cstring_atoui(&secprops.max_ssf, val));

  /* Set security properties. */
  result = sasl_setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* SASL needs to know if we are externally authenticated. */
  if (b->tunnel_user)
    result = sasl_setprop(sasl_ctx, SASL_AUTH_EXTERNAL, b->tunnel_user);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* Get the list of mechanisms. */
  result = sasl_listmech(sasl_ctx, NULL, NULL, " ", NULL,
                         &mechlist, NULL, &mech_count);

  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  if (mech_count == 0)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          _("Could not obtain the list"
                                          " of SASL mechanisms"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn_flush(conn, pool);
    }

  /* Send the list of mechanisms and the realm to the client. */
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "(w)c",
                                        mechlist, b->realm));

  /* The main authentication loop. */
  subpool = svn_pool_create(pool);
  do
    {
      svn_pool_clear(subpool);
      SVN_ERR(try_auth(conn, sasl_ctx, subpool, b, &success));
    }
  while (!success);
  svn_pool_destroy(subpool);

  SVN_ERR(svn_ra_svn__enable_sasl_encryption(conn, sasl_ctx, pool));

  if (no_anonymous)
    {
      char *p;
      const void *user;

      /* Get the authenticated username. */
      result = sasl_getprop(sasl_ctx, SASL_USERNAME, &user);

      if (result != SASL_OK)
        return fail_cmd(conn, pool, sasl_ctx);

      if ((p = strchr(user, '@')) != NULL)
        {
          /* Drop the realm part. */
          b->user = apr_pstrndup(b->pool, user, p - (const char *)user);
        }
      else
        {
          svn_error_t *err;
          err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                 _("Couldn't obtain the authenticated"
                                 " username"));
          SVN_ERR(write_failure(conn, pool, &err));
          return svn_ra_svn_flush(conn, pool);
        }
    }

  return SVN_NO_ERROR;
}
Ejemplo n.º 12
0
bool reds_sasl_start_auth(RedsStream *stream, AsyncReadDone read_cb, void *opaque)
{
    const char *mechlist = NULL;
    sasl_security_properties_t secprops;
    int err;
    char *localAddr, *remoteAddr;
    int mechlistlen;
    RedsSASL *sasl = &stream->priv->sasl;

    if (!(localAddr = reds_stream_get_local_address(stream))) {
        goto error;
    }

    if (!(remoteAddr = reds_stream_get_remote_address(stream))) {
        free(localAddr);
        goto error;
    }

    err = sasl_server_new("spice",
                          NULL, /* FQDN - just delegates to gethostname */
                          NULL, /* User realm */
                          localAddr,
                          remoteAddr,
                          NULL, /* Callbacks, not needed */
                          SASL_SUCCESS_DATA,
                          &sasl->conn);
    free(localAddr);
    free(remoteAddr);
    localAddr = remoteAddr = NULL;

    if (err != SASL_OK) {
        spice_warning("sasl context setup failed %d (%s)",
                    err, sasl_errstring(err, NULL, NULL));
        sasl->conn = NULL;
        goto error;
    }

    /* Inform SASL that we've got an external SSF layer from TLS */
    if (stream->priv->ssl) {
        sasl_ssf_t ssf;

        ssf = SSL_get_cipher_bits(stream->priv->ssl, NULL);
        err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf);
        if (err != SASL_OK) {
            spice_warning("cannot set SASL external SSF %d (%s)",
                        err, sasl_errstring(err, NULL, NULL));
            goto error_dispose;
        }
    } else {
        sasl->wantSSF = 1;
    }

    memset(&secprops, 0, sizeof secprops);
    /* Inform SASL that we've got an external SSF layer from TLS */
    if (stream->priv->ssl) {
        /* If we've got TLS (or UNIX domain sock), we don't care about SSF */
        secprops.min_ssf = 0;
        secprops.max_ssf = 0;
        secprops.maxbufsize = 8192;
        secprops.security_flags = 0;
    } else {
        /* Plain TCP, better get an SSF layer */
        secprops.min_ssf = 56; /* Good enough to require kerberos */
        secprops.max_ssf = 100000; /* Arbitrary big number */
        secprops.maxbufsize = 8192;
        /* Forbid any anonymous or trivially crackable auth */
        secprops.security_flags =
            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
    }

    err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops);
    if (err != SASL_OK) {
        spice_warning("cannot set SASL security props %d (%s)",
                      err, sasl_errstring(err, NULL, NULL));
        goto error_dispose;
    }

    err = sasl_listmech(sasl->conn,
                        NULL, /* Don't need to set user */
                        "", /* Prefix */
                        ",", /* Separator */
                        "", /* Suffix */
                        &mechlist,
                        NULL,
                        NULL);
    if (err != SASL_OK || mechlist == NULL) {
        spice_warning("cannot list SASL mechanisms %d (%s)",
                      err, sasl_errdetail(sasl->conn));
        goto error_dispose;
    }

    spice_debug("Available mechanisms for client: '%s'", mechlist);

    sasl->mechlist = spice_strdup(mechlist);

    mechlistlen = strlen(mechlist);
    if (!reds_stream_write_all(stream, &mechlistlen, sizeof(uint32_t))
        || !reds_stream_write_all(stream, sasl->mechlist, mechlistlen)) {
        spice_warning("SASL mechanisms write error");
        goto error;
    }

    spice_debug("Wait for client mechname length");
    reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t),
                           read_cb, opaque);

    return true;

error_dispose:
    sasl_dispose(&sasl->conn);
    sasl->conn = NULL;
error:
    return false;
}
int
main(int argc, char **argv)
{
	const char *user, *realm, *passwd, *service, *mechs, **globals, *err;
	int c, ret;
	sasl_callback_t callbacks[] = {
		{SASL_CB_GETOPT, my_getopt, NULL},
		{SASL_CB_LIST_END},
	};
	sasl_conn_t *connection;
	char hostname[512];
	char fulluser[512]; /* XXX: may overflow */

	user = realm = passwd = service = "";
	strcpy(hostname, "localhost");
	gethostname(hostname, sizeof(hostname));

	while ((c = getopt(argc, argv, "u:r:p:s:h:12v")) != -1) {
		switch (c) {
		case 'u':
			user = optarg;
			break;
		case 'r':
			realm = optarg;
			break;
		case 'p':
			passwd = optarg;
			break;
		case 's':
			service = optarg;
			break;
		case 'h':
			strncpy(hostname, optarg, sizeof(hostname) - 1);
			hostname[sizeof(hostname) - 1] = '\0';
			break;
		case '1':
			main_requested_sasl_version = 1;
			break;
		case '2':
			main_requested_sasl_version = 2;
			break;
		case 'v':
			main_verbose++;
			break;
		default:
			printf("Usage: %s [-v] [-1] [-2] "
			       "[-h hostname] "
			       "[-u user] "
			       "[-r realm] "
			       "[-p password] "
			       "[-s service] "
			       "\n", argv[0]);
			return 2;
			break;
		}
	}
	if ((strlen(user) == 0) || (strlen(passwd) == 0)) {
		printf("Usage: %s [-v] [-1] [-2] "
		       "[-h hostname] "
		       "[-u user] "
		       "[-r realm] "
		       "[-p password] "
		       "[-s service] "
		       "\n", argv[0]);
		return 2;
	}
	if (realm && (strlen(realm) > 0)) {
		sprintf(fulluser, "%s@%s", user, realm);
	} else {
		sprintf(fulluser, "%s", user);
	}

	ret = sasl_server_init(callbacks,
			       strlen(service) ? service : "sasl-checkpass");
	if (ret != SASL_OK) {
		fprintf(stderr, "Error in sasl_server_init(): %s\n",
			sasl_errstring(ret, NULL, NULL));
	}

	connection = NULL;
	ret = sasl_server_new(strlen(service) ? service : "sasl-checkpass",
			      hostname,
			      NULL,
#ifdef SASL2
			      NULL,
			      NULL,
#endif
			      callbacks,
			      0,
			      &connection);
	if (ret != SASL_OK) {
		fprintf(stderr, "Error in sasl_server_new(): %s\n",
			sasl_errstring(ret, NULL, NULL));
	}

	err = NULL;
	ret = sasl_checkpass(connection,
			     fulluser, strlen(fulluser),
			     passwd, strlen(passwd)
#ifndef SASL2
			     , &err
#endif
			     );
	switch (ret) {
	case SASL_OK:
		printf("OK\n");
		break;
	default:
		printf("NO: %d", ret);
		switch (ret) {
		case SASL_FAIL:
			err = "generic failure";
			break;
		case SASL_BADAUTH:
			err = "authentication failure";
			break;
		default:
			err = NULL;
			break;
		}
		if (err) {
			printf(" (%s)", err);
		}
		printf("\n");
		break;
	}
	return ret;
}
Ejemplo n.º 14
0
int
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
uschar *output, *out2, *input, *clear, *hname;
uschar *debug = NULL;   /* Stops compiler complaining */
sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
sasl_conn_t *conn;
int rc, firsttime=1, clen;
unsigned int inlen, outlen;

input=data;
inlen=Ustrlen(data);

HDEBUG(D_auth) debug=string_copy(data);

hname=expand_string(ob->server_hostname);
if(hname == NULL)
  {
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

if(inlen)
  {
  clen=auth_b64decode(input, &clear);
  if(clen < 0)
    {
    return BAD64;
    }
  input=clear;
  inlen=clen;
  }

rc=sasl_server_init(cbs, "exim");
if (rc != SASL_OK)
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
  return DEFER;
  }

rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL,
  NULL, NULL, 0, &conn);

if( rc != SASL_OK )
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
  sasl_done();
  return DEFER;
  }

rc=SASL_CONTINUE;

while(rc==SASL_CONTINUE)
  {
  if(firsttime)
    {
    firsttime=0;
    HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
    rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
           (const char **)(&output), &outlen);
    }
  else
    {
    /* make sure that we have a null-terminated string */
    out2=store_get(outlen+1);
    memcpy(out2,output,outlen);
    out2[outlen]='\0';
    if((rc=auth_get_data(&input, out2, outlen))!=OK)
      {
      /* we couldn't get the data, so free up the library before
       * returning whatever error we get */
      sasl_dispose(&conn);
      sasl_done();
      return rc;
      }
    inlen=Ustrlen(input);

    HDEBUG(D_auth) debug=string_copy(input);
    if(inlen)
      {
      clen=auth_b64decode(input, &clear);
      if(clen < 0)
       {
        sasl_dispose(&conn);
        sasl_done();
       return BAD64;
       }
      input=clear;
      inlen=clen;
      }

    HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
    rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
    }
  if(rc==SASL_BADPROT)
    {
    sasl_dispose(&conn);
    sasl_done();
    return UNEXPECTED;
    }
  else if( rc==SASL_FAIL     || rc==SASL_BUFOVER
       || rc==SASL_BADMAC   || rc==SASL_BADAUTH
       || rc==SASL_NOAUTHZ  || rc==SASL_ENCRYPT
       || rc==SASL_EXPIRED  || rc==SASL_DISABLED
       || rc==SASL_NOUSER   )
    {
    /* these are considered permanent failure codes */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
       "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
       sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return FAIL;
    }
  else if(rc==SASL_NOMECH)
    {
    /* this is a temporary failure, because the mechanism is not
     * available for this user. If it wasn't available at all, we
     * shouldn't have got here in the first place...
     */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg =
        string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
    sasl_dispose(&conn);
    sasl_done();
    return DEFER;
    }
  else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
    {
    /* Anything else is a temporary failure, and we'll let SASL print out
     * the error string for us
     */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg =
        string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return DEFER;
    }
  else if(rc==SASL_OK)
    {
    /* Get the username and copy it into $auth1 and $1. The former is now the
    preferred variable; the latter is the original variable. */
    rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
    auth_vars[0] = expand_nstring[1] = string_copy(out2);
    expand_nlength[1] = Ustrlen(expand_nstring[1]);
    expand_nmax = 1;

    HDEBUG(D_auth)
      debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, out2);
    /* close down the connection, freeing up library's memory */
    sasl_dispose(&conn);
    sasl_done();

    /* Expand server_condition as an authorization check */
    return auth_check_serv_cond(ablock);
    }
  }
/* NOTREACHED */
return 0;  /* Stop compiler complaints */
}
Ejemplo n.º 15
0
void start_auth_sasl(VncState *vs)
{
    const char *mechlist = NULL;
    sasl_security_properties_t secprops;
    int err;
    char *localAddr, *remoteAddr;
    int mechlistlen;

    VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc);

    /* Get local & remote client addresses in form  IPADDR;PORT */
    localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL);
    if (!localAddr) {
        goto authabort;
    }

    remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL);
    if (!remoteAddr) {
        g_free(localAddr);
        goto authabort;
    }

    err = sasl_server_new("vnc",
                          NULL, /* FQDN - just delegates to gethostname */
                          NULL, /* User realm */
                          localAddr,
                          remoteAddr,
                          NULL, /* Callbacks, not needed */
                          SASL_SUCCESS_DATA,
                          &vs->sasl.conn);
    g_free(localAddr);
    g_free(remoteAddr);
    localAddr = remoteAddr = NULL;

    if (err != SASL_OK) {
        VNC_DEBUG("sasl context setup failed %d (%s)",
                  err, sasl_errstring(err, NULL, NULL));
        vs->sasl.conn = NULL;
        goto authabort;
    }

    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
    if (vs->auth == VNC_AUTH_VENCRYPT &&
        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
        Error *local_err = NULL;
        int keysize;
        sasl_ssf_t ssf;

        keysize = qcrypto_tls_session_get_key_size(vs->tls,
                                                   &local_err);
        if (keysize < 0) {
            VNC_DEBUG("cannot TLS get cipher size: %s\n",
                      error_get_pretty(local_err));
            error_free(local_err);
            sasl_dispose(&vs->sasl.conn);
            vs->sasl.conn = NULL;
            goto authabort;
        }
        ssf = keysize * CHAR_BIT; /* tls key size is bytes, sasl wants bits */

        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
        if (err != SASL_OK) {
            VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
                      err, sasl_errstring(err, NULL, NULL));
            sasl_dispose(&vs->sasl.conn);
            vs->sasl.conn = NULL;
            goto authabort;
        }
    } else {
        vs->sasl.wantSSF = 1;
    }

    memset (&secprops, 0, sizeof secprops);
    /* Inform SASL that we've got an external SSF layer from TLS.
     *
     * Disable SSF, if using TLS+x509+SASL only. TLS without x509
     * is not sufficiently strong
     */
    if (vs->vd->is_unix ||
        (vs->auth == VNC_AUTH_VENCRYPT &&
         vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) {
        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
        secprops.min_ssf = 0;
        secprops.max_ssf = 0;
        secprops.maxbufsize = 8192;
        secprops.security_flags = 0;
    } else {
        /* Plain TCP, better get an SSF layer */
        secprops.min_ssf = 56; /* Good enough to require kerberos */
        secprops.max_ssf = 100000; /* Arbitrary big number */
        secprops.maxbufsize = 8192;
        /* Forbid any anonymous or trivially crackable auth */
        secprops.security_flags =
            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
    }

    err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
    if (err != SASL_OK) {
        VNC_DEBUG("cannot set SASL security props %d (%s)\n",
                  err, sasl_errstring(err, NULL, NULL));
        sasl_dispose(&vs->sasl.conn);
        vs->sasl.conn = NULL;
        goto authabort;
    }

    err = sasl_listmech(vs->sasl.conn,
                        NULL, /* Don't need to set user */
                        "", /* Prefix */
                        ",", /* Separator */
                        "", /* Suffix */
                        &mechlist,
                        NULL,
                        NULL);
    if (err != SASL_OK) {
        VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
                  err, sasl_errdetail(vs->sasl.conn));
        sasl_dispose(&vs->sasl.conn);
        vs->sasl.conn = NULL;
        goto authabort;
    }
    VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);

    vs->sasl.mechlist = g_strdup(mechlist);
    mechlistlen = strlen(mechlist);
    vnc_write_u32(vs, mechlistlen);
    vnc_write(vs, mechlist, mechlistlen);
    vnc_flush(vs);

    VNC_DEBUG("Wait for client mechname length\n");
    vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);

    return;

 authabort:
    vnc_client_error(vs);
}
Ejemplo n.º 16
0
void
auth_cyrus_sasl_init(auth_instance *ablock)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
const uschar *list, *listptr, *buffer;
int rc, i;
unsigned int len;
uschar *rs_point, *expanded_hostname;
char *realm_expanded;

sasl_conn_t *conn;
sasl_callback_t cbs[] = {
  {SASL_CB_GETOPT, NULL, NULL },
  {SASL_CB_LIST_END, NULL, NULL}};

/* default the mechanism to our "public name" */
if (ob->server_mech == NULL)
  ob->server_mech = string_copy(ablock->public_name);

expanded_hostname = expand_string(ob->server_hostname);
if (expanded_hostname == NULL)
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't expand server_hostname [%s]: %s",
      ablock->name, ob->server_hostname, expand_string_message);

realm_expanded = NULL;
if (ob->server_realm != NULL) {
  realm_expanded = CS expand_string(ob->server_realm);
  if (realm_expanded == NULL)
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
        "couldn't expand server_realm [%s]: %s",
        ablock->name, ob->server_realm, expand_string_message);
}

/* we're going to initialise the library to check that there is an
 * authenticator of type whatever mechanism we're using
 */

cbs[0].proc = (int(*)(void)) &mysasl_config;
cbs[0].context = ob->server_mech;

if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't initialise Cyrus SASL library.", ablock->name);

if ((rc = sasl_server_new(CS ob->server_service, CS expanded_hostname,
                   realm_expanded, NULL, NULL, NULL, 0, &conn)) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't initialise Cyrus SASL server connection.", ablock->name);

if ((rc = sasl_listmech(conn, NULL, "", ":", "", (const char **)&list, &len, &i)) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't get Cyrus SASL mechanism list.", ablock->name);

i = ':';
listptr = list;

HDEBUG(D_auth)
  {
  debug_printf("Initialised Cyrus SASL service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n",
      ob->server_service, expanded_hostname, realm_expanded);
  debug_printf("Cyrus SASL knows mechanisms: %s\n", list);
  }

/* the store_get / store_reset mechanism is hierarchical
 * the hierarchy is stored for us behind our back. This point
 * creates a hierarchy point for this function.
 */
rs_point = store_get(0);

/* loop until either we get to the end of the list, or we match the
 * public name of this authenticator
 */
while ( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) &&
       strcmpic(buffer,ob->server_mech) );

if (!buffer)
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "Cyrus SASL doesn't know about mechanism %s.", ablock->name, ob->server_mech);

store_reset(rs_point);

HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name);

/* make sure that if we get here then we're allowed to advertise. */
ablock->server = TRUE;

sasl_dispose(&conn);
sasl_done();
}
Ejemplo n.º 17
0
int
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
uschar *output, *out2, *input, *clear, *hname;
uschar *debug = NULL;   /* Stops compiler complaining */
sasl_callback_t cbs[] = {{SASL_CB_LIST_END, NULL, NULL}};
sasl_conn_t *conn;
char * realm_expanded = NULL;
int rc, firsttime = 1, clen, *negotiated_ssf_ptr = NULL, negotiated_ssf;
unsigned int inlen, outlen;

input = data;
inlen = Ustrlen(data);

HDEBUG(D_auth) debug = string_copy(data);

hname = expand_string(ob->server_hostname);
if (hname && ob->server_realm)
  realm_expanded = CS expand_string(ob->server_realm);
if (!hname  ||  !realm_expanded  && ob->server_realm)
  {
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

if (inlen)
  {
  if ((clen = b64decode(input, &clear)) < 0)
    return BAD64;
  input = clear;
  inlen = clen;
  }

if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK)
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
  return DEFER;
  }

rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL,
  NULL, NULL, 0, &conn);

HDEBUG(D_auth)
  debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n",
      ob->server_service, hname, realm_expanded);

if (rc != SASL_OK )
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
  sasl_done();
  return DEFER;
  }

if (tls_in.cipher)
  {
  if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK)
    {
    HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n",
        tls_in.bits, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF";
    sasl_done();
    return DEFER;
    }
  else
    HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits);
  }
else
  HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n");

/* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly
annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed
with their iptostring() function, which just wraps
getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the
inet_ntop which we wrap in our host_ntoa() function.

So the docs are too strict and we shouldn't worry about :: contractions. */

/* Set properties for remote and local host-ip;port */
for (int i = 0; i < 2; ++i)
  {
  struct sockaddr_storage ss;
  int (*query)(int, struct sockaddr *, socklen_t *);
  int propnum, port;
  const uschar *label;
  uschar *address, *address_port;
  const char *s_err;
  socklen_t sslen;

  if (i)
    {
    query = &getpeername;
    propnum = SASL_IPREMOTEPORT;
    label = CUS"peer";
    }
  else
    {
    query = &getsockname;
    propnum = SASL_IPLOCALPORT;
    label = CUS"local";
    }

  sslen = sizeof(ss);
  if ((rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen)) < 0)
    {
    HDEBUG(D_auth)
      debug_printf("Failed to get %s address information: %s\n",
          label, strerror(errno));
    break;
    }

  address = host_ntoa(-1, &ss, NULL, &port);
  address_port = string_sprintf("%s;%d", address, port);

  if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK)
    {
    s_err = sasl_errdetail(conn);
    HDEBUG(D_auth)
      debug_printf("Failed to set %s SASL property: [%d] %s\n",
          label, rc, s_err ? s_err : "<unknown reason>");
    break;
    }
  HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n",
      label, address_port);
  }

for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; )
  {
  if (firsttime)
    {
    firsttime = 0;
    HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
    rc = sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
           (const char **)(&output), &outlen);
    }
  else
    {
    /* make sure that we have a null-terminated string */
    out2 = string_copyn(output, outlen);

    if ((rc = auth_get_data(&input, out2, outlen)) != OK)
      {
      /* we couldn't get the data, so free up the library before
       * returning whatever error we get */
      sasl_dispose(&conn);
      sasl_done();
      return rc;
      }
    inlen = Ustrlen(input);

    HDEBUG(D_auth) debug = string_copy(input);
    if (inlen)
      {
      if ((clen = b64decode(input, &clear)) < 0)
       {
       sasl_dispose(&conn);
       sasl_done();
       return BAD64;
       }
      input = clear;
      inlen = clen;
      }

    HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
    rc = sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
    }

  if (rc == SASL_BADPROT)
    {
    sasl_dispose(&conn);
    sasl_done();
    return UNEXPECTED;
    }
  if (rc == SASL_CONTINUE)
    continue;

  /* Get the username and copy it into $auth1 and $1. The former is now the
  preferred variable; the latter is the original variable. */

  if ((sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2))) != SASL_OK)
    {
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL library will not tell us the username: %s\n",
	  sasl_errstring(rc, NULL, NULL));
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
       "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech,
       sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return FAIL;
    }
  auth_vars[0] = expand_nstring[1] = string_copy(out2);
  expand_nlength[1] = Ustrlen(out2);
  expand_nmax = 1;

  switch (rc)
    {
    case SASL_FAIL: case SASL_BUFOVER: case SASL_BADMAC: case SASL_BADAUTH:
    case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED:
    case SASL_DISABLED: case SASL_NOUSER:
      /* these are considered permanent failure codes */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
	 sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return FAIL;

    case SASL_NOMECH:
      /* this is a temporary failure, because the mechanism is not
       * available for this user. If it wasn't available at all, we
       * shouldn't have got here in the first place...
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;

    case SASL_OK:
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s authentication succeeded for %s\n",
	    ob->server_mech, auth_vars[0]);

      if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK)
	{
	HDEBUG(D_auth)
	  debug_printf("Cyrus SASL library will not tell us the SSF: %s\n",
	      sasl_errstring(rc, NULL, NULL));
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech,
	    sasl_errstring(rc, NULL, NULL));
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}
      negotiated_ssf = *negotiated_ssf_ptr;
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf);
      if (negotiated_ssf > 0)
	{
	HDEBUG(D_auth)
	  debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf);
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf);
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}

      /* close down the connection, freeing up library's memory */
      sasl_dispose(&conn);
      sasl_done();

      /* Expand server_condition as an authorization check */
      return auth_check_serv_cond(ablock);

    default:
      /* Anything else is a temporary failure, and we'll let SASL print out
       * the error string for us
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;
    }
  }
/* NOTREACHED */
return 0;  /* Stop compiler complaints */
}
int
main(int argc, char *argv[])
{
	char line[8192];
	char *username, *password;
#if SASL_VERSION_MAJOR < 2
	const char *errstr;
#endif

	int rc;
        sasl_conn_t *conn = NULL;

	/* make standard output line buffered */
	setvbuf(stdout, NULL, _IOLBF, 0);

	rc = sasl_server_init( NULL, APP_NAME_SASL );

	if ( rc != SASL_OK ) {
		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
		fprintf( stdout, "ERR\n" );
		return 1;
	}

	#if SASL_VERSION_MAJOR < 2
	rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn );
	#else
	rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, NULL, NULL, 0, &conn );
	#endif

	if ( rc != SASL_OK ) {
		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
		fprintf( stdout, "ERR\n" );
		return 1;
	}

	while ( fgets( line, sizeof( line ), stdin )) {
		username = &line[0];
		password = strchr( line, '\n' );
		if ( !password) {
			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
			fprintf( stdout, "ERR\n" );
			continue;
		}
		*password = '******';
		password = strchr ( line, ' ' );
		if ( !password) {
			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
			fprintf( stdout, "ERR\n" );
			continue;
		}
		*password++ = '\0';

		rfc1738_unescape(username);
		rfc1738_unescape(password);

		#if SASL_VERSION_MAJOR < 2
		rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr);
		#else
		rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password));
		#endif

		if ( rc != SASL_OK ) {
			#if SASL_VERSION_MAJOR < 2
			if ( errstr ) {
				fprintf( stderr, "errstr %s\n", errstr );
			}
			if ( rc != SASL_BADAUTH ) {
				fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
			}
			#endif
			fprintf( stdout, "ERR\n" );
		}
		else {
			fprintf( stdout, "OK\n" );
		}

	}

        sasl_dispose( &conn );
        sasl_done();

	return 0;
}