Subject: Re: Using SASL C API from a library

From: Larry Greenfield <[email-masked]>
Date: Tue, 01 Jul 2003 10:01:52 -0400

Philip Guenther wrote:

>Rob Siemborski <[email-masked]> writes:
>...
>  
>
>>This works, until an application is running using an incompatible
>>threading API (see Larry's answer to my earlier question).
>>    
>>
>I knew I should have replied to Larry's answer.  I find his example
>unconvincing.  He has suggested that there may exist a cooperative
>threading library running on a system that has a system level threading
>implementation and that intercepts blocking I/O calls (i.e., supplies
>symbols like connect(), read(), etc) such that it intercepts the calls
>of unmodified libraries, but that *doesn't* intercept calls to the
>system's threading primitives.  (If that's not what you're suggesting,
>Larry, please correct me.)
>
This appears to be an accurate description of the GNU Pth library using 
the "hard system call mapping". (I base this off of the documentation 
and not first hand experience.)

Pth is a popular and frequently used threading library.

Larry

---

From: Rob Siemborski <[email-masked]>
Date: Tue, 1 Jul 2003 10:12:53 -0400 (EDT)

On Tue, 1 Jul 2003, Greg Hudson wrote:

> > Unless I am misremembering, this is basically what we discussed in San
> > Francisco (I thought I had mentioned that).
>
> (The minutes do not appear to document any discussion of the SASL C API,
> incidentally.)

Since its not a charter item, it wasn't discussed in the formal WG
meeting.  I think Alexey has notes from when a few of us sat around
discussing it though.

> Previously, you said "it can be solved by not using global callbacks
> except in the outermost application," which is very different from "not
> using global callbacks at all."
>
> > Note that this is difficult for situations such as the getopt callback
> > where path information to loadable modules (or similar information that is
> > requried for the library to initialize) may need to be obtained.
>
> There is really no limit to the number of awful things you could justify
> putting into the API if you want to satisfy every possible foible of a
> back-end library. [snip]

You don't need to satisfy every possible one, but let's at least try to
anticipate reasonable desires of the implementors.

> So, unless you can demonstrate a present practical issue, I don't think
> this argument is even vaguely compelling.

Kerberos mechanisms need a path to a srvtab or keytab.  Perhaps shared
secret mechanisms need a path to a database of shared secrets.

Perhaps one of the worse examples (though one of the most useful) is a
list of mechanisms to limit what the library advertises.

The good news here is that most of these are (or can be made to be)
connection-context specific.  Ones that potentially need to be supported
by a global getopt callback really significantly fewer.

> Franky, the getopt callback is a great big hole in the spec for
> unspecified behavior (both mechanism-specific and
> implementation-specific), since there is no standardization of what the
> options mean.  Presumably the idea is that you would provide the answers
> from a configuration file or from command-line options, giving a sort of
> direct communications channel between the user and the SASL library or
> specific mechanism.  That may sound attractive to implementors, but it's
> a totally unacceptable idea, because it's impossible to document such a
> config file or command-line syntax without knowing the intimate (and
> version-specific) details of your SASL implementation, and because it's
> impossible to provide reasonable answers in a situation where a config
> file or command line doesn't make sense.

The application doesn't have to understand the options its handing
to the library, only the user does.  And the user can have access to
implementation-specific information about the library.

Sure, the library can also just access a configuration file to get the
information it needs, but then how does the user supply the path the the
configuration file?  I'm quite certain that having a fixed path to a
configuration file isn't what users are looking for.  And being able to
combine SASL options with application options in one place is a usability
improvement.

Implementations of the SASL API will require configuration options to
function properly, we shouldn't deny them a reasonable way to get that
information in a standard way, even if the information itself is
implementation dependent.

-Rob

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Rob Siemborski | Andrew Systems Group * Research Systems Programmer
PGP:0x5CE32FCC | Cyert Hall 207 * [email-masked] * 412.268.7456
-----BEGIN GEEK CODE BLOCK----
Version: 3.12
GCS/IT/CM/PA d- s+: a-- C++++$ ULS++++$ P+++$ L+++(++++) E W+ N o? K-
w O- M-- V-- PS+ PE++ Y+ PGP+ t+@ 5+++ R@ tv-@ b+ DI+++ G e h r- y?
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 01 Jul 2003 11:27:26 -0400

