CVS: beepcore-c/threaded_os/profiles Makefile.in,NONE,1.1 cyrus-profiles.c,NONE,1.1 cyrus-profiles.h,NONE,1.1 null-profiles.c,NONE,1.1 null-profiles.h,NONE,1.1 sasl-profiles.c,NONE,1.1 sasl-profiles.h,NONE,1.1 syslog-raw.c,NONE,1.1 syslog-raw.h,NONE,1.1 tls-profile.c,NONE,1.1 tls-profile.h,NONE,1.1 tuning.h,NONE,1.1
Chris Hanson <[email protected]> Sat, 07 Sep 2002 20:02:35 -0700
| Newsgroups | gmane.network.beep.beepcore.c.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/beepcore-c/beepcore-c/threaded_os/profiles
In directory usw-pr-cvs1:/tmp/cvs-serv32474/threaded_os/profiles
Added Files:
Makefile.in cyrus-profiles.c cyrus-profiles.h null-profiles.c
null-profiles.h sasl-profiles.c sasl-profiles.h syslog-raw.c
syslog-raw.h tls-profile.c tls-profile.h tuning.h
Log Message:
Move "profiles/" directory to "threaded_os/profiles/".
--- NEW FILE: Makefile.in ---
#
# Copyright (c) 2001 Invisible Worlds, Inc. All rights reserved.
#
# The contents of this file are subject to the Blocks Public License (the
# "License"); You may not use this file except in compliance with the License.
#
# You may obtain a copy of the License at http://www.beepcore.org/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# $Id: Makefile.in,v 1.1 2002/09/08 03:02:33 cphmit Exp $
#
# Please notice that all dependencies are resolved by ordering, so
# that you are not allowed to screw around the order of targets!
### Generic settings
srcdir = @srcdir@
top_srcdir = @top_srcdir@
include $(top_srcdir)/Make.defs
### Target directories
DIRS = unix
MOREDIRS =
### Simple tree makefile targets
ifdef DIRS
all: treeall
clean: treeclean
install: treeinstall
endif
### Default tree handling targets
include $(top_srcdir)/Make.targets
--- NEW FILE: cyrus-profiles.c ---
/* profiles for CYRUS SASL (requires v2.1.0 or later) */
/* NB:
please don't mess with the '#undef tuning', that part is still
under development...
*/
/*
* $Id: cyrus-profiles.c,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/* includes */
#ifndef WIN32
#include <ctype.h>
#include <sys/time.h>
[...1935 lines suppressed...]
}
PROFILE_REGISTRATION *cyrus_profiles_Init2 (struct configobj *appconfig) {
int result;
char *cp;
cyrus_first ();
if (!(cp = config_get (appconfig, BEEP_IDENT)))
cp = "beepd";
if ((result = sasl_server_init (cyrus_server_callbacks (appconfig), cp))
!= SASL_OK) {
log_line (LOG_PROF, 7, "sasl_server_init failed (cyrus code %d) %s",
result, sasl_errstring (result, NULL, NULL));
return NULL;
}
return cyrus_profiles_Init (appconfig);
}
--- NEW FILE: cyrus-profiles.h ---
/* profiles for CYRUS SASL */
/*
* $Id: cyrus-profiles.h,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/*
initiator usage:
1. cyrus_first ()
2. sasl_client_init (cyrus_client_callbacks (), pgmname)
3. pr = cyrus_profiles_Init (appconfig)
4. cyrus_tune (pr, ...)
5. establish session using pr
6. d = cyrus_login (...)
if d is non-NULL, you lose
listener usage:
1. cyrus_first ()
2. sasl_server_init (cyrus_server_callbacks (appconfig), pgmname)
3. pr = cyrus_profiles_Init (appconfig)
4. cyrus_tune (pr, ...)
5. establish session using pr
*/
#ifndef CYRUS_PROFILES_H
#define CYRUS_PROFILES_H 1
/* includes */
#include <beepcore-c/bp_wrapper.h>
#include <beepcore-c/bp_config.h>
#include <beepcore-c/tuning.h>
#include <sasl/sasl.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name Cyrus SASL profiles
**/
/*@{*/
/* typedefs */
/**
* Prototype for the connection creation callback
*
* This calls <i>sasl_client_new</i> or <i>sasl_server_new</i> with whatever
* callback information is desired, and, on success, makes a call to
* <i>sasl_setprop</i> to set the desired security properties with
* <b>SASL_SEC_PROPS</b>.
* <p>
* Another reason to supply this callback, is it allows you to squirrel away
* the connection pointer to later call <i>sasl_getprop</i>.
*
* @param bp A pointer to the connection structure.
*
* @param conn Must be filled-in by the callback, i.e., by calling
* <i>sasl_client_new</i> or <i>sasl_server_new</i>.
*
* @param clientData The user-supplied pointer provided to
* {@link cyrus_tune cyrus_tune} or
* {@link cyrus_login cyrus_login}.
*
* @param serverP If non-zero, call <i>sasl_server_new</i>
* (otherwise, call <i>sasl_client_new</i>).
*
* @return A SASL result code (e.g., <b>SASL_OK</b>).
**/
typedef int (*sasl_conn_callback_t) (struct BP_CONNECTION* bp,
sasl_conn_t** conn,
void* clientData,
int serverP);
/**
* Prototype for the client interaction callback
*
* This is called whenever a client interaction is necessary.
*
* @param bp A pointer to the connection structure.
*
* @param interact As provided by <i>sasl_client_start</i> or
* <i>sasl_client_step</i>.
*
* @param clientData The user-supplied pointer provided to
* {@link cyrus_login cyrus_login}.
*
* @return On failure, a pointer to a {@link diagnostic diagnostic} structure
* explaining the reason
* (which will subsequently be destroyed by calling
* {@link bp_diagnostic_destroy bp_diagnostic_destroy}).
**/
typedef struct diagnostic* (*sasl_interact_callback_t) (BP_CONNECTION* bp,
sasl_interact_t* interact,
void* clientData);
/* keys for configuration package */
/**
* Enables debug mode for the SASL family of profiles,
* defaults to <b>"0"</b>.
**/
#define SASL_CYRUS_DEBUG "beep profiles sasl debug"
/**
* Specifies the registered name of the service using SASL,
* defaults to <b>"beep"</b>.
**/
#define SASL_CYRUS_SERVICE "beep profiles sasl cyrus service"
/**
* Specifies the minimum SSF that may be negotiated
* defaults to <b>0</b>.
* This is not consulted if {@link cyrus_login cyrus_login} was given
* a non-NULL <i>callback1</i> parameter.
**/
#define SASL_CYRUS_MINSSF "beep profiles sasl cyrus min_ssf"
/**
* Specifies the maximum SSF that may be negotiated
* defaults to <b>256</b>.
* This is not consulted if {@link cyrus_login cyrus_login} was given
* a non-NULL <i>callback1</i> parameter.
**/
#define SASL_CYRUS_MAXSSF "beep profiles sasl cyrus max_ssf"
/**
* Specifies the registered name of the service using SASL,
* optional.
**/
#define SASL_CYRUS_PLUGINPATH "beep profiles sasl cyrus plugin_path"
/* module entry points */
/**
* Well-known entry point for the SASL profiles implemented by Cyrus.
* <p>
* Note that you <b>must</b> call <i>sasl_server_init</i> or
* <i>sasl_client_init</i> <b>before</b> you call this routine.
* (But, first of all, you <b>must</b> call {@link cyrus_first cyrus_first}.)
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>SASL_CYRUS_DEBUG</dt>
* <dd>A non-zero value to enable debugging (optional).</dd>
*
* <dt>SASL_CYRUS_SERVICE</dt>
* <dd>The registered name of the service using SASL,
* defaults to <b>"beep"</b>.</dd>
* </dl></blockquote>
*
* @return A pointer to a linked-list of profile-registration structures.
**/
extern struct PROFILE_REGISTRATION* cyrus_profiles_Init(struct configobj* appconfig);
/* additional profile-related functions */
/**
* The function to call before calling <i>sasl_client_init</i> or
* <i>sasl_server_init</i>.
**/
extern void cyrus_first (void);
/**
* Returns a <i>sasl_callback_t</i> array, suitable for passing to
* <i>sasl_client_init</i>.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>SASL_CYRUS_PLUGINPATH</dt>
* <dd>A colon-separated search path (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a static array.
**/
extern sasl_callback_t* cyrus_client_callbacks (struct configobj *appconfig);
/**
* Returns a <i>sasl_callback_t</i> array, suitable for passing to
* <i>sasl_server_init</i>.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>SASL_CYRUS_PLUGINPATH</dt>
* <dd>A colon-separated search path (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a static array.
**/
extern sasl_callback_t* cyrus_server_callbacks (struct configobj *appconfig);
/**
* Sets the <i>SASL_CB_LOG</i> callback to use the logging package.
*
* @param bp A pointer to the connection structure.
*
* @param cb The callback array to update.
**/
extern int cyrus_callback_setlog (BP_CONNECTION* bp,
sasl_callback_t* cb);
/**
* A default interaction-handler.
* <p>
* Consult the connection's {@link configobj configuration}
* structure for the relevant information.
* If absent, then it queries the user via <i>stdin</i>.
* <p>
* Input Keys, all optional:
* <blockquote><dl>
* <dt>SASL_LOCAL_REALM</dt>
* <dd>The authentication realm.</dd>
*
* <dt>SASL_LOCAL_USERNAME</dt>
* <dd>The SASL authentication-identity.</dd>
*
* <dt>SASL_LOCAL_TARGET</dt>
* <dd>The SASL authorization-identity.</dd>
*
* <dt>SASL_LOCAL_PASSPHRASE</dt>
* <dd>The passphrase for the authentication-identity.</dd>
* </dl></blockquote>
* <p>
* Consult the {@link (*sasl_interact_callback_t) callback} information
* for an explanation of the parameters and return value.
*
* @see cyrus_login
**/
extern struct diagnostic* cyrus_fillin (BP_CONNECTION* bp,
sasl_interact_t* interact,
void* clientData);
/**
* Configures a profile-registration structure to invoke a user-supplied
* callback when it wants to create a <i>sasl_conn_t</i>.
* <p>
* Call this before registering the profile with the wrapper
* (e.g., before calling {@link tcp_bp_listen tcp_bp_listen}.)
*
* @param pr A pointer to the profile-registration returned by
* {@link cyrus_profiles_Init cyrus_profiles_Init}.
*
* @param callback The routine to invoke to call <i>sasl_client_new</i>
* or <i>sasl_server_new</i>
* (cf., {@link (*sasl_conn_callback_t) callback}).
*
* @param clientData A user-supplied pointer, supplied to <i>callback</i>.
*
* @param allP If non-zero, traverse the entire chain of profile-registration
* structures.
**/
extern void cyrus_tune (PROFILE_REGISTRATION* pr,
sasl_conn_callback_t callback,
void* clientData,
int allP);
/**
* Tune using SASL, and update the connection's
* {@link configobj configuration} structure accordingly.
*
* @param bp A pointer to the connection structure.
* <p>
* Input Keys:
* <blockquote><dl>
* <dt>SASL_CYRUS_SERVICE</dt>
* <dd>The "service name" for this application,
* defaults to <b>"beep"</b>.</dd>
*
* <dt>SASL_LOCAL_MECHANISM</dt>
* <dd>The SASL mechanism to use; if not present, this is negotiated.</dd>
* </dl></blockquote>
* <p>
* Output Keys:
* <blockquote><dl>
* <dt>SASL_LOCAL_MECHANISM</dt>
* <dd>The SASL mechanism used for authentication.</dd>
*
* <dt>SASL_LOCAL_CODE</dt>
* <dd>The resulting status code.
* Consult \URL[Section 8 of RFC 3080]{http://www.beepcore.org/beepcore/docs/rfc3080.jsp#reply-codes}
* for an (incomplete) list.</dd>
*
* <dt>SASL_LOCAL_REASON</dt>
* <dd>A textual message corresponding to <b>SASL_LOCAL_CODE</b></dd>
* </dl></blockquote>
*
* @param serverName The value to use for the <i>serverName</i> attribute
* of the <start> element (may not be <b>NULL</b>).
*
* @param callback1 The routine to invoke to call <i>sasl_client_new</i>
* or <i>sasl_server_new</i>
* (cf., {@link (*sasl_conn_callback_t) callback}).
*
* @param clientData1 A user-supplied pointer, supplied to <i>callback1</i>.
*
* @param callback2 The routine to invoke when a client interaction is needed
* (cf., {@link (*sasl_interact_callback_t) callback}),
* if <b>NULL</b>,
* then {@link cyrus_fillin cyrus_fillin} is used.
*
* @param clientData2 A user-supplied pointer, supplied to the <i>callback</i>.
*
* @return On failure, a pointer to a {@link diagnostic diagnostic} structure
* explaining the reason
* (which should subsequently be destroyed by calling
* {@link bp_diagnostic_destroy bp_diagnostic_destroy}).
*
* @see cyrus_fillin
**/
extern struct diagnostic* cyrus_login(BP_CONNECTION* bp,
char* serverName,
sasl_conn_callback_t callback1,
void* clientData1,
sasl_interact_callback_t callback2,
void* clientData2);
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
--- NEW FILE: null-profiles.c ---
/* profiles for NULL ECHO/SINK */
/*
* $Id: null-profiles.c,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/* includes */
#ifndef WIN32
#include <string.h>
#else
#include <windows.h>
#endif
#include "null-profiles.h"
#include <beepcore-c/tuning.h>
#include <beepcore-c/logutil.h>
#include <beepcore-c/semutex.h>
/* defines and typedefs */
#define PRO_ECHO_URI "http://xml.resource.org/profiles/NULL/ECHO"
#define PRO_SINK_URI "http://xml.resource.org/profiles/NULL/SINK"
#define EMPTY_RPY \
"Content-Type: application/beep+xml\r\n\r\n<null />"
typedef struct pro_localdata {
int pl_flags; /* mode flags */
#define PRO_ECHOMODE (1<<0) /* doing echo, not sink */
#define PRO_START (1<<1) /* did null_start */
#define PRO_READY (1<<2) /* ready for null_send */
#define PRO_RSPWAIT (1<<3) /* waiting for peer's response */
#define PRO_CLSWAIT (1<<4) /* waiting for close */
#define PRO_DENIED (1<<5) /* close request was denied */
#define PRO_DEBUG (1<<6) /* debugging */
PROFILE_INSTANCE
*pl_pi; /* return value for null_start */
char *pl_rbuf; /* out parameters for null_trip */
int pl_rlen; /* .. */
sem_t pl_sem; /* semaphore used for receive */
} PRO_LOCALDATA;
/* statics */
static char *pro_name (char *uri);
/* profile methods */
static char *
pro_name (char *uri) {
char *cp;
if ((cp = strrchr (uri, '/')) != NULL)
return ++cp;
return uri;
}
/* first four methods are invoked when channels are not-yet/no-longer
instantiated
success: return NULL
failure: return char *reason
*/
/* invoked when profile is registered with the wrapper
do process-wide initialization
on failure, the wrapper makes no further calls to the profile for
the duration of the session
*/
static char *
pro_connection_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (((PRO_LOCALDATA *) pr -> user_ptr) -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s connection_init\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
/* invoked if profile is about to be made available for the session
do session-wide initialization
on failure, the wrapper makes no further calls to the profile
*/
static char *
pro_session_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (((PRO_LOCALDATA *) pr -> user_ptr) -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s session_init: role='%c' mode=\"%s\"\n",
pro_name (pr -> uri), bp -> role, bp -> mode);
fflush (stderr);
}
return NULL;
}
/* invoked just before the session is released
do session-wide finalization
return value is ignored by wrapper
*/
static char *
pro_session_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (((PRO_LOCALDATA *) pr -> user_ptr) -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s session_fin\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
/* invoked just before wrapper is destroyed
do process-wide finalization
return value is ignored by wrapper
*/
static char *
pro_connection_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (((PRO_LOCALDATA *) pr -> user_ptr) -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s connection_fin\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
/* next three methods are invoked when a session/channel starts */
/* invoked when the peer asks to start a channel
if not echoing, ignore any piggyback'd data
clone PRO_LOCALDATA and accept it
*/
static void
pro_start_indication (PROFILE_INSTANCE *pi,
PROFILE *po) {
DIAGNOSTIC ds,
*d = &ds;
PRO_LOCALDATA *pl = pi -> channel -> profile_registration
-> user_ptr,
*il;
PROFILE ps,
*p = &ps;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pl -> pl_flags & PRO_DEBUG) {
char *cp,
**pp;
static char *pairs[] = {
PRIVACY_REMOTE_SUBJECTNAME, "PRIVACY_REMOTE_SUBJECTNAME",
PRIVACY_CIPHER_NAME, "PRIVACY_CIPHER_NAME",
PRIVACY_CIPHER_PROTOCOL, "PRIVACY_CIPHER_PROTOCOL",
PRIVACY_CIPHER_SBITS, "PRIVACY_CIPHER_SBITS",
SASL_LOCAL_MECHANISM, "SASL_LOCAL_MECHANISM",
SASL_LOCAL_CODE, "SASL_LOCAL_CODE",
SASL_LOCAL_REASON, "SASL_LOCAL_REASON",
SASL_REMOTE_MECHANISM, "SASL_REMOTE_MECHANISM",
SASL_REMOTE_USERNAME, "SASL_REMOTE_USERNAME",
SASL_REMOTE_TARGET, "SASL_REMOTE_TARGET",
SASL_REMOTE_CODE, "SASL_REMOTE_CODE",
SASL_REMOTE_REASON, "SASL_REMOTE_REASON",
NULL
};
fprintf (stderr, "%s start_indication: piggyback=\"%s\"\n",
pro_name (po -> uri),
po -> piggyback ? po -> piggyback : "<NULL>");
for (pp = pairs; *pp; pp++)
if ((cp = config_get (appconfig, *pp++)) != NULL)
fprintf (stderr, " %s: \"%s\"\n", *pp, cp);
fflush (stderr);
}
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il))) {
memset (d, 0, sizeof *d);
d -> code = 421;
d -> message = "out of memory";
bpc_start_response (pi -> channel, po, d);
return;
}
memcpy (il, pl, sizeof *il);
il -> pl_pi = pi, pi -> user_ptr1 = il;
if (il -> pl_flags & PRO_ECHOMODE)
p = po;
else {
memset (p, 0, sizeof *p);
p -> uri = po -> uri;
}
bpc_start_response (pi -> channel, p, NULL);
}
/* invoked when a our request to start a channel has resulted in the channel starting
remember PRO_LOCALDATA passed as clientData
*/
static void
pro_start_confirmation (void *clientData,
PROFILE_INSTANCE *pi,
PROFILE *po) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (il -> pl_flags & PRO_DEBUG) {
char *cp,
**pp;
static char *pairs[] = {
PRIVACY_REMOTE_SUBJECTNAME, "PRIVACY_REMOTE_SUBJECTNAME",
PRIVACY_CIPHER_NAME, "PRIVACY_CIPHER_NAME",
PRIVACY_CIPHER_PROTOCOL, "PRIVACY_CIPHER_PROTOCOL",
PRIVACY_CIPHER_SBITS, "PRIVACY_CIPHER_SBITS",
SASL_LOCAL_MECHANISM, "SASL_LOCAL_MECHANISM",
SASL_LOCAL_CODE, "SASL_LOCAL_CODE",
SASL_LOCAL_REASON, "SASL_LOCAL_REASON",
SASL_REMOTE_MECHANISM, "SASL_REMOTE_MECHANISM",
SASL_REMOTE_USERNAME, "SASL_REMOTE_USERNAME",
SASL_REMOTE_TARGET, "SASL_REMOTE_TARGET",
SASL_REMOTE_CODE, "SASL_REMOTE_CODE",
SASL_REMOTE_REASON, "SASL_REMOTE_REASON",
NULL
};
fprintf (stderr, "%s start_confirmation: piggyback=\"%s\"\n",
pro_name (po -> uri),
po -> piggyback ? po -> piggyback : "<NULL>");
for (pp = pairs; *pp; pp++)
if ((cp = config_get (appconfig, *pp++)) != NULL)
fprintf (stderr, " %s: \"%s\"\n", *pp, cp);
fflush (stderr);
}
il -> pl_pi = pi, pi -> user_ptr1 = il;
}
/* invoked when a response is received to null_start's request to start a channel
note failure
*/
static void
pro_start_callback (void *clientData,
CHANNEL_INSTANCE *ci,
DIAGNOSTIC *error) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (il -> pl_flags & PRO_DEBUG) {
if (error)
fprintf (stderr, "%s pro_start_callback: error=[%d] \"%s\" \n",
pro_name (ci -> profile_registration -> uri),
error -> code,
error -> message ? error -> message : "<NULL>");
else
fprintf (stderr, "%s pro_start_callback: no error\n",
pro_name (ci -> profile_registration -> uri));
fflush (stderr);
}
if (error)
printf ("unable to start channel: [%d] %s\n",
error -> code,
error -> message ? error -> message : "<NULL>");
}
/* next three methods are invoked when a session/channel closes */
/*
invoked when we or the peer asks to close a session/channel
(or perhaps due to transport problem, etc.)
if the remote peer is asking, reject it
otherwise, accept it
*/
static void
pro_close_indication (PROFILE_INSTANCE *pi,
DIAGNOSTIC *request,
char origin,
char scope) {
BP_CONNECTION *bp = pi -> channel -> conn;
DIAGNOSTIC *d;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (il -> pl_flags & PRO_DEBUG) {
fprintf (stderr,
"%s close_indication: request=[%d] \"%s\" origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
request -> code, request -> message ? request -> message
: "<NULL>",
origin, scope);
fflush (stderr);
}
d = ((il -> pl_flags & PRO_START) && (origin == PRO_ACTION_REMOTE))
? bp_diagnostic_new (bp, 500, NULL, "no thanks")
: NULL;
bpc_close_response (pi -> channel, d);
if (d)
bp_diagnostic_destroy (bp, d);
}
/* invoked when we know whether the channel has finally closed or not
(regardless of who requested it)
if nothing happened, do nothing
if we requested the close, leave PRO_LOCALDATA for null_close
if we're doing a round-trip, signal null_trip and release the semaphore
otherwise, lib_free PRO_LOCALDATA
*/
static void
pro_close_confirmation (PROFILE_INSTANCE *pi,
char status,
DIAGNOSTIC *error,
char origin,
char scope) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (il -> pl_flags & PRO_DEBUG) {
if (error)
fprintf (stderr,
"%s close_confirmation: status=%c error=[%d] \"%s\" origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status, error -> code, error -> message ? error -> message
: "<NULL>",
origin, scope);
else
fprintf (stderr,
"%s close_confirmation: status=%c no error origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status, origin, scope);
fflush (stderr);
}
if (status != PRO_ACTION_SUCCESS)
return;
pi -> user_ptr1 = NULL;
if (il -> pl_flags & PRO_CLSWAIT)
il -> pl_flags &= ~PRO_CLSWAIT;
else if (il -> pl_flags & PRO_START) {
il -> pl_pi = NULL;
if (il -> pl_flags & PRO_RSPWAIT) {
il -> pl_flags &= ~PRO_RSPWAIT;
SEM_POST (&il -> pl_sem);
}
}
else
lib_free (il);
}
/* invoked when a response is received to null_close's request to close
the channel
note failure
*/
static void
pro_close_callback (void *clientData,
CHANNEL_INSTANCE *ci,
DIAGNOSTIC *error) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (il -> pl_flags & PRO_DEBUG) {
if (error)
fprintf (stderr, "%s pro_close_callback: error=[%d] \"%s\" \n",
pro_name (ci -> profile_registration -> uri),
error -> code,
error -> message ? error -> message : "<NULL>");
else
fprintf (stderr, "%s pro_close_callback: no error\n",
pro_name (ci -> profile_registration -> uri));
fflush (stderr);
}
if (error) {
il -> pl_flags |= PRO_DENIED, il -> pl_flags &= ~PRO_CLSWAIT;
printf ("unable to close channel: [%d] %s\n",
error -> code,
error -> message ? error -> message : "<NULL>");
}
}
/* next two methods are invoked on tuning resets */
/* invoked when the local peer is about to do a tuning reset */
static void
pro_tuning_reset_indication (PROFILE_INSTANCE *pi) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (il -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s tuning_reset_indication\n",
pro_name (pi -> channel -> profile_registration -> uri));
fflush (stderr);
}
}
/* invoked when we know whether the tuning reset occurred */
static void
pro_tuning_reset_confirmation (PROFILE_INSTANCE *pi,
char status) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (il -> pl_flags & PRO_DEBUG) {
fprintf (stderr, "%s tuning_reset_confirmation: status=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status);
fflush (stderr);
}
pro_close_confirmation (pi, status, NULL, PRO_ACTION_LOCAL,
PRO_ACTION_SESSION);
}
/* invoked when a frame is available to be read
frame actions taken by
received ECHO SINK
-------- ---- ----
MSG send echo RPY partial: ignore
complete: send empty RPY
RPY update out parameters for null_trip
if complete, leave RSPWAIT
ERR/NUL if complete, leave RSPWAIT
ANS ignore ignore
*/
static void
pro_frame_available (PROFILE_INSTANCE *pi) {
int size;
char *buffer,
*payload;
FRAME *f;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (!(f = bpc_query_frame (pi -> channel, BLU_QUERY_ANYTYPE,
BLU_QUERY_ANYMSG, BLU_QUERY_ANYANS)))
return;
if (il -> pl_flags & PRO_DEBUG) {
fprintf (stderr,
"%s frame_available: type=%c number=%ld answer=%ld more=%c size=%ld\n",
pro_name (pi -> channel -> profile_registration -> uri),
f -> msg_type, f -> message_number, f -> answer_number,
f -> more, f -> size);
fprintf (stderr, f -> size > 75 ? "%-75.75s...\n" : "%s\n",
f -> payload);
fflush (stderr);
}
switch (f -> msg_type) {
case BLU_FRAME_TYPE_MSG:
if (il -> pl_flags & PRO_ECHOMODE)
payload = f -> payload, size = f -> size;
else if (f -> more == BLU_FRAME_COMPLETE)
payload = EMPTY_RPY, size = sizeof EMPTY_RPY - 1;
else
break;
if ((buffer = bpc_buffer_allocate (pi -> channel, size)) != NULL) {
memcpy (buffer, payload, size);
bpc_send (pi -> channel, BLU_FRAME_TYPE_RPY,
f -> message_number, BLU_FRAME_IGNORE_ANSNO,
f -> more, buffer, size);
} else
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"%s frame_available: out of memory",
pro_name (pi -> channel -> profile_registration -> uri));
break;
case BLU_FRAME_TYPE_RPY:
if (f -> size <= il -> pl_rlen) {
memcpy (il -> pl_rbuf, f -> payload, f -> size);
il -> pl_rbuf += f -> size, il -> pl_rlen -= f -> size;
} else
il -> pl_rlen = -1;
/* and fall... */
case BLU_FRAME_TYPE_ERR:
case BLU_FRAME_TYPE_NUL:
if (f -> more == BLU_FRAME_COMPLETE) {
il -> pl_flags &= ~PRO_RSPWAIT;
SEM_POST (&il -> pl_sem);
}
break;
case BLU_FRAME_TYPE_ANS:
default:
break;
}
bpc_frame_destroy (pi -> channel, f);
}
/* module entry points */
static PROFILE_REGISTRATION *
pro_init (struct configobj *appconfig,
int echoP) {
int debugP;
char *cp;
PRO_LOCALDATA *pl;
PROFILE_REGISTRATION *pr;
if (!(pr = (PROFILE_REGISTRATION *) lib_malloc (sizeof *pr +
sizeof *pl))) {
log_line (LOG_PROF, 6, "unable to allocate PR");
return NULL;
}
memset (pr, 0, sizeof *pr);
cp = echoP ? NULL_ECHO_DEBUG : NULL_SINK_DEBUG;
debugP = 0;
if ((cp = config_get (appconfig, cp)) != NULL)
debugP = atoi (cp);
cp = echoP ? NULL_ECHO_URI : NULL_SINK_URI;
if (!(pr -> uri = config_get (appconfig, cp)))
pr -> uri = echoP ? PRO_ECHO_URI : PRO_SINK_URI;
cp = echoP ? NULL_ECHO_IMODES : NULL_SINK_IMODES;
if (!(pr -> initiator_modes = config_get (appconfig, cp)))
pr -> initiator_modes = "plaintext,encrypted";
cp = echoP ? NULL_ECHO_LMODES : NULL_SINK_LMODES;
if (!(pr -> listener_modes = config_get (appconfig, cp)))
pr -> listener_modes = "plaintext,encrypted";
pr -> full_messages = 0;
pr -> thread_per_channel = 0;
pr -> proreg_connection_init = pro_connection_init;
pr -> proreg_connection_fin = pro_connection_fin;
pr -> proreg_session_init = pro_session_init;
pr -> proreg_session_fin = pro_session_fin;
pr -> proreg_start_indication = pro_start_indication;
pr -> proreg_start_confirmation = pro_start_confirmation;
pr -> proreg_close_indication = pro_close_indication;
pr -> proreg_close_confirmation = pro_close_confirmation;
pr -> proreg_tuning_reset_indication = pro_tuning_reset_indication;
pr -> proreg_tuning_reset_confirmation = pro_tuning_reset_confirmation;
pr -> proreg_frame_available = pro_frame_available;
pr -> user_ptr = pl = (PRO_LOCALDATA *) (((char *) pr) + sizeof *pr);
memset (pl, 0, sizeof *pl);
if (echoP)
pl -> pl_flags |= PRO_ECHOMODE;
if (debugP)
pl -> pl_flags |= PRO_DEBUG;
return pr;
}
PROFILE_REGISTRATION *
null_echo_Init (struct configobj *appconfig) {
return pro_init (appconfig, 1);
}
PROFILE_REGISTRATION *
null_sink_Init (struct configobj *appconfig) {
return pro_init (appconfig, 0);
}
/* initiator: start channel */
void *
null_start (BP_CONNECTION *bp,
PROFILE_REGISTRATION *pr,
char *serverName) {
DIAGNOSTIC *d;
PRO_LOCALDATA *pl = pr -> user_ptr,
*il;
PROFILE ps,
*p = &ps;
memset (p, 0, sizeof *p);
p -> uri = pr -> uri;
p -> piggyback_length = strlen (p -> piggyback = "");
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il)))
return NULL;
memcpy (il, pl, sizeof *il);
il -> pl_flags |= PRO_START;
/* this blocks! */
d = bp_start_request (bp, BLU_CHAN0_CHANO_DEFAULT, BLU_CHAN0_MSGNO_DEFAULT,
p, serverName, pro_start_callback, (void *) il);
if (d) {
printf ("unable to start channel: [%d] %s\n",
d -> code, d -> message);
bp_diagnostic_destroy (bp, d);
}
if (il -> pl_pi) {
SEM_INIT (&il -> pl_sem, 0);
il -> pl_flags |= PRO_READY;
} else
lib_free (il), il = NULL;
return ((void *) il);
}
/* initiator: send a message, get back reply */
extern int
null_trip (void *v,
char *ibuf,
int ilen,
char *obuf,
int omaxlen) {
char *buffer;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) v;
PROFILE_INSTANCE *pi;
if (!(pi = il -> pl_pi)) {
SEM_DESTROY (&il -> pl_sem);
lib_free (il);
return NULL_DONE;
}
if (!(il -> pl_flags & PRO_READY))
return NULL_BUSY;
if (!(buffer = bpc_buffer_allocate (pi -> channel, ilen)))
return NULL_ERROR;
memcpy (buffer, ibuf, ilen);
il -> pl_rbuf = obuf, il -> pl_rlen = omaxlen;
il -> pl_flags |= PRO_RSPWAIT, il -> pl_flags &= ~PRO_READY;
bpc_send (pi -> channel, BLU_FRAME_TYPE_MSG, BLU_FRAME_MSGNO_UNUSED,
BLU_FRAME_IGNORE_ANSNO, BLU_FRAME_COMPLETE, buffer, ilen);
SEM_WAIT (&il -> pl_sem);
if (!il -> pl_pi) {
SEM_DESTROY (&il -> pl_sem);
lib_free (il);
return NULL_DONE;
}
il -> pl_flags |= PRO_READY;
if (il -> pl_rlen < 0)
return NULL_ERROR;
return (omaxlen - il -> pl_rlen);
}
/* initiator: close channel */
extern int
null_close (void *v) {
BP_CONNECTION *bp;
DIAGNOSTIC *d;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) v;
PROFILE_INSTANCE *pi;
if (!(pi = il -> pl_pi)) {
SEM_DESTROY (&il -> pl_sem);
lib_free (il);
return NULL_DONE;
}
if (!(il -> pl_flags & PRO_READY))
return NULL_BUSY;
il -> pl_flags |= PRO_CLSWAIT, il -> pl_flags &= ~PRO_READY;
bp = pi -> channel -> conn;
if ((d = bpc_close_request (pi -> channel, BLU_CHAN0_MSGNO_DEFAULT, 200,
NULL, NULL, pro_close_callback,
(void *) il)) != NULL) {
printf ("unable to close channel: [%d] %s\n",
d -> code, d -> message);
bp_diagnostic_destroy (bp, d);
il -> pl_flags |= PRO_READY, il -> pl_flags &= ~PRO_CLSWAIT;
return NULL_ERROR;
}
/* could use a semaphore instead of a spinlock, but it's an example... */
while (il -> pl_flags & PRO_CLSWAIT)
YIELD ();
if (il -> pl_flags & PRO_DENIED) {
il -> pl_flags |= PRO_READY, il -> pl_flags &= ~PRO_DENIED;
return NULL_DENIED;
}
SEM_DESTROY (&il -> pl_sem);
lib_free (il);
return NULL_OK;
}
--- NEW FILE: null-profiles.h ---
/* profiles for NULL ECHO/SINK */
/*
* $Id: null-profiles.h,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/*
initiator usage:
1. pr = null_echo_Init (appconfig) or null_sink_Init ...
2. establish session, bp, using pr
3. v = null_start (bp, pr)
if v is NULL, you lose
4. for 0..I: cc = null_trip (v, ibuf, ilen, obuf, omaxlen)
if (cc < 0) release session, etc.
otherwise cc octets were stored in obuf
5. i = null_close (v)
if (i < 0) release session, etc.
otherwise channel is closed
listener usage:
1. pr = null_echo_Init (appconfig) or null_sink_Init ...
2. establish session using pr
3. sr_Fin (pr) prior to destroying pr
*/
#ifndef NULL_PROFILES_H
#define NULL_PROFILES_H 1
/* includes */
#include <beepcore-c/bp_config.h>
#include <beepcore-c/bp_wrapper.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name The NULL/ECHO and NULL/SINK profiles
**/
/*@{*/
/* keys for configuration package */
/**
* URI to use for the NULL ECHO profile,
* defaults to <b>"http://xml.resource.org/profiles/NULL/ECHO"</b>.
**/
#define NULL_ECHO_URI "beep profiles null_echo uri"
/**
* Initiator modes for the NULL ECHO profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define NULL_ECHO_IMODES "beep profiles null_echo initiator_modes"
/**
* Listener modes for the NULL ECHO profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define NULL_ECHO_LMODES "beep profiles null_echo listener_modes"
/**
* Enables debug mode for the NULL ECHO profile,
* defaults to <b>"0"</b>.
**/
#define NULL_ECHO_DEBUG "beep profiles null_echo debug"
/**
* URI to use for the NULL SINK profile,
* defaults to <b>"http://xml.resource.org/profiles/NULL/SINK"</b>.
**/
#define NULL_SINK_URI "beep profiles null_sink uri"
/**
* Initiator modes for the NULL SINK profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define NULL_SINK_IMODES "beep profiles null_sink initiator_modes"
/**
* Listener modes for the NULL SINK profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define NULL_SINK_LMODES "beep profiles null_sink listener_modes"
/**
* Enables debug mode for the NULL SINK profile,
* defaults to <b>"0"</b>.
**/
#define NULL_SINK_DEBUG "beep profiles null_sink debug"
/* module entry points */
/**
* Well-known entry point for the NULL/ECHO profile.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>NULL_ECHO_URI</dt>
* <dd>The registration URI for the profile (optional).</dd>
*
* <dt>NULL_ECHO_IMODES</dt>
* <dd>The <i>initiator_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>NULL_ECHO_LMODES</dt>
* <dd>The <i>listener_modes</i> to use when registering the profile
* (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a profile-registration structure.
**/
extern struct PROFILE_REGISTRATION* null_echo_Init (struct configobj* appconfig);
/**
* Well-known entry point for the NULL/SINK profile.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure that may be used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>NULL_SINK_URI</dt>
* <dd>The registration URI for the profile (optional).</dd>
*
* <dt>NULL_SINK_IMODES</dt>
* <dd>The <i>initiator_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>NULL_SINK_LMODES</dt>
* <dd>The <i>listener_modes</i> to use when registering the profile
* (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a profile-registration structure.
**/
extern struct PROFILE_REGISTRATION* null_sink_Init (struct configobj* appconfig);
/* initiator routines */
/**
* Starts an echo or sink channel.
*
* @param bp A pointer to the connection structure.
*
* @param pr A pointer to the profile-registration returned by either
* {@link null_echo_Init null_echo_Init} or
* {@link null_sink_Init null_sink_Init}.
*
* @param serverName The value to use for the <i>serverName</i> attribute
* of the <start> element, or <b>NULL</b>.
*
* @return An opaque pointer for use with {@link null_trip null_trip} and
* {@link null_close null_close}.
**/
extern void* null_start (struct BP_CONNECTION* bp,
struct PROFILE_REGISTRATION* pr,
char* serverName);
/**
* Initiates a round-trip transaction.
*
* @param v An opaque pointer returned by {@link null_start null_start}.
*
* @param ibuf A character pointer to the send buffer.
*
* @param ilen The length of the send buffer, in octets.
*
* @param obuf A character pointer to the receive buffer.
*
* @param omaxlen The length of the receive buffer, in octets.
*
* @return The number of octets received, or one of:
* <ul>
* <li>{@link NULL_ERROR NULL_ERROR}</li>
* <li>{@link NULL_BUSY NULL_BUSY}</li>
* <li>{@link NULL_DONE NULL_DONE}</li>
* </ul>
**/
extern int null_trip (void* v,
char* ibuf,
int ilen,
char* obuf,
int omaxlen);
/**
* Closes an echo or sink channel.
*
* @param v An opaque pointer returned by {@link null_start null_start}.
*
* @return One of:
* <ul>
* <li>{@link NULL_OK NULL_OK}</li>
* <li>{@link NULL_ERROR NULL_ERROR}</li>
* <li>{@link NULL_BUSY NULL_BUSY}</li>
* <li>{@link NULL_DONE NULL_DONE}</li>
* <li>{@link NULL_DENIED NULL_DENIED}</li>
* </ul>
**/
extern int null_close (void* v);
/**
* no problema
**/
#define NULL_OK 0
/**
* error performing task
**/
#define NULL_ERROR (-1)
/**
* still doing {@link null_trip null_trip}
**/
#define NULL_BUSY (-2)
/**
* channel is closed
**/
#define NULL_DONE (-3)
/**
* remote peer refused to close
**/
#define NULL_DENIED (-4)
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
--- NEW FILE: sasl-profiles.c ---
/*
* Copyright (c) 2001 Invisible Worlds, Inc. All rights reserved.
*
* The contents of this file are subject to the Blocks Public License (the
* "License"); You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at http://www.beepcore.org/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*/
/*
* $Id: sasl-profiles.c,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/* includes */
#ifndef WIN32
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#else
#include <windows.h>
#define sem_t HANDLE
#endif
#include <beepcore-c/sasl-profiles.h>
#include <beepcore-c/logutil.h>
#include <beepcore-c/CBEEPint.h>
#include "SASLutils/sasl_general.h"
/* defines and typedefs */
#define PRO_ANONYMOUS_URI "http://iana.org/beep/SASL/ANONYMOUS"
#define PRO_OTP_URI "http://iana.org/beep/SASL/OTP"
#define DEFAULT_CONTENT_TYPE "Content-Type: application/beep+xml\r\n\r\n"
typedef struct pro_localdata {
int pl_flags;
#define PRO_INITIATOR (1<<0)
#define PRO_STARTING (1<<1)
#define PRO_CLOSED (1<<2)
CHANNEL_INSTANCE *pl_channel;
DIAGNOSTIC *pl_status;
int pl_task;
#define PRO_SERVER_ANON 0x00
#define PRO_SERVER_OTP 0x01
#define PRO_CLIENT_ANON 0x80
#define PRO_CLIENT_OTP 0x81
int pl_sent;
struct sasl_data_block
pl_sdb;
} PRO_LOCALDATA;
/* statics */
static int pro_debug;
static char *pro_name (char *uri);
static void sasl_error (PROFILE_INSTANCE *pi,
char *data,
int size);
static char *sasl_response (PROFILE_INSTANCE *pi,
int result);
static void sasl_set_local_success (PROFILE_INSTANCE *pi);
static void sasl_set_local_failure (PROFILE_INSTANCE *pi,
DIAGNOSTIC *d);
static void sasl_set_remote_success (PROFILE_INSTANCE *pi);
static void sasl_set_remote_failure (PROFILE_INSTANCE *pi,
int code,
char *reason);
/* profile methods */
static char *
pro_name (char *uri) {
char *cp;
if ((cp = strrchr (uri, '/')) != NULL)
return ++cp;
return uri;
}
static char *
pro_connection_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "%s connection_init\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
static char *
pro_session_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "%s session_init: role='%c' mode=\"%s\"\n",
pro_name (pr -> uri), bp -> role, bp -> mode);
fflush (stderr);
}
return NULL;
}
static char *
pro_session_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "%s session_fin\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
static char *
pro_connection_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "%s connection_fin\n", pro_name (pr -> uri));
fflush (stderr);
}
return NULL;
}
static void
pro_start_indication (PROFILE_INSTANCE *pi,
PROFILE *po) {
char *cp,
*otp;
DIAGNOSTIC ds,
*d = &ds;
PRO_LOCALDATA *il;
PROFILE ps,
*p = &ps;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
struct cfgsearchobj *cs;
if (pro_debug) {
fprintf (stderr, "%s start_indication: piggyback=\"%s\"\n",
pro_name (po -> uri),
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
memset (p, 0, sizeof *p);
p -> uri = po -> uri;
memset (d, 0, sizeof *d);
d -> code = 421;
if (((cp = config_get (appconfig, SASL_LOCAL_CODE)) != NULL)
&& (*cp == '2')) {
d -> code = 520;
d -> message = "already tuned for authentication";
bpc_start_response (pi -> channel, p, d);
return;
}
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il))) {
d -> message = "out of memory";
bpc_start_response (pi -> channel, p, d);
return;
}
pi -> user_ptr1 = il;
memset (il, 0, sizeof *il);
if (!(otp = config_get (appconfig, SASL_OTP_URI)))
otp = PRO_OTP_URI;
il -> pl_task = strcmp (po -> uri, otp) ? PRO_SERVER_ANON : PRO_SERVER_OTP;
if (!(il -> pl_sdb.path = config_get (appconfig, SASL_OTP_DIRECTORY)))
il -> pl_sdb.path = "/tmp";
cs = config_search_init (appconfig, SASL_REMOTE_PREFIX, "");
for (cp = config_search_string_firstkey (cs);
cp;
cp = config_search_string_nextkey (cs))
config_delete (appconfig, cp);
config_search_fin (&cs);
switch (il -> pl_task) {
case PRO_SERVER_ANON:
config_set (appconfig, SASL_REMOTE_MECHANISM, "anonymous");
break;
case PRO_SERVER_OTP:
config_set (appconfig, SASL_REMOTE_MECHANISM, "otp");
break;
}
if (po -> piggyback_length > 0) {
int result = SASL_COMPLETE;
switch (il -> pl_task) {
case PRO_SERVER_ANON:
if ((result = sasl_anonymous_server_guts (po -> piggyback,
&il -> pl_sdb))
== SASL_COMPLETE)
config_set (appconfig, SASL_REMOTE_USERNAME,
il -> pl_sdb.parse_blob_data);
break;
case PRO_SERVER_OTP:
result = sasl_otp_server_guts_1 (po -> piggyback,
&il -> pl_sdb);
break;
}
p -> piggyback_length = strlen (p -> piggyback =
sasl_response (pi, result));
il -> pl_sent = 1;
}
bpc_start_response (pi -> channel, p, NULL);
}
static void
pro_start_confirmation (void *clientData,
PROFILE_INSTANCE *pi,
PROFILE *po) {
int problem,
size;
char *buffer,
*payload;
PRO_LOCALDATA *il = clientData;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "%s start_confirmation: piggyback=\"%s\"\n",
pro_name (po -> uri),
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
pi -> user_ptr1 = il;
il -> pl_flags &= ~(PRO_STARTING | PRO_CLOSED);
il -> pl_channel = pi -> channel;
if (po -> piggyback_length == 0) {
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, 504, NULL,
"expecting blob element");
return;
}
if (strstr (po -> piggyback, "<error")) {
sasl_error (pi, po -> piggyback, po -> piggyback_length);
return;
}
switch (il -> pl_task) {
case PRO_CLIENT_ANON:
parse_blob (po -> piggyback, &il -> pl_sdb);
if (!strcmp (il -> pl_sdb.parse_blob_status, "complete"))
sasl_set_local_success (pi);
else
sasl_set_local_failure (pi, NULL);
break;
case PRO_CLIENT_OTP:
if (!(payload = sasl_otp_client_guts_2
(po -> piggyback,
config_get (appconfig, SASL_LOCAL_PASSPHRASE),
&problem, &il -> pl_sdb))) {
if (problem == SASL_ERROR_ALGORITHM) {
config_set (appconfig, SASL_LOCAL_CODE, "504");
config_set (appconfig, SASL_LOCAL_REASON,
"unsupported algorithm");
} else {
config_set (appconfig, SASL_LOCAL_CODE, "501");
config_set (appconfig, SASL_LOCAL_REASON,
"unable to parse blob");
}
payload = "<blob status='abort' />";
}
size = strlen (payload) + sizeof DEFAULT_CONTENT_TYPE - 1;
if ((buffer = bpc_buffer_allocate (pi -> channel, size)) != NULL) {
sprintf (buffer, "%s%s", DEFAULT_CONTENT_TYPE, payload);
bpc_send (pi -> channel, BLU_FRAME_TYPE_MSG,
BLU_FRAME_MSGNO_UNUSED, BLU_FRAME_IGNORE_ANSNO,
BLU_FRAME_COMPLETE, buffer, size);
il -> pl_sent++;
} else
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"%s start_confirmation: out of memory",
pro_name (po -> uri));
break;
}
}
static void
pro_close_indication (PROFILE_INSTANCE *pi,
DIAGNOSTIC *request,
char origin,
char scope) {
if (pro_debug) {
fprintf (stderr,
"%s close_indication: request=[%d] \"%s\" origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
request -> code, request -> message ? request -> message
: "<NULL>",
origin, scope);
fflush (stderr);
}
bpc_close_response (pi -> channel, NULL);
}
static void
pro_close_confirmation (PROFILE_INSTANCE *pi,
char status,
DIAGNOSTIC *error,
char origin,
char scope) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (pro_debug) {
if (error)
fprintf (stderr,
"%s close_confirmation: status=%c error=[%d] \"%s\" origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status, error -> code, error -> message ? error -> message
: "<NULL>",
origin, scope);
else
fprintf (stderr,
"%s close_confirmation: status=%c no error origin=%c scope=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status, origin, scope);
fflush (stderr);
}
if (status != PRO_ACTION_SUCCESS)
return;
if (il) {
if (il -> pl_flags & PRO_INITIATOR) {
il -> pl_flags |= PRO_CLOSED;
} else {
pi -> user_ptr1 = NULL;
lib_free (il);
}
}
}
static void
pro_tuning_reset_indication (PROFILE_INSTANCE *pi) {
if (pro_debug) {
fprintf (stderr, "%s tuning_reset_indication\n",
pro_name (pi -> channel -> profile_registration -> uri));
fflush (stderr);
}
}
static void
pro_tuning_reset_confirmation (PROFILE_INSTANCE *pi,
char status) {
if (pro_debug) {
fprintf (stderr, "%s tuning_reset_confirmation: status=%c\n",
pro_name (pi -> channel -> profile_registration -> uri),
status);
fflush (stderr);
}
pro_close_confirmation (pi, status, NULL, PRO_ACTION_LOCAL,
PRO_ACTION_SESSION);
}
static void
pro_message_available (PROFILE_INSTANCE *pi) {
int result,
size;
char *buffer,
*payload,
*response = NULL;
FRAME *f;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
result = SASL_ALREADY_DONE;
if (!(f = bpc_query_message (pi -> channel, BLU_QUERY_ANYTYPE,
BLU_QUERY_ANYMSG, BLU_QUERY_ANYANS)))
return;
if (pro_debug) {
fprintf (stderr,
"%s message_available: type=%c number=%ld answer=%ld size=%ld\n",
pro_name (pi -> channel -> profile_registration -> uri),
f -> msg_type, f -> message_number, f -> answer_number,
f -> size);
fprintf (stderr, f -> size > 150 ? "%-150.150s...\n" : "%s\n",
f -> payload);
fflush (stderr);
}
size = bpc_frame_aggregate (pi -> channel, f, &buffer);
if (buffer == NULL) {
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"%s message_available: out of memory aggregating message",
pro_name (pi -> channel -> profile_registration -> uri));
bpc_frame_destroy (pi -> channel, f);
return;
}
switch (il -> pl_task) {
case PRO_CLIENT_ANON:
break;
case PRO_CLIENT_OTP:
if (il -> pl_sent != 2)
break;
if (strstr (buffer, "<error") != NULL)
sasl_error (pi, buffer, size);
else {
parse_blob (buffer, &il -> pl_sdb);
if (!strcmp (il -> pl_sdb.parse_blob_status, "complete"))
sasl_set_local_success (pi);
else
sasl_set_local_failure (pi, NULL);
}
break;
case PRO_SERVER_ANON:
if (il -> pl_sent != 0)
break;
if ((result = sasl_anonymous_server_guts (buffer, &il -> pl_sdb))
== SASL_COMPLETE)
config_set (appconfig, SASL_REMOTE_USERNAME,
il -> pl_sdb.parse_blob_data);
break;
case PRO_SERVER_OTP:
switch (il -> pl_sent) {
case 0:
result = sasl_otp_server_guts_1 (buffer, &il -> pl_sdb);
break;
case 1:
if ((result = sasl_otp_server_guts_2 (buffer, &il -> pl_sdb))
== SASL_COMPLETE) {
config_set (appconfig, SASL_REMOTE_USERNAME,
il -> pl_sdb.authenID);
config_set (appconfig, SASL_REMOTE_TARGET,
(il -> pl_sdb.authorID[0] != '\0')
? il -> pl_sdb.authorID
: il -> pl_sdb.authenID);
}
break;
}
break;
}
bpc_buffer_destroy (pi -> channel, buffer);
switch (il -> pl_task) {
case PRO_CLIENT_ANON:
case PRO_CLIENT_OTP:
response = NULL;
break;
case PRO_SERVER_ANON:
case PRO_SERVER_OTP:
response = sasl_response (pi, result);
break;
}
if (f -> msg_type == BLU_FRAME_TYPE_MSG) {
payload = response ? response
: "<error code='521'>Client-side only</error>";
size = strlen (payload) + sizeof DEFAULT_CONTENT_TYPE - 1;
if ((buffer = bpc_buffer_allocate(pi -> channel, size)) != NULL) {
sprintf (buffer, "%s%s", DEFAULT_CONTENT_TYPE, payload);
bpc_send (pi -> channel,
(payload[1] == 'e')
? BLU_FRAME_TYPE_ERR : BLU_FRAME_TYPE_RPY,
f -> message_number, f -> answer_number,
BLU_FRAME_COMPLETE, buffer, size);
il -> pl_sent++;
} else
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"%s message: out of memory sending response",
pro_name (pi -> channel -> profile_registration -> uri));
}
bpc_frame_destroy (pi -> channel, f);
}
static void
pro_window_full (PROFILE_INSTANCE *pi) {
DIAGNOSTIC *d;
if (pro_debug) {
fprintf (stderr, "%s window_full\n",
pro_name (pi -> channel -> profile_registration -> uri));
fflush (stderr);
}
bp_log (pi -> channel -> conn, LOG_PROF, 5, "%s channel window full!?!",
pro_name (pi -> channel -> profile_registration -> uri));
if (!(d = bpc_close_request (pi -> channel, BLU_CHAN0_MSGNO_DEFAULT, 550,
NULL, "stop misbehaving", NULL, NULL))) {
bp_log (pi -> channel -> conn, LOG_PROF, 4,
"unable to close SASL channel: [%d] %s", d -> code,
d -> message);
bp_diagnostic_destroy (pi -> channel -> conn, d);
}
}
/* helper functions */
static void
sasl_error (PROFILE_INSTANCE *pi,
char *data,
int size) {
char *cp;
DIAGNOSTIC ds,
*d = &ds;
FRAME *f;
if ((cp = strstr (data, "<error")) != NULL)
size -= cp - data, data = cp;
memset (d, 0, sizeof *d);
if (!(f = bpc_frame_allocate (pi -> channel, size))) {
d -> code = 421;
d -> message = "out of memory decoding SASL error";
} else {
f -> msg_type = BLU_FRAME_TYPE_ERR;
strcpy (f -> payload, data);
if (!(d = bpc_parse_error (pi -> channel, f))) {
d -> code = 500;
d -> message = "unable to parse error message from server";
}
}
sasl_set_local_failure (pi, d);
if (d != &ds)
bp_diagnostic_destroy (pi -> channel -> conn, d);
if (f)
bpc_frame_destroy (pi -> channel, f);
}
static char *
sasl_response (PROFILE_INSTANCE *pi,
int result) {
char *response;
struct sasl_data_block
*sdb = &(((PRO_LOCALDATA *) pi -> user_ptr1) -> pl_sdb);
switch (result) {
case SASL_COMPLETE:
response = "<blob status='complete' />";
sasl_set_remote_success (pi);
break;
case SASL_CONTINUE:
response = sdb -> payload;
break;
case SASL_ABORTED:
response = "<blob status='complete' />";
sasl_set_remote_failure (pi, 550, "Aborted by client");
break;
case SASL_ERROR_BLOB:
response = "<error code='501'>Invalid blob format</error>";
sasl_set_remote_failure (pi, 501, "Invalid blob format");
break;
case SASL_ERROR_TRACE:
response = "<error code='551'>Invalid trace information</error>";
sasl_set_remote_failure (pi, 551, "Invalid trace information");
break;
case SASL_ERROR_PROXY:
response = "<error code='551'>Proxying not supported</error>";
sasl_set_remote_failure (pi, 551, "Proxying not supported");
break;
case SASL_ERROR_USERNAME:
response = "<error code='535'>Invalid user name</error>";
sasl_set_remote_failure (pi, 535, "Invalid user name");
break;
case SASL_ERROR_USERBUSY:
response = "<error code='450'>Database busy</error>";
sasl_set_remote_failure (pi, 450, "Database busy");
break;
case SASL_ERROR_SEQUENCE:
response = "<error code='534'>Sequence exhausted</error>";
sasl_set_remote_failure (pi, 534, "Sequence exhausted");
break;
case SASL_ERROR_HEXONLY:
response = "<error code='554'>Expecting hex: response</error>";
sasl_set_remote_failure (pi, 554, "Expecting hex: response");
break;
case SASL_ERROR_BADHASH:
response = "<error code='535'>Invalid user name</error>";
sasl_set_remote_failure (pi, 535, "Bad response");
break;
default:
response = "<error code='504'>Internal error</error>";
sasl_set_remote_failure (pi, 504, "Internal error");
break;
}
return response;
}
static void
sasl_set_local_success (PROFILE_INSTANCE *pi) {
int code;
char *reason;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "sasl_set_local_success\n");
fflush (stderr);
}
if (config_test_and_set (appconfig, SASL_LOCAL_CODE, "200") != CONFIG_OK) {
code = atoi (config_get (appconfig, SASL_LOCAL_CODE));
reason = config_get (appconfig, SASL_LOCAL_REASON);
} else {
code = 200;
config_set (appconfig, SASL_LOCAL_REASON, reason = "login successful");
}
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, code, NULL,
"%s", reason);
}
static void
sasl_set_local_failure (PROFILE_INSTANCE *pi,
DIAGNOSTIC *d) {
int code;
char buffer[BUFSIZ],
*reason;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (d) {
code = d -> code;
reason = d -> message ? d -> message : "";
} else if (!il -> pl_sdb.parse_blob_status[0])
code = 501, reason = "unable to parse blob from server";
else if (!strcmp (il -> pl_sdb.parse_blob_status, "abort"))
code = 450, reason = "server returned 'abort' status";
else if (!strcmp (il -> pl_sdb.parse_blob_status, "continue"))
code = 300, reason = "server returned 'continue' status";
else {
code = 555;
sprintf (reason = buffer, "server returned '%s' status",
il -> pl_sdb.parse_blob_status);
}
if (pro_debug) {
fprintf (stderr, "sasl_set_local_failure: code=%d reason=\"%s\"\n",
code, reason);
fflush (stderr);
}
config_set (appconfig, SASL_LOCAL_REASON, reason);
sprintf (buffer, "%d", code);
config_set (appconfig, SASL_LOCAL_CODE, buffer);
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, code, NULL,
"%s", reason);
}
static void
sasl_set_remote_success (PROFILE_INSTANCE *pi) {
char *cp;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "sasl_set_remote_success\n");
fflush (stderr);
}
if (config_test_and_set (appconfig, SASL_REMOTE_CODE, "200")
== CONFIG_OK) {
config_set (appconfig, SASL_REMOTE_REASON, "login successful");
cp = config_get (appconfig, SASL_REMOTE_MECHANISM);
bp_log (pi -> channel -> conn, LOG_PROF, 2, "sasl 200 %s %s", cp,
config_get (appconfig, SASL_REMOTE_USERNAME));
}
}
static void
sasl_set_remote_failure (PROFILE_INSTANCE *pi,
int code,
char *reason) {
char buffer[BUFSIZ];
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "sasl_set_remote_failure: code=%d reason=\"%s\"\n",
code, reason);
fflush (stderr);
}
sprintf (buffer, "%d", code);
config_set (appconfig, SASL_REMOTE_CODE, buffer);
config_set (appconfig, SASL_REMOTE_REASON, reason);
bp_log (pi -> channel -> conn, LOG_PROF, 3, "sasl %d %s", code, reason);
}
/*
* Additional profile-related functions.
*/
DIAGNOSTIC *
sasl_login (BP_CONNECTION *bp,
char *serverName) {
char *cp,
*mechanism;
DIAGNOSTIC *d;
PRO_LOCALDATA *il;
PROFILE ps,
*p = &ps;
struct configobj *appconfig = bp_get_config (bp);
if (((cp = config_get (appconfig, SASL_REMOTE_CODE)) != NULL)
&& (*cp == '2'))
return bp_diagnostic_new (bp, 520, NULL,
"already tuned for authentication");
if (!(mechanism = config_get (appconfig,
SASL_LOCAL_MECHANISM)))
return bp_diagnostic_new (bp, 501, NULL, "mechanism undefined");
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il)))
return bp_diagnostic_new (bp, 421, NULL, "out of memory");
memset (il, 0, sizeof *il);
il -> pl_flags = PRO_INITIATOR | PRO_STARTING | PRO_CLOSED;
il -> pl_sent = 1;
memset (p, 0, sizeof *p);
if (!strcasecmp (mechanism, "anonymous")) {
il -> pl_task = PRO_CLIENT_ANON;
if (!(p -> uri = config_get (appconfig, SASL_ANONYMOUS_URI)))
p -> uri = PRO_ANONYMOUS_URI;
p -> piggyback =
sasl_anonymous_client_guts (config_get (appconfig,
SASL_LOCAL_TRACEINFO),
&il -> pl_sdb);
} else if (!strcasecmp (mechanism, "otp")) {
char *authenID,
*authorID;
il -> pl_task = PRO_CLIENT_OTP;
if (!(p -> uri = config_get (appconfig, SASL_OTP_URI)))
p -> uri = PRO_OTP_URI;
if (!(authenID = config_get (appconfig, SASL_LOCAL_USERNAME))) {
lib_free (il);
return bp_diagnostic_new (bp, 501, NULL,
"authentication ID undefined");
}
authorID = config_get (appconfig, SASL_LOCAL_TARGET);
p -> piggyback = sasl_otp_client_guts_1 (authenID, authorID,
&il -> pl_sdb);
} else {
lib_free (il);
return bp_diagnostic_new (bp, 501, NULL, "mechanism unknown: %s",
mechanism);
}
p -> piggyback_length = strlen (p -> piggyback);
config_delete (appconfig, SASL_LOCAL_CODE);
config_delete (appconfig, SASL_LOCAL_REASON);
config_set (appconfig, SASL_LOCAL_MECHANISM, mechanism);
if ((d = bp_start_request (bp, BLU_CHAN0_CHANO_DEFAULT,
BLU_CHAN0_MSGNO_DEFAULT, p, serverName, NULL,
(void *) il)) != NULL)
goto out;
while ((il -> pl_status == NULL)
&& ((il -> pl_flags & (PRO_STARTING|PRO_CLOSED)) != PRO_CLOSED)
&& (bp -> status != INST_STATUS_EXIT))
YIELD ();
if (!il -> pl_status) {
d = bp_diagnostic_new (bp, 450, NULL,
bp -> status != INST_STATUS_EXIT
? "lost channel during tuning"
: "lost session during tuning");
goto out;
}
if (il -> pl_status -> code >= 400)
d = il -> pl_status;
else
bp_diagnostic_destroy (NULL, il -> pl_status);
out: ;
if (!(il -> pl_flags & PRO_CLOSED))
il -> pl_channel -> profile -> user_ptr1 = NULL;
lib_free (il);
return d;
}
/*
* Well-known shared library entry point.
*/
PROFILE_REGISTRATION *sasl_profiles_Init (struct configobj *appconfig) {
char *cp;
PROFILE_REGISTRATION anons,
*anon = &anons,
otps,
*otp = &otps;
pro_debug = 0;
if ((cp = config_get (appconfig, SASL_FAMILY_DEBUG)) != NULL)
pro_debug = atoi (cp);
memset (anon, 0, sizeof *anon);
if (!(anon -> uri = config_get (appconfig, SASL_ANONYMOUS_URI)))
anon -> uri = PRO_ANONYMOUS_URI;
if (!(anon -> initiator_modes = config_get (appconfig,
SASL_ANONYMOUS_IMODES)))
anon -> initiator_modes = "plaintext,encrypted";
if (!(anon -> listener_modes = config_get (appconfig,
SASL_ANONYMOUS_LMODES)))
anon -> listener_modes = "plaintext,encrypted";
anon -> full_messages = 1;
anon -> thread_per_channel = 0;
anon -> proreg_connection_init = pro_connection_init;
anon -> proreg_connection_fin = pro_connection_fin;
anon -> proreg_session_init = pro_session_init;
anon -> proreg_session_fin = pro_session_fin;
anon -> proreg_start_indication = pro_start_indication;
anon -> proreg_start_confirmation = pro_start_confirmation;
anon -> proreg_close_indication = pro_close_indication;
anon -> proreg_close_confirmation = pro_close_confirmation;
anon -> proreg_tuning_reset_indication = pro_tuning_reset_indication;
anon -> proreg_tuning_reset_confirmation = pro_tuning_reset_confirmation;
anon -> proreg_message_available = pro_message_available;
anon -> proreg_window_full = pro_window_full;
memcpy (otp, anon, sizeof *otp);
if (!(otp -> uri = config_get (appconfig, SASL_OTP_URI)))
otp -> uri = PRO_OTP_URI;
if (!(otp -> initiator_modes = config_get (appconfig, SASL_OTP_IMODES)))
otp -> initiator_modes = "plaintext,encrypted";
if (!(otp -> listener_modes = config_get (appconfig, SASL_OTP_LMODES)))
otp -> listener_modes = "plaintext,encrypted";
if ((anon = bp_profile_registration_clone (NULL, anon)) != NULL)
anon -> next = bp_profile_registration_clone (NULL, otp);
return anon;
}
--- NEW FILE: sasl-profiles.h ---
/*
* Copyright (c) 2001 Invisible Worlds, Inc. All rights reserved.
*
* The contents of this file are subject to the Blocks Public License (the
* "License"); You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at http://www.beepcore.org/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*/
/*
* $Id: sasl-profiles.h,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/*
initiator usage:
1. pr = sasl_profiles_Init (appconfig)
2. establish session using pr
3. d = sasl_login (...)
if d is non-NULL, you lose
listener usage:
1. pr = sasl_profiles_Init (appconfig)
2. establish session using pr
*/
#ifndef SASL_PROFILES_H
#define SASL_PROFILES_H 1
/* includes */
#include <beepcore-c/bp_wrapper.h>
#include <beepcore-c/bp_config.h>
#include <beepcore-c/tuning.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name The SASL ANONYMOUS and OTP profiles
**/
/*@{*/
/* keys for configuration package */
/**
* URI to use for the SASL ANONYMOUS profile,
* defaults to <b>"http://iana.org/beep/SASL/ANONYMOUS"</b>.
**/
#define SASL_ANONYMOUS_URI "beep profiles sasl_anon uri"
/**
* Initiator modes for the SASL ANONYMOUS profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SASL_ANONYMOUS_IMODES "beep profiles sasl_anon initiator_modes"
/**
* Listener modes for the SASL ANONYMOUS profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SASL_ANONYMOUS_LMODES "beep profiles sasl_anon listener_modes"
/**
* URI to use for the SASL OTP profile,
* defaults to <b>"http://iana.org/beep/SASL/OTP"</b>.
**/
#define SASL_OTP_URI "beep profiles sasl_otp uri"
/**
* Initiator modes for the SASL OTP profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SASL_OTP_IMODES "beep profiles sasl_otp initiator_modes"
/**
* Listener modes for the SASL OTP profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SASL_OTP_LMODES "beep profiles sasl_otp listener_modes"
/**
* The directory where the OTP database is kept,
* defaults to <b>"/tmp"</b>.
**/
#define SASL_OTP_DIRECTORY "beep profiles sasl_otp directory"
/**
* Enables debug mode for the SASL family of profiles,
* defaults to <b>"0"</b>.
**/
#define SASL_FAMILY_DEBUG "beep profiles sasl debug"
/**
* Trace information for SASL ANONYMOUS.
**/
#define SASL_LOCAL_TRACEINFO "beep identity local traceinfo"
/* module entry points */
/**
* Well-known entry point for the SASL ANONYMOUS and OTP profiles.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>SASL_ANONYMOUS_URI/SASL_OTP_URI</dt>
* <dd>The registration URI for the profile (optional).</dd>
*
* <dt>SASL_ANONYMOUS_IMODES/SASL_OTP_IMODES</dt>
* <dd>The <i>initiator_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>SASL_ANONYMOUS_LMODES/SASL_OTP_LMODES</dt>
* <dd>The <i>listener_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>SASL_OTP_DIRECTORY</dt>
* <dd>The directory where OTP information is kept,
* defaults to <b>"/tmp"</b>.</dd>
*
* <dt>SASL_FAMILY_DEBUG</dt>
* <dd>A non-zero value to enable debugging (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a linked-list of profile-registration structures.
**/
extern struct PROFILE_REGISTRATION* sasl_profiles_Init(struct configobj* appconfig);
/**
* Tune using SASL, and update the connection's
* {@link configobj configuration} structure accordingly.
*
* @param bp A pointer to the connection structure.
* <p>
* Input Keys:
* <blockquote><dl>
* <dt>SASL_LOCAL_MECHANISM</dt>
* <dd>One of: <b>"anonymous"</b>, <b>"otp"</b>.</dd>
*
* <dt>SASL_LOCAL_TRACEINFO</t>
* <dd>Trace information for SASL ANONYMOUS.</dd>
*
* <dt>SASL_LOCAL_USERNAME</dt>
* <dd>The SASL authentication-identity.</dd>
*
* <dt>SASL_LOCAL_TARGET</dt>
* <dd>The SASL authorization-identity.</dd>
*
* <dt>SASL_LOCAL_PASSPHRASE</dt>
* <dd>The passphrase for the authentication-identity.</dd>
* </dl></blockquote>
* <p>
* Output Keys:
* <blockquote><dl>
* <dt>SASL_LOCAL_MECHANISM</dt>
* <dd>The SASL mechanism used for authentication.</dd>
*
* <dt>SASL_LOCAL_CODE</dt>
* <dd>The resulting status code.
* Consult \URL[Section 8 of RFC 3080]{http://www.beepcore.org/beepcore/docs/rfc3080.jsp#reply-codes}
* for an (incomplete) list.</dd>
*
* <dt>SASL_LOCAL_REASON</dt>
* <dd>A textual message corresponding to <b>SASL_LOCAL_CODE</b></dd>
* </dl></blockquote>
*
* @param serverName The value to use for the <i>serverName</i> attribute
* of the <start> element, or <b>NULL</b>.
*
* @return On failure, a pointer to a {@link diagnostic diagnostic} structure
* explaining the reason
* (which should subsequently be destroyed by calling
* {@link bp_diagnostic_destroy bp_diagnostic_destroy}).
**/
extern struct diagnostic* sasl_login(BP_CONNECTION* bp,
char* serverName);
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
--- NEW FILE: syslog-raw.c ---
/* profile for SYSLOG reliable RAW */
/*
* $Id: syslog-raw.c,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
#define BEEPD
/* includes */
#include <string.h>
#include "syslog-raw.h"
#include <beepcore-c/logutil.h>
/* defines and typedefs */
#define PRO_RAW_URI "http://iana.org/beep/SYSLOG/RAW"
#define DEFAULT_CONTENT_TYPE "\r\n"
typedef struct pro_localdata {
int pl_flags; /* mode flags */
#define PRO_INITIATOR (1<<0) /* either initiator */
#define PRO_LISTENER (1<<1) /* or listener */
#define PRO_ONCEONLY (1<<2) /* report only first problem */
#define PRO_READY (1<<3) /* ready for sr_log/sr_fin */
#define PRO_ABORTED (1<<4) /* the session is aborting */
long pl_msgNo; /* when answering a MSG */
long pl_ansNo; /* .. */
PROFILE_INSTANCE
*pl_pi; /* hook to wrappers */
char *pl_serverName; /* what you'd think */
sr_callback pl_callback; /* application callback */
void *pl_clientData; /* .. */
} PRO_LOCALDATA;
/* statics */
static int pro_debug;
static void pro_upcall (PRO_LOCALDATA *il,
int code,
char *message);
static DIAGNOSTIC *
pro_send_start (BP_CONNECTION *bp,
PRO_LOCALDATA *il);
static void pro_send_error (PROFILE_INSTANCE *pi,
long msgNo,
int code,
char *language,
char *diagnostic);
static void pro_syslog (PRO_LOCALDATA *il,
char *buffer,
int size);
/* profile methods */
/*
first four methods are invoked when channels are not-yet/no-longer
instantiated
success: return NULL
failure: return char *reason
*/
/* invoked when wrapper tries to register the profile
do process-wide initialization
on failure, the wrapper doesn't register the profile
*/
static char *
pro_connection_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "SR connection_init\n");
fflush (stderr);
}
return NULL;
}
/* invoked if profile is about to be made available for the session
do session-wide initialization
on failure, the wrapper makes no further calls to the profile for
the duration of the session
*/
static char *
pro_session_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "SR session_init: role='%c' mode=\"%s\"\n",
bp -> role, bp -> mode);
fflush (stderr);
}
return NULL;
}
/* invoked just before the session is released
do session-wide finalization
return value is ignored by wrapper
*/
static char *
pro_session_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "SR session_fin\n");
fflush (stderr);
}
return NULL;
}
/* invoked just before wrapper is destroyed
do process-wide finalization
return value is ignored by wrapper
*/
static char *
pro_connection_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "SR connection_fin\n");
fflush (stderr);
}
return NULL;
}
/* next four methods are invoked when a session/channel starts */
/* invoked when the peer sends a greeting
listener: do nothing
initiator: clone PRO_LOCALDATA and start a channel,
or tell the application why not
*/
static void
pro_greeting_notification (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp,
char status) {
DIAGNOSTIC *d;
PRO_LOCALDATA *pl = pr -> user_ptr,
*il;
if (pro_debug) {
fprintf (stderr, "SR greeting_notification status=%c\n",
status);
fflush (stderr);
}
if (pl -> pl_flags & PRO_LISTENER)
return;
switch (status) {
case PROFILE_PRESENT:
break;
case PROFILE_ABSENT:
pro_upcall (pl, 500, "greeting: profile not present");
return;
case GREETING_ERROR:
pro_upcall (pl, 500, "greeting: got error");
return;
}
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il))) {
pro_upcall (pl, 500, "SR greeting: out of memory");
return;
}
memcpy (il, pl, sizeof *il);
if ((d = pro_send_start (bp, il)) != NULL) {
pro_upcall (pl, d -> code, d -> message);
bp_diagnostic_destroy (bp, d);
lib_free (il);
}
}
/* invoked when the peer asks to start a channel
listener: ignore any piggyback'd data
clone PRO_LOCALDATA and accept it
or tell the application why not
initiator: decline it
*/
static void
pro_start_indication (PROFILE_INSTANCE *pi,
PROFILE *po) {
long wsize;
char *buffer,
*cp;
DIAGNOSTIC ds,
*d = &ds;
PRO_LOCALDATA *pl = pi -> channel -> profile_registration
-> user_ptr,
*il;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "SR start_indication: piggyback=\"%s\"\n",
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
memset (d, 0, sizeof *d);
if (pl -> pl_flags & PRO_INITIATOR) {
memset (d, 0, sizeof *d);
d -> code = 521;
d -> message = "not available";
bpc_start_response (pi -> channel, po, d);
return;
}
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il))) {
pro_upcall (pl, d -> code = 421, d -> message = "out of memory");
bpc_start_response (pi -> channel, po, d);
return;
}
memcpy (il, pl, sizeof *il);
il -> pl_pi = pi, pi -> user_ptr1 = il;
bpc_start_response (pi -> channel, po, NULL);
if ((cp = config_get (appconfig, SYSLOG_RAW_WINDOWSIZE))
&& (wsize = (long) atol (cp)) > 4096)
(void) bpc_set_channel_window (pi -> channel, wsize);
if (!(buffer = bpc_buffer_allocate (pi -> channel,
sizeof DEFAULT_CONTENT_TYPE - 1))) {
pro_upcall (il, 500, "SR start: out of memory");
return;
}
strcpy (buffer, DEFAULT_CONTENT_TYPE);
bpc_send (pi -> channel, BLU_FRAME_TYPE_MSG, BLU_FRAME_MSGNO_UNUSED,
BLU_FRAME_IGNORE_ANSNO, BLU_FRAME_COMPLETE, buffer,
strlen (buffer));
(*il -> pl_callback) ((void *) il, 350, NULL, il -> pl_clientData);
}
/* invoked when a our request to start a channel has resulted in the channel starting
remember PRO_LOCALDATA passed as clientData
*/
static void
pro_start_confirmation (void *clientData,
PROFILE_INSTANCE *pi,
PROFILE *po) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (pro_debug) {
fprintf (stderr, "SR start_confirmation: piggyback=\"%s\"\n",
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
il -> pl_pi = pi, pi -> user_ptr1 = il;
}
/* initiator only: invoked when a response is received to our request to
start a channel, either from pro_greeting_notification
(the first time we start the channel) or
pro_close_confirmation (when we start the channel again
after sr_sync)
failure: tell the application
*/
static void
pro_start_callback (void *clientData,
CHANNEL_INSTANCE *ci,
DIAGNOSTIC *error) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (error) {
pro_upcall (il, error -> code, error -> message);
lib_free (il);
}
}
/* next three methods are invoked when a session/channel closes */
/*
invoked when we or the peer asks to close a session/channel
(or perhaps due to transport problem, etc.)
always accept it
*/
static void
pro_close_indication (PROFILE_INSTANCE *pi,
DIAGNOSTIC *request,
char origin,
char scope) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (pro_debug) {
fprintf (stderr,
"SR close_indication: request=[%d] \"%s\" origin=%c scope=%c\n",
request -> code, request -> message ? request -> message
: "<NULL>",
origin, scope);
fflush (stderr);
}
switch (scope) {
case PRO_ACTION_SESSION:
case PRO_ACTION_CHANNEL:
break;
case PRO_ACTION_ABORT:
default:
il -> pl_flags |= PRO_ABORTED;
break;
}
il -> pl_flags &= ~PRO_READY;
bpc_close_response (pi -> channel, NULL);
}
/* invoked when we know whether the channel has finally closed or not
(regardless of who requested it)
if nothing happened, do nothing
initiator: if flushing a channel, start another one
otherwise, tell the application we're done
*/
static void
pro_close_confirmation (PROFILE_INSTANCE *pi,
char status,
DIAGNOSTIC *error,
char origin,
char scope) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (pro_debug) {
if (error)
fprintf (stderr,
"SR close_confirmation: status=%c error=[%d] \"%s\" origin=%c scope=%c\n",
status, error -> code, error -> message ? error -> message
: "<NULL>",
origin, scope);
else
fprintf (stderr,
"SR close_confirmation: status=%c no error origin=%c scope=%c\n",
status, origin, scope);
fflush (stderr);
}
if (status != PRO_ACTION_SUCCESS) {
if (il -> pl_flags & PRO_INITIATOR)
il -> pl_flags |= PRO_READY;
return;
}
pi -> user_ptr1 = NULL;
if (il -> pl_flags & PRO_ABORTED)
pro_upcall (il, 421, "session aborted");
else
pro_upcall (il, 220, NULL);
lib_free (il);
}
/* listener: invoked when a response is received to pro_message_available's
request to close the channel
success: do nothing
failure: tell the application
*/
static void
pro_close_callback (void *clientData,
CHANNEL_INSTANCE *ci,
DIAGNOSTIC *error) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (error)
pro_upcall (il, error -> code, error -> message);
}
/* next two methods are invoked on tuning resets */
/* invoked when the local peer is about to do a tuning reset */
static void
pro_tuning_reset_indication (PROFILE_INSTANCE *pi) {
if (pro_debug) {
fprintf (stderr, "SR tuning_reset_indication\n");
fflush (stderr);
}
}
/* invoked when we know whether the tuning reset occurred */
static void
pro_tuning_reset_confirmation (PROFILE_INSTANCE *pi,
char status) {
if (pro_debug) {
fprintf (stderr, "SR tuning_reset_confirmation: status=%c\n", status);
fflush (stderr);
}
pro_close_confirmation (pi, status, NULL, PRO_ACTION_LOCAL,
PRO_ACTION_SESSION);
}
/* next two methods are invoked on read events */
/* invoked when a message is available to be read
message actions taken by
received listener initiator
-------- -------- ---------
MSG send ERR tell the application we're ready
for sr_log
ANS parse and pass up n/a
NUL close channel n/a
RPY/ERR abort channel n/a
*/
static void
pro_message_available (PROFILE_INSTANCE *pi) {
int code = 200,
size;
char *buffer;
DIAGNOSTIC *d;
FRAME *f;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
BP_CONNECTION *bp = pi -> channel -> conn;
if (!(f = bpc_query_message (pi -> channel, BLU_QUERY_ANYTYPE,
BLU_QUERY_ANYMSG, BLU_QUERY_ANYANS)))
return;
if (pro_debug) {
fprintf (stderr,
"SR message_available: type=%c number=%ld answer=%ld more=%c size=%ld\n",
f -> msg_type, f -> message_number, f -> answer_number,
f -> more, f -> size);
fprintf (stderr, f -> size > 75 ? "%-75.75s...\n" : "%s\n",
f -> payload);
fflush (stderr);
}
switch (f -> msg_type) {
case BLU_FRAME_TYPE_MSG:
if (il -> pl_flags & PRO_INITIATOR) {
il -> pl_msgNo = f -> message_number;
il -> pl_ansNo = -1;
il -> pl_flags |= PRO_READY;
(*il -> pl_callback) ((void *) il, 350, NULL, il -> pl_clientData);
} else
pro_send_error (pi, f -> message_number, 500, NULL,
"not expecting MSG");
break;
case BLU_FRAME_TYPE_ANS:
size = bpc_frame_aggregate (pi -> channel, f, &buffer);
if (buffer) {
pro_syslog (il, buffer, size);
bpc_buffer_destroy (pi -> channel, buffer);
} else
bp_log (bp, LOG_PROF, 5,
"SR message: out of memory reading ANS");
break;
case BLU_FRAME_TYPE_RPY:
case BLU_FRAME_TYPE_ERR:
code = 500;
il -> pl_flags |= PRO_ABORTED;
/* and fall... */
case BLU_FRAME_TYPE_NUL:
if ((d = bpc_close_request (pi -> channel, BLU_CHAN0_MSGNO_DEFAULT,
code, NULL,
code == 500 ? "protocol error" : NULL,
pro_close_callback,
(void *) il)) != NULL) {
pro_upcall (il, d -> code, d -> message);
bp_diagnostic_destroy (bp, d);
}
break;
default:
break;
}
bpc_message_destroy (pi -> channel, f);
}
/* invoked when input queue is full, and the message is incomplete
could avoid this if we used the frame-based interface
however that would mean we'd have to be able to re-assemble multiple
ANS messages and add a lot of state to pro_syslog...
*/
static void
pro_window_full (PROFILE_INSTANCE *pi) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (pro_debug) {
fprintf (stderr, "SR window_full\n");
fflush (stderr);
}
pro_upcall (il, 421, "session blocked, increase window size");
}
/* helper methods */
/* invoke the application's callback, at most once */
static void
pro_upcall (PRO_LOCALDATA *il,
int code,
char *message) {
if (!(il -> pl_flags & PRO_ONCEONLY)) {
il -> pl_flags |= PRO_ONCEONLY;
(*il -> pl_callback) (NULL, code, message, il -> pl_clientData);
}
}
/* initiator: start a channel */
static DIAGNOSTIC *
pro_send_start (BP_CONNECTION *bp,
PRO_LOCALDATA *il) {
PROFILE ps,
*p = &ps;
struct configobj *appconfig = bp_get_config (bp);
memset (p, 0, sizeof *p);
if (!(p -> uri = config_get (appconfig, SYSLOG_RAW_URI)))
p -> uri = PRO_RAW_URI;
p -> piggyback_length = strlen (p -> piggyback = "");
return bp_start_request (bp, BLU_CHAN0_CHANO_DEFAULT,
BLU_CHAN0_MSGNO_DEFAULT, p, il -> pl_serverName,
pro_start_callback, (void *) il);
}
/* listener: send an ERR if we receive a MSG */
static void
pro_send_error (PROFILE_INSTANCE *pi,
long msgNo,
int code,
char *language,
char *diagnostic) {
char *buffer = bpc_error_allocate (pi -> channel, code, language,
diagnostic);
if (buffer)
bpc_send (pi -> channel, BLU_FRAME_TYPE_ERR, msgNo,
BLU_FRAME_IGNORE_ANSNO, BLU_FRAME_COMPLETE, buffer,
strlen (buffer));
else
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"SR message: out of memory sending ERR");
}
/* listener: parse syslog entries and pass to application */
static void
pro_syslog (PRO_LOCALDATA *il,
char *buffer,
int size) {
int twiceP;
char *cp,
*dp;
/* skip past MIME headers to find beginning of data, two possibilities:
Content-Type: ...\r\n[...\r\n]\r\n
\r\n
*/
cp = buffer;
twiceP = 1;
while (size-- > 0) {
char c = *cp++;
switch (c) {
case '\r':
if ((size > 0) && (*cp == '\n'))
cp++, size--;
twiceP++;
break;
case '\n':
twiceP++;
break;
default:
twiceP = 0;
break;
}
if (twiceP > 1)
break;
}
dp = cp;
while (size > 0) {
char c = *cp;
switch (c) {
case '\r':
case '\n':
*cp = '\0';
if (cp > dp)
(*il -> pl_callback) ((void *) il, cp - dp, dp,
il -> pl_clientData);
cp++, size--;
if ((size > 0) && (*cp == '\n'))
cp++, size--;
dp = cp;
break;
default:
cp++, size--;
break;
}
}
if (cp > dp)
(*il -> pl_callback) ((void *) il, cp - dp, dp, il -> pl_clientData);
}
/*
* Well-known shared library entry point.
*/
PROFILE_REGISTRATION *
sr_Init (struct configobj *appconfig) {
char *cp;
PRO_LOCALDATA *pl;
PROFILE_REGISTRATION *pr;
pro_debug = 0;
if ((cp = config_get (appconfig, SYSLOG_RAW_DEBUG)) != NULL)
pro_debug = atoi (cp);
if (!(pr = (PROFILE_REGISTRATION *) lib_malloc (sizeof *pr +
sizeof *pl))) {
log_line (LOG_PROF, 6, "unable to allocate PR");
return NULL;
}
memset (pr, 0, sizeof *pr);
if (!(pr -> uri = config_get (appconfig, SYSLOG_RAW_URI)))
pr -> uri = PRO_RAW_URI;
if (!(pr -> initiator_modes = config_get (appconfig, SYSLOG_RAW_IMODES)))
pr -> initiator_modes = "plaintext,encrypted";
if (!(pr -> listener_modes = config_get (appconfig, SYSLOG_RAW_LMODES)))
pr -> listener_modes = "plaintext,encrypted";
pr -> full_messages = 1;
pr -> thread_per_channel = 0;
pr -> proreg_connection_init = pro_connection_init;
pr -> proreg_connection_fin = pro_connection_fin;
pr -> proreg_session_init = pro_session_init;
pr -> proreg_session_fin = pro_session_fin;
pr -> proreg_greeting_notification = pro_greeting_notification;
pr -> proreg_start_indication = pro_start_indication;
pr -> proreg_start_confirmation = pro_start_confirmation;
pr -> proreg_close_indication = pro_close_indication;
pr -> proreg_close_confirmation = pro_close_confirmation;
pr -> proreg_tuning_reset_indication = pro_tuning_reset_indication;
pr -> proreg_tuning_reset_confirmation = pro_tuning_reset_confirmation;
pr -> proreg_message_available = pro_message_available;
pr -> proreg_window_full = pro_window_full;
pr -> user_ptr = pl = (PRO_LOCALDATA *) (((char *) pr) + sizeof *pr);
memset (pl, 0, sizeof *pl);
return pr;
}
/* invoked by a listening application
pr - non-NULL result from sr_Init
callback - pointer to callback procedure
clientData - opaque pointer
*/
void
sr_listener (PROFILE_REGISTRATION *pr,
sr_callback callback,
void *clientData) {
PRO_LOCALDATA *pl = pr -> user_ptr;
pl -> pl_flags = PRO_LISTENER;
pl -> pl_callback = callback;
pl -> pl_clientData = clientData;
}
/* invoked by an initiating application
pr - non-NULL result from sr_Init
callback - pointer to callback procedure
clientData - opaque pointer
*/
void
sr_initiator (PROFILE_REGISTRATION *pr,
char *serverName,
sr_callback callback,
void *clientData) {
PRO_LOCALDATA *pl = pr -> user_ptr;
pl -> pl_flags = PRO_INITIATOR;
pl -> pl_serverName = serverName;
pl -> pl_callback = callback;
pl -> pl_clientData = clientData;
}
/* initiator: send syslog entry */
int
sr_log (void *v,
char *entry) {
int i;
char *buffer,
*ep;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) v;
PROFILE_INSTANCE *pi;
if (!(pi = il -> pl_pi)) {
lib_free (il);
return SR_DONE;
}
if (!(il -> pl_flags & PRO_READY))
return SR_BUSY;
if ((i = strlen (ep = entry)) > 0) {
ep += i - 1;
if (*ep == '\n')
ep--, i--;
if ((i > 0) && (*ep == '\r'))
i--;
}
if (i == 0)
return SR_OK;
if (!(buffer = bpc_buffer_allocate (pi -> channel,
i
+ (sizeof DEFAULT_CONTENT_TYPE - 1))))
return SR_ERROR;
sprintf (buffer, "%s%*.*s", DEFAULT_CONTENT_TYPE, i, i, entry);
if (++il -> pl_ansNo > 2147483647)
il -> pl_ansNo = 0;
bpc_send (pi -> channel, BLU_FRAME_TYPE_ANS, il -> pl_msgNo,
il -> pl_ansNo, BLU_FRAME_COMPLETE, buffer, strlen (buffer));
return SR_OK;
}
/* initiator: drain entries, optionally closing channel */
int
sr_fin (void *v) {
char *buffer;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) v;
PROFILE_INSTANCE *pi;
if (!(pi = il -> pl_pi)) {
lib_free (il);
return SR_DONE;
}
if (!(il -> pl_flags & PRO_READY))
return SR_BUSY;
if (!(buffer = bpc_buffer_allocate (pi -> channel, 0)))
return SR_ERROR;
il -> pl_flags &= ~PRO_READY;
bpc_send (pi -> channel, BLU_FRAME_TYPE_NUL, il -> pl_msgNo,
BLU_FRAME_IGNORE_ANSNO, BLU_FRAME_COMPLETE, buffer, 0);
return SR_OK;
}
#ifdef BEEPD
static void
callback_listener (void *v,
int code,
char *diagnostic,
void *clientData) {
fprintf (stderr,
"SR callback_listener v=0x%x code=%d\n diagnostic=\"%s\"\n",
(unsigned int) v, code, diagnostic);
fflush (stderr);
}
PROFILE_REGISTRATION *
sr_Init_listener (struct configobj *appconfig) {
PROFILE_REGISTRATION *pr = sr_Init (appconfig);
if (pr)
sr_listener (pr, callback_listener, NULL);
return pr;
}
#endif
--- NEW FILE: syslog-raw.h ---
/* profile for SYSLOG reliable RAW */
/*
* $Id: syslog-raw.h,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/*
initiator usage:
1. pr = sr_Init (appconfig)
sr_initiator (pr, callback, clientData)
2. establish session using pr
3. await invocation of callback (v, code, diagnostic, clientData)
if v is NULL:
look at code/diagnostic for reason
release session, etc.
otherwise:
remember v
4. for 0..I: sr_log (v, msg)
5. sr_fin (v)
6. await invocation of callback (v, code, diagnostic, clientData)
look at code/diagnostic for success/failure
listener usage:
1. pr = sr_Init (appconfig)
sr_listener (pr, callback, clientData)
2. establish session using pr
3. forever: await invocation of callback (v, code, diagnostic, clientData)
if v is NULL:
look at code/diagnostic for reason
release session, etc.
if diagnostic is NULL:
we're now plugged in (may happen more than once)
otherwise:
give diagnostic (of length code) to logging system
*/
#ifndef SR_PROFILE_H
#define SR_PROFILE_H 1
/* includes */
#include <beepcore-c/bp_config.h>
#include <beepcore-c/bp_wrapper.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name The SYSLOG reliable RAW profile
**/
/*@{*/
/* typedefs */
/**
* Prototype for the application callback
*
* @param v A profile-provided pointer to be used for future calls to
* {@link sr_log sr_log} or {@link sr_fin sr_fin}.
* If <b>NULL</b>, then the channel has closed, and the session may
* be released.
*
* @param code A numeric result code.
* Consult \URL[Section 8 of RFC 3080]{http://www.beepcore.org/beepcore/docs/rfc3080.jsp#reply-codes}
* for an (incomplete) list.
*
* @param diagnostic A textual message corresopnding to the <i>code</i> parameter.
*
* @param clientData The user-supplied pointer provided to either
* {@link sr_initiator sr_initiator} or
* {@link sr_listener sr_listener}.
**/
typedef void (*sr_callback) (void *v,
int code,
char *message,
void *clientData);
/* keys for configuration package */
/**
* URI to use for the SYSLOG reliable RAW profile,
* defaults to <b>"http://iana.org/beep/SYSLOG/RAW"</b>.
**/
#define SYSLOG_RAW_URI "beep profiles syslog_raw uri"
/**
* Initiator modes for the SYSLOG reliable RAW profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SYSLOG_RAW_IMODES "beep profiles syslog_raw initiator_modes"
/**
* Listener modes for the SYSLOG reliable RAW profile,
* defaults to <b>"plaintext,encrypted"</b>.
**/
#define SYSLOG_RAW_LMODES "beep profiles syslog_raw listener_modes"
/**
* User-specified window size for the SYSLOG reliable RAW profile.
**/
#define SYSLOG_RAW_WINDOWSIZE "beep profiles syslog_raw window_size"
/**
* Enables debug mode for the SYSLOG reliable RAW profile,
* defaults to <b>"0"</b>.
**/
#define SYSLOG_RAW_DEBUG "beep profiles syslog_raw debug"
/* module entry points */
/**
* Well-known entry point for the SYSLOG reliable RAW profile.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>SYSLOG_RAW_URI</dt>
* <dd>The registration URI for the profile (optional).</dd>
*
* <dt>SYSLOG_RAW_IMODES</dt>
* <dd>The <i>initiator_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>SYSLOG_RAW_LMODES</dt>
* <dd>The <i>listener_modes</i> to use when registering the profile
* (optional).</dd>
*
* <dt>SYSLOG_RAW_DEBUG</dt>
* <dd>A non-zero value to enable debugging (optional).</dd>
* </dl></blockquote>
*
* @return A pointer to a profile-registration structure.
**/
extern PROFILE_REGISTRATION* sr_Init (struct configobj* appconfig);
/* listener routines */
/**
* Configures a profile-registration structure to behave as a listener.
* <p>
* Call this before registering the profile with the wrapper
* (e.g., before calling {@link tcp_bp_listen tcp_bp_listen}.)
*
* @param pr A pointer to the profile-registration returned by
* {@link sr_Init sr_Init}.
*
* @param callback The routine to invoke on an event
* (cf., {@link (*sr_callback) callback}).
*
* @param clientData A user-supplied pointer.
**/
extern void sr_listener (PROFILE_REGISTRATION* pr,
sr_callback callback,
void* clientData);
/* initiator routines */
/**
* Configures a profile-registration structure to behave as an initiator.
* <p>
* Call this before registering the profile with the wrapper
* (e.g., before calling {@link tcp_bp_connect tcp_bp_connect}.)
*
* @param pr A pointer to the profile-registration returned by
* {@link sr_Init sr_Init}.
*
* @param serverName The value to use for the <i>serverName</i> attribute
* of the <start> element, or <b>NULL</b>.
*
* @param callback The routine to invoke on an event
* (cf., {@link (*sr_callback) callback}).
*
* @param clientData A user-supplied pointer.
**/
extern void sr_initiator (PROFILE_REGISTRATION* pr,
char* serverName,
sr_callback callback,
void* clientData);
/**
* Sends an entry to log.
*
* @param v An opaque pointer returned by the last
* {@link (*sr_callback) callback}.
*
* @param entry The entries to log.
*
* @return One of:
* <ul>
* <li>{@link SR_OK SR_OK}</li>
* <li>{@link SR_ERROR SR_ERROR}</li>
* <li>{@link SR_BUSY SR_BUSY}</li>
* <li>{@link SR_DONE SR_DONE}</li>
* </ul>
**/
extern int sr_log (void* v,
char* entry);
/**
* Closes the SYSLOG reliable RAW channel.
*
* @param v An opaque pointer returned by the last
* {@link (*sr_callback) callback}.
*
* @return One of:
* <ul>
* <li>{@link SR_OK SR_OK}</li>
* <li>{@link SR_ERROR SR_ERROR}</li>
* <li>{@link SR_BUSY SR_BUSY}</li>
* <li>{@link SR_DONE SR_DONE}</li>
* </ul>
**/
extern int sr_fin (void* v);
/**
* no problema
**/
#define SR_OK 0
/**
* error performing task
**/
#define SR_ERROR (-1)
/**
* still doing {@link sr_log sr_log}.
**/
#define SR_BUSY (-2)
/**
* channel is closed
**/
#define SR_DONE (-3)
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
--- NEW FILE: tls-profile.c ---
/*
* Copyright (c) 2001 Invisible Worlds, Inc. All rights reserved.
*
* The contents of this file are subject to the Blocks Public License (the
* "License"); You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at http://www.beepcore.org/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*/
/*
* $Id: tls-profile.c,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/* includes */
#ifndef WIN32
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#else
#define sem_t HANDLE
#endif
#include <beepcore-c/tls-profile.h>
#include <beepcore-c/bp_notify.h>
#include <beepcore-c/logutil.h>
#include <beepcore-c/workthread.h>
#include <beepcore-c/bp_slist_utility.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <beepcore-c/bp_fiostate.h>
#include <beepcore-c/bp_fpollmgr.h>
/* defines and typedefs */
#define PRO_TLS_URI "http://iana.org/beep/TLS"
typedef struct pro_localdata {
int pl_flags;
#define PRO_INITIATOR (1<<0)
#define PRO_STARTING (1<<1)
#define PRO_CLOSED (1<<2)
CHANNEL_INSTANCE *pl_channel;
DIAGNOSTIC *pl_status;
SSL_CTX *pl_ctx;
} PRO_LOCALDATA;
/* statics */
static int pro_debug;
static WORKQUEUE* notifyqueue = NULL;
static void tls_tuning_reset_server_handshake (PROFILE_INSTANCE *pi);
static void tls_tuning_reset_notify (void* data);
static void tls_tuning_reset_client_handshake (PROFILE_INSTANCE *pi);
static void tls_set_success (PROFILE_INSTANCE *pi,
SSL *ssl);
static void tls_set_failure (PROFILE_INSTANCE *pi,
int error);
static int tls_reader (void *handle,
char *buffer,
int size);
static int tls_writer (void *handle,
char *buffer,
int size);
#if 0
static int tls_destroy (void *handle);
#endif
/* profile methods */
static char *
pro_connection_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "TLS connection_init\n");
fflush (stderr);
}
return NULL;
}
static char *
pro_session_init (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "TLS session_init: role='%c' mode=\"%s\"\n",
bp -> role, bp -> mode);
fflush (stderr);
}
return NULL;
}
static char *
pro_session_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "TLS session_fin\n");
fflush (stderr);
}
return NULL;
}
static char *
pro_connection_fin (PROFILE_REGISTRATION *pr,
BP_CONNECTION *bp) {
if (pro_debug) {
fprintf (stderr, "TLS connection_fin\n");
fflush (stderr);
}
return NULL;
}
static void
pro_start_indication (PROFILE_INSTANCE *pi,
PROFILE *po) {
char certbuf[BUFSIZ],
*certfile,
*cp,
*dir,
keybuf[BUFSIZ],
*keyfile,
*serverName;
DIAGNOSTIC ds,
*d = &ds;
PROFILE ps,
*p = &ps;
PRO_LOCALDATA *il;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
struct cfgsearchobj *cs;
if (!(serverName = bp_server_name (pi -> channel -> conn)))
serverName = pi -> channel -> inbound -> server_name;
if (pro_debug) {
fprintf (stderr,
"TLS start_indication: servername=\"%s\" piggyback=\"%s\"\n",
serverName ? serverName : "<NULL>",
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
memset (p, 0, sizeof *p);
p -> uri = po -> uri;
memset (d, 0, sizeof *d);
d -> code = 421;
if (((cp = config_get (appconfig, SASL_LOCAL_CODE)) != NULL)
&& (*cp == '2')) {
d -> code = 520;
d -> message = "already tuned for authentication";
bpc_start_response (pi -> channel, p, d);
return;
}
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il))) {
d -> message = "out of memory";
bpc_start_response (pi -> channel, p, d);
return;
}
certfile = keyfile = NULL;
if ((dir = config_get (appconfig, TLS_CERTDIR))
&& !(strstr (serverName, "/"))
&& !(strstr (serverName, ".."))) {
sprintf (certbuf, "%s/%s", dir, serverName);
#ifndef WIN32
if (access (certbuf, R_OK) >= 0) {
certfile = keyfile = certbuf;
if ((dir = config_get (appconfig, TLS_KEYDIR)) != NULL) {
sprintf (keybuf, "%s/%s", dir, serverName);
if (access (keybuf, R_OK) >= 0)
keyfile = keybuf;
else
certfile = keyfile = NULL;
}
}
#else
certfile = keyfile = certbuf;
if ((dir = config_get (appconfig, TLS_KEYDIR)) != NULL) {
sprintf (keybuf, "%s/%s", dir, serverName);
keyfile = keybuf;
}
#endif
}
memset (il, 0, sizeof *il);
if (!(il -> pl_ctx = SSL_CTX_new (SSLv23_server_method ()))) {
if (pro_debug)
ERR_print_errors_fp (stderr);
d -> message = "unable to create server context";
} else if (!certfile
&& !(certfile = config_get (appconfig, TLS_CERTFILE))) {
d -> message = "TLS_CERTFILE not present in configuration";
} else if (SSL_CTX_use_certificate_file (il -> pl_ctx, certfile,
SSL_FILETYPE_PEM) <= 0) {
if (pro_debug)
ERR_print_errors_fp (stderr);
d -> message = "unable to use certificate file";
} else if (!keyfile && !(keyfile = config_get (appconfig, TLS_KEYFILE))) {
d -> message = "TLS_KEYFILE not present in configuration";
} else if (SSL_CTX_use_PrivateKey_file (il -> pl_ctx, keyfile,
SSL_FILETYPE_PEM) <= 0) {
if (pro_debug)
ERR_print_errors_fp (stderr);
d -> message = "unable to use private key file";
} else if (!SSL_CTX_check_private_key (il -> pl_ctx)) {
d -> message = "private key does not match certificate's public key";
} else if (po -> piggyback_length == 0)
d = NULL;
else if (strstr (po -> piggyback, "<ready")) {
bp_slist *list;
CHANNEL_INSTANCE *inst;
for (list = pi -> channel -> conn -> channel_instance;
list;
list = list -> next)
{
if ((inst = list -> data) -> channel_number == 0) {
bpc_tuning_reset_request (inst);
break;
}
}
p -> piggyback_length = strlen (p -> piggyback = "<proceed />");
#if 0
err = workqueue_add_item(notifyqueue, tls_tuning_reset_notify, pi);
if (err == 0) {
fiostate_block_read (GET_WRAPPER(pi->channel->conn) -> iostate);
d = NULL;
} else {
d -> message = "unable to wait for channels to become quiescent";
}
#else
fiostate_block_read (GET_WRAPPER(pi->channel->conn) -> iostate);
d = NULL;
#endif
} else
d = bp_diagnostic_new (pi -> channel -> conn, 504, NULL,
"expecting ready element in piggyback");
if (d && d -> message) {
lib_free (il);
} else {
pi -> user_ptr1 = il;
cs = config_search_init (appconfig, PRIVACY_PREFIX, "");
for (cp = config_search_string_firstkey (cs);
cp;
cp = config_search_string_nextkey (cs))
config_delete (appconfig, cp);
config_search_fin (&cs);
}
bpc_start_response (pi -> channel, p, d);
#if 1
workqueue_add_item(notifyqueue, tls_tuning_reset_notify, pi);
#endif
if ((d != NULL) && (d != &ds))
bp_diagnostic_destroy (pi -> channel -> conn, d);
}
static void
pro_start_confirmation (void *clientData,
PROFILE_INSTANCE *pi,
PROFILE *po) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) clientData;
if (pro_debug) {
fprintf (stderr, "TLS start_confirmation: piggyback=\"%s\"\n",
po -> piggyback ? po -> piggyback : "<NULL>");
fflush (stderr);
}
pi -> user_ptr1 = il;
il -> pl_flags &= ~(PRO_STARTING | PRO_CLOSED);
il -> pl_channel = pi -> channel;
if ((po -> piggyback_length > 0) && strstr (po -> piggyback, "<proceed"))
#if 1
tls_tuning_reset_client_handshake (pi);
#else
workqueue_add_item(notifyqueue, tls_tuning_reset_client_handshake, pi);
#endif
else
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, 504, NULL,
"expecting proceed element");
}
static void
pro_close_indication (PROFILE_INSTANCE *pi,
DIAGNOSTIC *request,
char origin,
char scope) {
if (pro_debug) {
fprintf (stderr,
"TLS close_indication: request=[%d] \"%s\" origin=%c scope=%c\n",
request -> code, request -> message ? request -> message
: "<NULL>",
origin, scope);
fflush (stderr);
}
bpc_close_response (pi -> channel, NULL);
}
static void
pro_close_confirmation(PROFILE_INSTANCE *pi,
char status,
DIAGNOSTIC *error,
char origin,
char scope) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (pro_debug) {
if (error)
fprintf (stderr,
"TLS close_confirmation: status=%c error=[%d] \"%s\" origin=%c scope=%c\n",
status, error -> code, error -> message ? error -> message
: "<NULL>",
origin, scope);
else
fprintf (stderr,
"TLS close_confirmation: status=%c no error origin=%c scope=%c\n",
status, origin, scope);
fflush (stderr);
}
if (status != PRO_ACTION_SUCCESS)
return;
if (il) {
if (il -> pl_flags & PRO_INITIATOR)
il -> pl_flags |= PRO_CLOSED;
else {
pi -> user_ptr1 = NULL;
SSL_CTX_free (il -> pl_ctx);
lib_free (il);
}
}
}
static void
pro_tuning_reset_indication (PROFILE_INSTANCE *pi) {
if (pro_debug) {
fprintf (stderr, "TLS tuning_reset_indication\n");
fflush (stderr);
}
}
static void
pro_tuning_reset_confirmation (PROFILE_INSTANCE *pi,
char status) {
if (pro_debug) {
fprintf (stderr, "TLS tuning_reset_confirmation: status=%c\n", status);
fflush (stderr);
}
pro_close_confirmation (pi, status, NULL, PRO_ACTION_LOCAL,
PRO_ACTION_SESSION);
}
static void
pro_message_available(PROFILE_INSTANCE *pi) {
int type;
char *buffer;
FRAME *f;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (!(f = bpc_query_message (pi -> channel, BLU_QUERY_ANYTYPE,
BLU_QUERY_ANYMSG, BLU_QUERY_ANYANS)))
return;
if (pro_debug) {
fprintf (stderr,
"TLS message_available: type=%c number=%ld answer=%ld size=%ld\n",
f -> msg_type, f -> message_number, f -> answer_number,
f -> size);
fprintf (stderr, f -> size > 75 ? "%-75.75s...\n" : "%s\n",
f -> payload);
fflush (stderr);
}
switch (f -> msg_type) {
case BLU_FRAME_TYPE_MSG:
type = BLU_FRAME_TYPE_ERR;
if (il -> pl_flags & PRO_INITIATOR)
buffer = bpc_error_allocate (pi -> channel, 521, NULL,
"client-side only");
else if (!strstr (f -> payload, "<ready")) {
buffer = bpc_error_allocate (pi -> channel, 504, NULL,
"expecting ready element");
} else if ((buffer = bpc_buffer_allocate (pi -> channel,
sizeof "<proceed />"
- 1)) != NULL) {
type = BLU_FRAME_TYPE_RPY;
strcpy (buffer, "<proceed />");
bpc_tuning_reset_request (pi -> channel);
fiostate_block_read(GET_WRAPPER(pi->channel->conn) -> iostate);
}
if (buffer != NULL) {
bpc_send (pi -> channel, type, f -> message_number,
BLU_FRAME_IGNORE_ANSNO, BLU_FRAME_COMPLETE, buffer,
strlen (buffer));
if (type == BLU_FRAME_TYPE_RPY) {
bpc_frame_destroy (pi -> channel, f);
tls_tuning_reset_server_handshake (pi);
return;
}
} else
bp_log (pi -> channel -> conn, LOG_PROF, 5,
"TLS message: out of memory allocating buffer/error");
break;
case BLU_FRAME_TYPE_RPY:
if (strstr (f -> payload, "<proceed")) {
bpc_frame_destroy (pi -> channel, f);
tls_tuning_reset_client_handshake (pi);
return;
}
/* and fall... */
case BLU_FRAME_TYPE_ANS:
case BLU_FRAME_TYPE_NUL:
case BLU_FRAME_TYPE_ERR:
bpc_tuning_reset_complete (pi -> channel, PRO_ACTION_FAILURE,
NULL);
break;
}
bpc_frame_destroy (pi -> channel, f);
}
static void
pro_window_full (PROFILE_INSTANCE *pi) {
DIAGNOSTIC *d;
if (pro_debug) {
fprintf (stderr, "TLS window_full\n");
fflush (stderr);
}
bp_log (pi -> channel -> conn, LOG_PROF, 5, "TLS channel window full!?!");
if (!(d = bpc_close_request (pi -> channel, BLU_CHAN0_MSGNO_DEFAULT, 550,
NULL, "stop misbehaving", NULL, NULL))) {
bp_log (pi -> channel -> conn, LOG_PROF, 4,
"unable to close TLS channel: [%d] %s", d -> code,
d -> message);
bp_diagnostic_destroy (pi -> channel -> conn, d);
}
}
/* helper functions */
static void
tls_tuning_reset_server_handshake (PROFILE_INSTANCE *pi) {
int error;
char *cp;
BIO *bio;
SSL *ssl;
BP_CONNECTION *bp = pi -> channel -> conn;
WRAPPER *w = GET_WRAPPER (bp);
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
struct configobj *appconfig = bp_get_config (bp);
struct cfgsearchobj *cs;
if (pro_debug) {
fprintf (stderr, "TLS server_handshake\n");
fflush (stderr);
}
fiostate_unblock_write (w -> iostate);
fiostate_block_read (w -> iostate);
bpc_wait_state_quiescent (pi -> channel);
fiostate_block_read (w -> iostate);
fiostate_block_write (w -> iostate);
ssl = SSL_new (il -> pl_ctx);
bio = BIO_new (BIO_s_socket ());
BIO_set_fd (bio, w -> iostate -> socket, BIO_NOCLOSE);
BIO_set_nbio (bio, 1);
SSL_set_bio (ssl, bio, bio);
do {
error = SSL_get_error (ssl, SSL_accept (ssl));
} while ((error == SSL_ERROR_WANT_READ)
|| (error == SSL_ERROR_WANT_WRITE));
cs = config_search_init (appconfig, SASL_REMOTE_PREFIX, "");
for (cp = config_search_string_firstkey (cs);
cp;
cp = config_search_string_nextkey (cs))
config_delete (appconfig, cp);
config_search_fin (&cs);
if (error != SSL_ERROR_NONE) {
tls_set_failure (pi, error);
SSL_free (ssl);
bpc_tuning_reset_complete (pi -> channel, PRO_ACTION_SUCCESS,
"plaintext");
} else {
tls_set_success (pi, ssl);
bp_new_reader_writer (w -> iostate, tls_reader, ssl, tls_writer,
ssl, 4096, NULL /*tls_destroy*/, NULL);
bpc_tuning_reset_complete (pi -> channel, PRO_ACTION_SUCCESS,
"encrypted");
}
}
static void
tls_tuning_reset_notify (void* data) {
PROFILE_INSTANCE *pi = (PROFILE_INSTANCE*) data;
if (pi -> channel -> conn -> status == INST_STATUS_EXIT)
return;
bp_wait_channel_0_state_quiescent (pi -> channel -> conn);
tls_tuning_reset_server_handshake (pi);
}
static void
tls_tuning_reset_client_handshake (PROFILE_INSTANCE *pi) {
int error;
char *cp;
BIO *bio;
SSL *ssl;
BP_CONNECTION *bp = pi -> channel -> conn;
WRAPPER *w = GET_WRAPPER (bp);
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
struct configobj *appconfig = bp_get_config (bp);
struct cfgsearchobj *cs;
if (pro_debug) {
fprintf (stderr, "TLS client_handshake\n");
fflush (stderr);
}
fiostate_block_read(w->iostate);
fiostate_block_write(w->iostate);
ssl = SSL_new (il -> pl_ctx);
bio = BIO_new (BIO_s_socket ());
BIO_set_fd (bio, w -> iostate -> socket, BIO_NOCLOSE);
BIO_set_nbio (bio, 1);
SSL_set_bio (ssl, bio, bio);
do
{
error = SSL_get_error (ssl, SSL_connect (ssl));
} while ((error == SSL_ERROR_WANT_READ)
|| (error == SSL_ERROR_WANT_WRITE));
il -> pl_flags |= PRO_CLOSED;
cs = config_search_init (appconfig, SASL_REMOTE_PREFIX, "");
for (cp = config_search_string_firstkey (cs);
cp;
cp = config_search_string_nextkey (cs))
config_delete (appconfig, cp);
config_search_fin (&cs);
if (error != SSL_ERROR_NONE) {
tls_set_failure (pi, error);
SSL_free (ssl);
bpc_tuning_reset_complete (pi -> channel, PRO_ACTION_SUCCESS,
"plaintext");
} else {
tls_set_success (pi, ssl);
bp_new_reader_writer(w -> iostate, tls_reader, ssl, tls_writer,
ssl, 4096, NULL /* tls_destroy */, NULL);
bpc_tuning_reset_complete (pi -> channel, PRO_ACTION_SUCCESS,
"encrypted");
}
}
static void
tls_set_success (PROFILE_INSTANCE *pi,
SSL *ssl) {
int bits;
char buffer[BUFSIZ],
*cp;
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
SSL_CIPHER *cipher = SSL_get_current_cipher (ssl);
X509 *x509;
struct configobj *appconfig = bp_get_config (pi -> channel -> conn);
if (pro_debug) {
fprintf (stderr, "tls_set_success\n");
fflush (stderr);
}
if ((x509 = SSL_get_peer_certificate (ssl)) != NULL) {
cp = X509_NAME_oneline (X509_get_subject_name (x509), NULL, 0);
config_set (appconfig, PRIVACY_REMOTE_SUBJECTNAME, cp);
#if 0
/** @todo fix this */
free (cp);
#endif
}
config_set (appconfig, PRIVACY_CIPHER_NAME,
(char *) SSL_CIPHER_get_name (cipher));
config_set (appconfig, PRIVACY_CIPHER_PROTOCOL,
SSL_CIPHER_get_version (cipher));
sprintf (buffer, "%d", SSL_CIPHER_get_bits (cipher, &bits));
config_set (appconfig, PRIVACY_CIPHER_SBITS, buffer);
if (il -> pl_flags & PRO_INITIATOR)
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, 200, NULL,
"tuning successful");
}
static void
tls_set_failure (PROFILE_INSTANCE *pi,
int error) {
PRO_LOCALDATA *il = (PRO_LOCALDATA *) pi -> user_ptr1;
if (il -> pl_flags & PRO_INITIATOR)
il -> pl_status = bp_diagnostic_new (pi -> channel -> conn, 550, NULL,
"openssl returned %d", error);
else
log_line (LOG_PROF, 5, "openssl returned %d", error);
}
static int
tls_reader (void *handle,
char *buffer,
int size) {
SSL *ssl = (SSL *) handle;
return SSL_read (ssl, buffer, size);
}
static int
tls_writer (void *handle,
char *buffer,
int size) {
SSL *ssl = (SSL *) handle;
return SSL_write (ssl, buffer, size);
}
#if 0
static int
tls_destroy (void *handle) {
SSL *ssl = (SSL *) handle;
if (ssl)
SSL_free (ssl);
return 0;
}
#endif
/*
* Additional profile-related functions.
*/
DIAGNOSTIC *
tls_privatize (BP_CONNECTION *bp,
char *serverName) {
char *cp;
bp_slist *list;
CHANNEL_INSTANCE *ci;
DIAGNOSTIC *d;
PROFILE ps,
*p = &ps;
PRO_LOCALDATA *il;
struct configobj *appconfig = bp_get_config (bp);
struct cfgsearchobj *cs;
if (((cp = config_get (appconfig, SASL_REMOTE_CODE)) != NULL)
&& (*cp == '2'))
return bp_diagnostic_new (bp, 520, NULL,
"already tuned for authentication");
if (!(il = (PRO_LOCALDATA *) lib_malloc (sizeof *il)))
return bp_diagnostic_new (bp, 421, NULL, "out of memory");
memset (il, 0, sizeof *il);
il -> pl_flags = PRO_INITIATOR | PRO_STARTING | PRO_CLOSED;
if (!(il -> pl_ctx = SSL_CTX_new (TLSv1_client_method ()))) {
if (pro_debug)
ERR_print_errors_fp (stderr);
lib_free (il);
return bp_diagnostic_new (bp, 421, NULL,
"unable to create client context");
}
for (list = bp -> channel_instance; list; list = list -> next)
if ((ci = list -> data) -> channel_number == 0) {
bpc_tuning_reset_request (ci);
break;
}
memset (p, 0, sizeof *p);
p -> uri = PRO_TLS_URI;
p -> piggyback_length = strlen (p -> piggyback = "<ready />");
cs = config_search_init (appconfig, PRIVACY_PREFIX, "");
for (cp = config_search_string_firstkey (cs);
cp;
cp = config_search_string_nextkey (cs))
config_delete (appconfig, cp);
config_search_fin (&cs);
if ((d = bp_start_request(bp, BLU_CHAN0_CHANO_DEFAULT,
BLU_CHAN0_MSGNO_DEFAULT, p, serverName, NULL,
(void *) il)) != NULL)
goto out;
while ((il -> pl_status == NULL)
&& ((il -> pl_flags & (PRO_STARTING|PRO_CLOSED)) != PRO_CLOSED)
&& (bp -> status != INST_STATUS_EXIT))
YIELD ();
while (bp->status == INST_STATUS_TUNING)
YIELD();
if (!il -> pl_status) {
d = bp_diagnostic_new (bp, 400, NULL,
bp -> status != INST_STATUS_EXIT
? "lost channel during tuning"
: "lost session during tuning");
goto out;
}
if (il -> pl_status -> code >= 400) {
d = il -> pl_status;
goto out;
}
bp_diagnostic_destroy (bp, il -> pl_status);
if ((!(d = bp_wait_for_greeting (bp)))
&& (bp -> status == INST_STATUS_EXIT))
d = bp_diagnostic_new (bp, 400, NULL, "lost session after tuning");
out: ;
if (!(il -> pl_flags & PRO_CLOSED))
il -> pl_channel -> profile -> user_ptr1 = NULL;
SSL_CTX_free (il -> pl_ctx);
lib_free (il);
return d;
}
/*
* Well-known shared library entry point.
*/
PROFILE_REGISTRATION *tls_profile_Init(struct configobj *appconfig) {
char *cp;
PROFILE_REGISTRATION prs,
*pr = &prs;
pro_debug = 0;
if ((cp = config_get (appconfig, TLS_DEBUG)) != NULL)
pro_debug = atoi (cp);
memset (pr, 0, sizeof *pr);
if (!(pr -> uri = config_get (appconfig, TLS_URI)))
pr -> uri = PRO_TLS_URI;
pr -> initiator_modes = "plaintext";
pr -> listener_modes = "plaintext";
pr -> full_messages = 1;
pr -> thread_per_channel = 0;
pr -> proreg_connection_init = pro_connection_init;
pr -> proreg_connection_fin = pro_connection_fin;
pr -> proreg_session_init = pro_session_init;
pr -> proreg_session_fin = pro_session_fin;
pr -> proreg_start_indication = pro_start_indication;
pr -> proreg_start_confirmation = pro_start_confirmation;
pr -> proreg_close_indication = pro_close_indication;
pr -> proreg_close_confirmation = pro_close_confirmation;
pr -> proreg_tuning_reset_indication = pro_tuning_reset_indication;
pr -> proreg_tuning_reset_confirmation = pro_tuning_reset_confirmation;
pr -> proreg_message_available = pro_message_available;
pr -> proreg_window_full = pro_window_full;
SSL_library_init ();
SSL_load_error_strings ();
if (!(cp = config_get (appconfig, TLS_CERTFILE))) {
log_line (LOG_PROF, 6, "TLS_CERTFILE not present in configuration");
return NULL;
}
if (!strstr (cp, ".pem")) {
log_line (LOG_PROF, 6, "TLS_CERTFILE doesn't end in \".pem\"");
return NULL;
}
if (!(cp = config_get (appconfig, TLS_KEYFILE))) {
log_line (LOG_PROF, 6, "TLS_KEYFILE not present in configuration");
return NULL;
}
if (!strstr (cp,".pem")) {
log_line (LOG_PROF, 6, "TLS_KEYFILE doesn't end in \".pem\"");
return NULL;
}
notifyqueue = workqueue_create();
if (notifyqueue == NULL) {
log_line (LOG_PROF, 6, "Unable to initalize worker threads");
return NULL;
}
return bp_profile_registration_clone (NULL, pr);
}
--- NEW FILE: tls-profile.h ---
/*
* Copyright (c) 2001 Invisible Worlds, Inc. All rights reserved.
*
* The contents of this file are subject to the Blocks Public License (the
* "License"); You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at http://www.beepcore.org/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*/
/*
* $Id: tls-profile.h,v 1.1 2002/09/08 03:02:33 cphmit Exp $
*/
/*
initiator usage:
1. pr = tls_profile_Init (appconfig)
2. establish session using pr
3. d = tls_privatize (...)
if d is non-NULL, you lose
listener usage:
1. pr = tls_profile_Init (appconfig)
2. establish session using pr
*/
#ifndef TLS_PROFILE_H
#define TLS_PROFILE_H 1
/* includes */
#include <beepcore-c/bp_wrapper.h>
#include <beepcore-c/bp_config.h>
#include <beepcore-c/tuning.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name The TLS profile
**/
/*@{*/
/* keys for configuration package */
/**
* URI to use for the TLS profile,
* defaults to <b>"http://iana.org/beep/TLS"</b>.
**/
#define TLS_URI "beep profiles tls uri"
/**
* File containing the public key certificate,
* must be present.
**/
#define TLS_CERTFILE "beep profiles tls certfile"
/**
* Directory containing public key certificates,
* each file named according to the <i>serverName</i> attribute.
* If this key or the resulting file isn't present,
* <i>TLS_CERTFILE</i> is used instead.
**/
#define TLS_CERTDIR "beep profiles tls certdir"
/**
* File containing the secret key,
* must be present.
**/
#define TLS_KEYFILE "beep profiles tls keyfile"
/**
* Directory containing secret keys,
* each file named according to the <i>serverName</i> attribute.
* If this key or the resulting file isn't present,
* <i>TLS_KEYFILE</i> is used instead.
**/
#define TLS_KEYDIR "beep profiles tls keydir"
/**
* Enables debug mode for the TLS profile,
* defaults to <b>"0"</b>.
**/
#define TLS_DEBUG "beep profiles tls debug"
/* module entry points */
/**
* Well-known entry point for the TLS profile.
*
* @param appconfig A pointer to the {@link configobj configuration}
* structure used for configuration purposes.
* <p>
* Keys:
* <blockquote><dl>
* <dt>TLS_URI</dt>
* <dd>The registration URI for the profile.</dd>
*
* <dt>TLS_DEBUG</dt>
* <dd>A non-zero value to enable debugging (optional).</dd>
*
* <dt>TLS_CERTDIR</dt>
* <dd>The name of the directory containing public key certificates,
* each file named according to the <i>serverName</i> attribute
* (optional, server-side only).
* If this key or the resulting file isn't present,
* <i>TLS_CERTFILE</i> is used instead.</dd>
*
* <dt>TLS_KEYFILE</dt>
* <dd>The name of the file containing the private key.</dd>
*
* <dt>TLS_KEYDIR</dt>
* <dd>The name of the directory containing secret keys,
* each file named according to the <i>serverName</i> attribute
* (optional, server-side only).
* If this key or the resulting file isn't present,
* <i>TLS_KEYFILE</i> is used instead.</dd>
* </dl></blockquote>
*
* @return A pointer to a profile-registration structure.
**/
extern struct PROFILE_REGISTRATION* tls_profile_Init(struct configobj* appconfig);
/**
* Tune using TLS, and update the connection's
* {@link configobj configuration} structure accordingly.
* <p>
* On success, transport privacy is in effect and no user channels are open.
*
* @param bp A pointer to the connection structure.
* <p>
* Input Keys:
* <blockquote><dl>
* <dt>TLS_CERTFILE</dt>
* <dd>The name of the file containing the public key certificate.</dd>
*
* <dt>TLS_KEYFILE</dt>
* <dd>The name of the file containing the private key.</dd>
* </dl></blockquote>
*
* <p>
* Output Keys:
* <blockquote><dl>
* <dt>PRIVACY_REMOTE_SUBJECTNAME</dt>
* <dd>The subject name from the peer's certificate.</dd>
*
* <dt>PRIVACY_CIPHER_NAME</dt>
* <dd>The name of the cipher in use.</dd>
*
* <dt>PRIVACY_CIPHER_PROTOCOL</dt>
* <dd>The name of the privacy protocol in use.</dd>
*
* <dt>PRIVACY_CIPHER_SBITS</dt>
* <dd>The number of bits in the secret key in use.</dd>
* </dl></blockquote>
*
* @param serverName The value to use for the <i>serverName</i> attribute
* of the <start> element, or <b>NULL</b>.
*
* @return On failure, a pointer to a {@link diagnostic diagnostic} structure
* explaining the reason
* (which should subsequently be destroyed by calling
* {@link bp_diagnostic_destroy bp_diagnostic_destroy}).
**/
extern struct diagnostic* tls_privatize(struct BP_CONNECTION* bp,
char* serverName);
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
--- NEW FILE: tuning.h ---
/* tuning parameters */
#ifndef TUNING_H
#define TUNING_H 1
/* includes */
#include <beepcore-c/bp_config.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/**
* @name Tuning Parameters
**/
/*@{*/
/**
* The prefix used for identity properties associated with the local peer.
**/
#define SASL_LOCAL_PREFIX "beep identity local "
/**
* The SASL authentication-identity.
**/
#define SASL_LOCAL_USERNAME "beep identity local username"
/**
* The SASL authorization-identity.
**/
#define SASL_LOCAL_TARGET "beep identity local target"
/**
* The authentication realm.
**/
#define SASL_LOCAL_REALM "beep identity local target"
/**
* The passphrase for the authentication-identity.
**/
#define SASL_LOCAL_PASSPHRASE "beep identity local passphrase"
/**
* The mechanism used during the peer's attempt to authenticate.
* <p>
* Typically, this is set by {@link sasl_login sasl_login}
* or {@link cyrus_login cyrus_login}.
**/
#define SASL_LOCAL_MECHANISM "beep identity local mechanism"
/**
* The reply code resulting from a peer's attempt to authenticate.
* <p>
* Typically, this is set by {@link sasl_login sasl_login}
* or {@link cyrus_login cyrus_login}.
* Consult \URL[Section 8 of RFC 3080]{http://www.beepcore.org/beepcore/docs/rfc3080.jsp#reply-codes}
* for an (incomplete) list.
**/
#define SASL_LOCAL_CODE "beep identity local reply_code"
/**
* A textual message corresponding to the
* {@link SASL_LOCAL_CODE SASL_LOCAL_CODE}.
* <p>
* Typically, this is set by {@link sasl_login sasl_login}
* or {@link cyrus_login cyrus_login}.
**/
#define SASL_LOCAL_REASON "beep identity local reply_text"
/**
* The prefix used for identity properties associated with the remote peer.
**/
#define SASL_REMOTE_PREFIX "beep identity remote "
/**
* The mechanism used during the peer's attempt to authenticate.
**/
#define SASL_REMOTE_MECHANISM "beep identity remote mechanism"
/**
* The SASL authentication-identity of the peer.
* <p>
* After registering the result from
* {@link sasl_profiles_Init sasl_profiles_Init}
* or {@link cyrus_profiles_Init cyrus_profiles_Init},
* this parameter gets set when appropriate.
**/
#define SASL_REMOTE_USERNAME "beep identity remote username"
/**
* The SASL authorization-identity of the peer.
* <p>
* After registering the result from
* {@link sasl_profiles_Init sasl_profiles_Init}
* or {@link cyrus_profiles_Init cyrus_profiles_Init},
* this parameter gets set when appropriate.
**/
#define SASL_REMOTE_TARGET "beep identity remote target"
/**
* The numeric result of the peer's attempt to authenticate.
* <p>
* After registering the result from
* {@link sasl_profiles_Init sasl_profiles_Init}
* or {@link cyrus_profiles_Init cyrus_profiles_Init},
* this parameter gets set when appropriate.
* Consult \URL[Section 8 of RFC 3080]{http://www.beepcore.org/beepcore/docs/rfc3080.jsp#reply-codes}
* for an (incomplete) list.
**/
#define SASL_REMOTE_CODE "beep identity remote reply_code"
/**
* A textual message corresponding to the
* {@link SASL_REMOTE_CODE SASL_REMOTE_CODE}.
* <p>
* After registering the result from
* {@link sasl_profiles_Init sasl_profiles_Init}
* or {@link cyrus_profiles_Init cyrus_profiles_Init},
* this parameter gets set when appropriate.
**/
#define SASL_REMOTE_REASON "beep identity remote reply_text"
/**
* The prefix used for privacy properties associated with the session.
**/
#define PRIVACY_PREFIX "beep identity privacy "
/**
* The name of the cipher in use.
* <p>
* On the client-side, this is typically set as a result of calling
* {@link tls_privatize tls_privatize}; whilst on the server-side,
* after registering the result from {@link tls_profile_Init tls_profile_Init},
* this parameter gets set when appropriate.
* If the Cyrus SASL package is in use, then this may also be set as a result
* of calling {@link cyrus_login cyrus_login}; whilst on the server-side,
* after registering the result from
* {@link cyrus_profiles_Init cyrus_profiles_Init}.
**/
#define PRIVACY_CIPHER_NAME "beep identity privacy cipher name"
/**
* The number of bits in the session key in use.
* <p>
* On the client-side, this is typically set as a result of calling
* {@link tls_privatize tls_privatize}; whilst on the server-side,
* after registering the result from {@link tls_profile_Init tls_profile_Init},
* this parameter gets set when appropriate.
* If the Cyrus SASL package is in use, then this may also be set as a result
* of calling {@link cyrus_login cyrus_login}; whilst on the server-side,
* after registering the result from
* {@link cyrus_profiles_Init cyrus_profiles_Init}.
**/
#define PRIVACY_CIPHER_SBITS "beep identity privacy cipher session_bits"
/**
* The name of the privacy protocol in use.
* <p>
* On the client-side, this is typically set as a result of calling
* {@link tls_privatize tls_privatize}; whilst on the server-side,
* after registering the result from {@link tls_profile_Init tls_profile_Init},
* this parameter gets set when appropriate.
**/
#define PRIVACY_CIPHER_PROTOCOL "beep identity privacy cipher protocol"
/**
* The subject name from the peer's certificate.
* <p>
* On the client-side, this is typically set as a result of calling
* {@link tls_privatize tls_privatize}; whilst on the server-side,
* after registering the result from {@link tls_profile_Init tls_profile_Init},
* this parameter gets set when appropriate.
**/
#define PRIVACY_REMOTE_SUBJECTNAME \
"beep identity privacy remote subject_name"
/*@}*/
#if defined(__cplusplus)
}
#endif
#endif
-------------------------------------------------------
In remembrance
www.osdn.com/911/