> by a global getopt callback really significantly fewer.

Certainly it should be possible for krb5, since krb5 does not use global
state.  (It also does not allow the caller to pass a path to find
krb5.conf.)

> configuration file isn't what users are looking for.

I believe this is argument from fantasy.  I don't think there's any
back-end mechanism library which asks for this kind of information from
the calling code.  They all uses fixed paths, possibly overridden by
environment variables which the calling code is not expected to tamper
with.

> And being able to combine SASL options with application options in one
> place is a usability improvement.

Options required for a SASL library itself should be nailed down by the
spec or not subject to configuration by the caller.  (The plugin dir,
for instance, should be found in a fixed location or via an environment
variable; there's no reason for SASL to introduce a completely new
override mechanism.)

> implementation dependent.

Once again, you've made an argument which (I believe) no other
standardized API makes, and provided no specific examples to back it up.

---

From: Sam Hartman <[email-masked]>
Date: Wed, 02 Jul 2003 12:36:25 -0400

>>>>> "Rob" == Rob Siemborski <[email-masked]> writes:

    Rob> On Sun, 29 Jun 2003, Greg Hudson wrote:

    >> It seems like a bizarre argument, especially when Unix systems
    >> converged on the POSIX threads API years and years ago.

    Rob> Solaris has a non-pthreads threading API.  There's no reason
    Rob> the SASL C API should dictate what threading API to use.

It's my understanding that at least in recent Solaris versions, the
locks between this API and the pthreads API are compatible.  Please
correct me if I'm wrong.

---

From: Alexey Melnikov <[email-masked]>
Date: Wed, 02 Jul 2003 18:41:59 -0600

> variable; there's no reason for SASL to introduce a completely new

Oh, please. What if my application wants to use a fixes path, but not the one
hardcoded in the SASL library?

Plus hardcoded paths don't work on certain OSes (e.g. Windows).

Alexey
__________________________________________
Home Page: http://orthanc.ab.ca/mel
IETF standard
related pages: http://orthanc.ab.ca/mel/devel/Links.html
__________________________________________

---

From: Alexey Melnikov <[email-masked]>
Date: Wed, 02 Jul 2003 18:47:29 -0600

Rob Siemborski wrote:

> > Since people have grown silent on the topic, I'll note that no excuse
> > has been given for the global callbacks structure, and no answer has
> > been given to my argument that library calls to the SASL C API could
> > accidentally trigger invocations of the application's global callbacks
> > no matter what the library does to guard against this possibility.  If
> > transition for users of Cyrus SASL is the only concern, then the API
> > spec can preserve the parameter as a dummy and mandate that all callers
> > must pass NULL, as has been done in Unix with gettimeofday() and the
> > timezone parameter.
>

Yes, this is in my notes. More specifically:

1). Init problem: deprecatate global callbacks.

If global callbacks are provided multiple times, this is implementation
dependent.

2). Make appname setprop/getprop

appname must be NULL in sasl_server_init, if it is called from a library.

> Note that this is difficult for situations such as the getopt callback,
> requried for the library to initialize) may need to be obtained.  In this
> case (since it is part of the one-time library startup) the application
> would need to supply a getopt callback.  Since its one-time startup state,
> your library couldn't change it if it wanted to.

So, where this discussion leaves us? Should I change the document to say that
global callbacks must be NULL, except for maybe the getopt callback?

Alexey

---

From: Greg Hudson <[email-masked]>
Date: 02 Jul 2003 22:05:04 -0400

> Plus hardcoded paths don't work on certain OSes (e.g. Windows).

Why would you ever write an application which cares, more than any other
application, where a SASL library looks for its plugin directory?

Every caller of the SASL library should be in the same position here. 
Which means the library needs to be able to find its plugins without
help from the calling code.  Whether that means a fixed path, an
environment variable, the registry, or whatever else is up to the
library, but asking the calling code to provide that information is of
no help.

But let's say I'm wrong, and there really is some good reason why the
calling code should be helping out.  And let's also say that this reason
isn't good enough to make the plugin directory part of the standard SASL
C API.  What value is there in half-standardizing the interface through
which the library gets this information?  If some application needs this
non-standard functionality and therefore can only use (let's say) the
Cyrus implementation, then the Cyrus implementation can add its own
non-standard function to specify the plugin directory.

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 09:51:35 -0400 (EDT)

> non-standard function to specify the plugin directory.

Are you saying its better to have NO standard way to get configuration
information into the library fromt he application?  Thus, if I want an
application to work with two types of libraries, I have to provide (in
hard code) perhaps a callback for SASL_NONSTANARD_CB_PATHNAME and
SASL_NONSTANDARD_CB_PATH_TO_PLUGINS just to work with two implementation?
Worse: what if these two implementations define the same values for these
two callbacks!

The getopt callback supplys a standard way to get this information from
the application.  Since presumably the application is looking up this
information in its own config files, the user can read the documentation
for their SASL implementation and decide if they need to set the SASL
option "pathname" or "path_to_plugins".  This can be done without needing
to change the code to the application.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 13:04:27 -0400

On Thu, 2003-07-03 at 09:51, Rob Siemborski wrote:
> information into the library fromt he application?

Absolutely.  The vast majority of APIs contain no such mechanism,
because a library should be able to do its job without creating such a
mechanism.  If for some reason the library needs configuration, it can
get it via its own configuration files, which it can find through
mechanisms not involving the calling code (fixed paths, environment
variables, the registry, etc.).

The only exception class tends to be gui toolkits, which usually want to
take over the command line by accepting and modifying argc and argv. 
I'm ambivalent about this practice (it makes it harder to document the
command-line syntax of programs using the gui toolkit, but it's hard to
imagine doing without it given the variety of standard command-line
arguments affecting the toolkit), but it's not terribly onerous because
a GUI toolkit tends to dominate the scope and structure of an
application.  Not so with a SASL library.

>   Thus, if I want an

If we are talking about an application providing this information for
its own reasons, then it's already sunk; the SASL API says nothing about
plugin paths, you don't know what option name would be involved, and the
implementation might not even use plugins.  (And of course, if the
application is providing such information for its own reasons, it
probably cares about the back-end plugin interface, which isn't
specified at all.)

But, of course, the specifiers are not envisioning an application
providing this information for its own reasons; they are envisioning an
application blindly (no stigma here) passing along user configuration,

> to change the code to the application.

We're going around in circles on this point.  I'll skip the part where I
argue against this idea at the end of
<http://www.imc.org/ietf-sasl/mail-archive/msg01008.html> and go to the
part where you respond in
<http://www.imc.org/ietf-sasl/mail-archive/msg01014.html> with (among
discussions of fixed paths versus other ways of finding a config file,
which we've also talked about at length):

which is another puzzling argument.  Most discussion of usability
revolves around GUI interfaces, and it is impossible to create a
non-degenerate GUI configuration interface for options you know nothing
about.  The best you can do is provide a registry-like interface where
the user can manipulate key-value pairs, which is only one step away
from editing text files.

But even if we're talking about usability among the tiny
(percentagewise) population of users who are comfortable editing
configuration files, I don't see the benefit.  Why would I want to have
a single configuration whose meaning is split over two or more different
pieces of documentation?  Wouldn't I like my configuration files to have
nicely commented templates?  (That would be logistically difficult for
configuration files which span abstraction barriers like you envision.) 
And if I want to change where (say) Cyrus SASL looks for its plugins,
why would I want to have to do that for every application which uses
Cyrus SASL, instead of doing it in one place?

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 13:15:31 -0400 (EDT)

> Cyrus SASL, instead of doing it in one place?

Nothing prevents the library from having defaults, or looking at
environment variables, or reading from /dev/random to gain the
information otherwise provided by getopt in other ways.

However, in your scenario all the applications running on a system need to
share the same global configuration with no possibility of making
application-specific changes.  Which really isn't acceptable.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 13:20:26 -0400

> application-specific changes.  Which really isn't acceptable.

Why not?  There is no application-specific configuration for krb5, or
for the resolver, or for a host of other libraries.  (You can, of
course, hack it up using environment variables and alternate config
files, but people rarely seem to.)

If you actually can come up with a practical reason to have
application-specific configuration for a SASL library (a concept which
doesn't make a lot of sense when SASL is being driven from another
library), then it is *still* better to handle this from a SASL-specific
configuration file, using options keyed off the application name,
because then it's possible to write documentation and GUI tools which
understand everything about the config file, unlike in your scheme.

---

From: Alexey Melnikov <[email-masked]>
Date: Thu, 03 Jul 2003 16:27:30 -0600

> variables, the registry, etc.).

I am afraid I disagree. Centralizing all configuration for an application in
one place might be a good (and required) thing.

> application blindly (no stigma here) passing along user configuration,

Ok people.
I am afraid we are starting a religious war at this point and this is not going
to do us any good.

So, how about making some constructive suggestions. How about the following:
1). libraries MUST NOT specify callbacks when calling
sasl_client_init/sasl_server_init.
Global callbacks are thus deprecated.
2). a new function is added to set getopt callback. An application that doesn't
care about getopt, will not call this function. If this callback is not set,
the SASL library will use reasonable defaults or get the required information
from own config file/environment/registry/whatever.
3). one of the getopt options is a plugin directory. If the application doesn't
care, its getopt callback will fail to return the value for this option. The
SASL library will choose a reasonable default in this case. If the SASL library
doesn't support plugins, it will not care about this option.

I believe this is how it works now anyway (except for new function for setting
getopt).

Alexey

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 18:44:10 -0400 (EDT)

On Thu, 3 Jul 2003, Alexey Melnikov wrote:

> Ok people. I am afraid we are starting a religious war at this point and
> this is not going to do us any good.

I agree.

> 2). a new function is added to set getopt callback. An application that
> doesn't care about getopt, will not call this function. If this callback
> is not set, the SASL library will use reasonable defaults or get the
> required information from own config file/environment/registry/whatever.
>

This is worse than the global callbacks scenario with libraries forbidden
from setting global callbaks, since in this situation a libary can call
the magic new function to set the getopt() callback.

I don't see how this is better than allowing a getopt() callback to be set
by the application, but not by libraries in the call to sasl_xxx_init().

Even if we forbid libraries from calling this new function, the situation
is worse than allowing applications to set a getopt callback in their call
to sasl_xxx_init(), as it requires changes from current practice.

> I believe this is how it works now anyway (except for new function for setting

Not quite true, this requires standardizing the name of an option, as
well.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 18:42:56 -0400

> Global callbacks are thus deprecated.

You seem to leave open the question of whether applications are allowed
to specify callbacks.  Was that intentional?

(As I've mentioned before, if applications are allowed to set global
callbacks, then a library using SASL cannot guard against accidentally
triggering the application global callbacks.)

> care about getopt, will not call this function.

Well, as everybody knows, my religion does not include such a device,
but global state is generally not burdensome as long as it's
(completely) optional.  So I won't scream and yell about it.

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 06:18:17 -0600

> the magic new function to set the getopt() callback.

IMHO, it is not different.

You can't prevent libraries or applications from doing stupid things, you can only
advise them how to avoid problems.

> by the application, but not by libraries in the call to sasl_xxx_init().

Would you rather allow getopt (and only getopt) to be set by the application when
calling a sasl_xxx_init()
and a library using SASL always pass NULL as callbacks?

> Not quite true, this requires standardizing the name of an option, as

I meant in Cyrus SASL library, not the document.

Alexey

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 06:38:57 -0600

Greg Hudson wrote:

> to specify callbacks.

Sorry, forgot about that. Either an application should pass NULL as a library (and
new function is introduced for setting getopt as described), or the application is
only allowed to set getopt as a global callback. In this case interaction between
global callbacks and local one should be documented.

>  Was that intentional?

No.

> (completely) optional.  So I won't scream and yell about it.

I was hoping for this :-).

Alexey

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 08:32:31 -0600

Rob Siemborski wrote:

> On Fri, 4 Jul 2003, Alexey Melnikov wrote:
>
> > Would you rather allow getopt (and only getopt) to be set by the
> > application when calling a sasl_xxx_init() and a library using SASL
> > always pass NULL as callbacks?
>
> Yes, since it is much closer to what is currently done, and I don't see
> the gain of adding a separate "set getopt" function which needs to be
> called before sasl_xxx_init anyway.  If there's a concrete gain that
> justified the change in code, I'd be less opposed.
>
> So option names would still be non-standard?  Doesn't this not address
> Greg's concern then?

I think it should be standard, but Greg wouldn't care :-).

Alexey

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 10:29:31 -0400 (EDT)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 04 Jul 2003 10:46:03 -0400

> global callbacks and local one should be documented.

It sounds like we get the simplest transition if we make the changes:

  * Libraries must pass NULL for the global callbacks.
  * Applications must pass NULL, or only a getopt callback.
  * Applications MAY pass a getopt callback, but we don't say they
    SHOULD.

Existing SASL implementations don't have to do anything except modify
their documentation.

To resolve my other issue while still preserving the ability to use a
non-standard thread library:

  * sasl_set_mutex() becomes optional, but must be called from the
    initial single-threaded environment if it is called at all.  If
    it is not called, the library will use the most standard native
    thread APIs to protect any internal global state.
  * sasl_*_init() no longer needs to be called from the initial
    single-threaded environment.

This change is more burdensome.for existing implementations which have
internal global state to protect; they must use threads (I'm told the
pthreads API works under Windows, but I don't know how advisable it is
to use it) and introduce a link-time dependency on a threads library. 
But the API does then become safely usable from a library.

(I am okay with allowing implementations to simply not advertise thread
safety, in which case they don't need to implement their own locks.)

These changes do not turn the API into a shining example of standard API
design in my book, of course; they are merely proposed as a practical
compromise.

> So option names would still be non-standard?  Doesn't this not address

There are my concerns about the API's practical usability from a
library, and there are my concerns about good design of a standard API,
and I haven't kept them separate in this discussion.  The former
concerns are mostly objective, but it's clear that the other members of
this working group don't agree with me on the latter concerns, so I will
try to stick to the former.

With that proviso, having a pseudo-standardized getopt() is okay as long
as we don't enforce its use by callers.  So I have concerns with the
following text in the current draft:

   The most important callback is the "getopt" callback (see
   section 3.3.3) which is used to retrieve security policy option set-
   tings from the caller's preferences.

This text worries me because the getopt callback is referred to as
"important" and because security policy should be retrieved through a
fully standard interface.  (That may require a lot of work; I haven't
thought about that problem in great detail.)  Imagine trying to build an
application which has a GUI to configure security policy preferences
using the current design.

      The callbacks argument is the default list of callbacks (see sec-
      tion 3.1.1 for definition of sasl_callback_t structure) and SHOULD
      include the sasl_getopt_t callback (see section 3.3.3).

This text worries me because, again, it seems to expect that the
implementation will really want to see a getopt callback and will behave
only minimally usefully without one.

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 11:16:00 -0400 (EDT)

> Existing SASL implementations don't have to do anything except modify

I'm okay with this.

> safety, in which case they don't need to implement their own locks.)

If this change allows for implementations to advertise thread safety only
if sasl_set_mutex is called (from a non-threaded environment), I'm at least
willing to talk about this.

First, I think that calling sasl_set_mutex needs to be a "SHOULD" and not
"OPTIONAL".

I also worry a bit about sasl_xxx_init not being required to be called
from a single non-threaded environment, since in order to simulate this
the library would need to lock around it.  If sasl_set_mutex has been
called, presumably this means that sasl_set_mutex allocates the necessary
mutex, but now we can never release this mutex safely (well, unless
sasl_set_mutex was called again with all NULL values, I suppose).  This
may not be a practical concern.

> design in my book, of course; they are merely proposed as a practical

As you can probably understand, its really hard for me to not oppose
significant changes in the API as we try to standardize it.  We've already
implemented two substantially different SASL APIs, I'm not looking forward
to doing it a third time, especially given the deployment we currently
have.

Making it usable is one thing (for which I am willing to compromise),
however making it a "shining example of API design" in ways that are not
backwards compatible, just for the sake of doing so is probably going to
see pushback.

> using the current design.

I tend to agree that "security policy" decisions should be done through
standard interfaces.  Of course, if things like telling the mechanisms
what database to pull user secrets from (or how to authenticate to that
database, or so on) is a "security policy" decision, we're going to have
problems defining any standard interface to deal with this.

I think this sentence can just be eliminated, it doesn't really add
anything useful to section 3.3.1.

> only minimally usefully without one.

I'm willing to change SHOULD to a MAY here (for applications), and MUST
NOT (for libraries).

Something like:

The callbacks argument is the default list of callbacks (see section 3.1.1
for definition of sasl_callback_t structure).  Libraries that are clients
of the API MUST supply NULL For this parameter.  Applications that are
clients of the API MAY supply a list that includes the sasl_getopt_t
callback, but MUST NOT supply any other callbacks through this interface.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 04 Jul 2003 11:27:20 -0400

I understand not wanting to make incompatible changes to the API at this
time.

> willing to talk about this.

Well, as long as they're clear, they can hedge all they want, I suppose.

> may not be a practical concern.

pthreads allows you to create a statically intialized mutex.  You'd
never release such a beast; you'd just use it to lock around
non-thread-safe operations.

> callback, but MUST NOT supply any other callbacks through this interface.

That looks okay to me.

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 11:37:47 -0400 (EDT)

> non-thread-safe operations.

That's true.

However, if sasl_set_mutex *is* called we have no way of staticly
allocating a mutex, since we have to dynamicly call the init function to
get the proper mutex (and we may not be using pthread mutexes).

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Sam Hartman <[email-masked]>
Date: Sun, 06 Jul 2003 00:51:02 -0400

>>>>> "Alexey" == Alexey Melnikov <[email-masked]> writes:

    Alexey> Ok people.  I am afraid we are starting a religious war at
    Alexey> this point and this is not going to do us any good.

If this were a WG item I'd disagree that anyone was proposing a
religious war.  I'd comment that there seems to be an unspecified
requirement behind the global getopt callback.  I'd ask the proponents
of that callback to describe clearly what problem it was trying to
solve.

Then, I'd see if the WG could reach consensus on whether that problem
was a good thing to solve in a standards track API.

If the WG reached consensus on a problem and agreed the problem was
worth solving, then we would look at whether the getopt callback
actually solved that problem.

But this document is not a WG item; you can use whatever procedure you
like to decide its contents.

---

From: Larry Greenfield <[email-masked]>
Date: Tue, 01 Jul 2003 10:01:52 -0400

Larry

---

From: Rob Siemborski <[email-masked]>
Date: Tue, 1 Jul 2003 10:12:53 -0400 (EDT)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 01 Jul 2003 11:27:26 -0400

---

From: Sam Hartman <[email-masked]>
Date: Wed, 02 Jul 2003 12:36:25 -0400

---

From: Alexey Melnikov <[email-masked]>
Date: Wed, 02 Jul 2003 18:41:59 -0600

Alexey

---

From: Alexey Melnikov <[email-masked]>
Date: Wed, 02 Jul 2003 18:47:29 -0600

Alexey

---

From: Greg Hudson <[email-masked]>
Date: 02 Jul 2003 22:05:04 -0400

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 09:51:35 -0400 (EDT)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 13:04:27 -0400

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 13:15:31 -0400 (EDT)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 13:20:26 -0400

---

From: Alexey Melnikov <[email-masked]>
Date: Thu, 03 Jul 2003 16:27:30 -0600

Ok people.

Alexey

---

From: Rob Siemborski <[email-masked]>
Date: Thu, 3 Jul 2003 18:44:10 -0400 (EDT)

I agree.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 03 Jul 2003 18:42:56 -0400

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 06:18:17 -0600

Alexey

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 06:38:57 -0600

No.

Alexey

---

From: Alexey Melnikov <[email-masked]>
Date: Fri, 04 Jul 2003 08:32:31 -0600

Alexey

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 10:29:31 -0400 (EDT)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 04 Jul 2003 10:46:03 -0400

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 11:16:00 -0400 (EDT)

I'm okay with this.

Something like:

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: 04 Jul 2003 11:27:20 -0400

That looks okay to me.

---

From: Rob Siemborski <[email-masked]>
Date: Fri, 4 Jul 2003 11:37:47 -0400 (EDT)

That's true.

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----

---

From: Sam Hartman <[email-masked]>
Date: Sun, 06 Jul 2003 00:51:02 -0400