Hi,
I did some little research and now i understand that SPNEGO helps the
client and server to negotiate which mechanism to choose like
Kerberos. I found in the source code of Samba the spnego.c file and it
tells me that they use a RFC2478 Compliant SPNEGO implementation. With
functions like:
read_negTokenInit, write_negTokenInit to initiate
and read_negTokenTarg, write_negTokenTarg to talk after the init.
But i don't know if it is a problem for ESOE that the SPNEGO function
in samba is used to communicate with an Windows AD.
Greets Martijn.
The C file :
/*
Unix SMB/CIFS implementation.
RFC2478 Compliant SPNEGO implementation
Copyright (C) Jim McDonough <j...@us.ibm.com> 2003
This program is free software; you can redistribute it and/or
modify
it under the terms of the GNU General Public License as published
by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
{
ZERO_STRUCTP(token);
asn1_start_tag(asn1, ASN1_CONTEXT(0));
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
int i;
switch (asn1->data[asn1->ofs]) {
/* Read mechTypes */
case ASN1_CONTEXT(0):
asn1_start_tag(asn1, ASN1_CONTEXT(0));
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
token->mechTypes = SMB_MALLOC_P(char *);
for (i = 0; !asn1->has_error &&
0 < asn1_tag_remaining(asn1); i++) {
token->mechTypes =
SMB_REALLOC_ARRAY(token->mechTypes, char *, i + 2);
asn1_read_OID(asn1, token->mechTypes + i);
}
token->mechTypes[i] = NULL;
asn1_end_tag(asn1);
asn1_end_tag(asn1);
break;
/* Read reqFlags */
case ASN1_CONTEXT(1):
asn1_start_tag(asn1, ASN1_CONTEXT(1));
asn1_read_Integer(asn1, &token->reqFlags);
token->reqFlags |= SPNEGO_REQ_FLAG;
asn1_end_tag(asn1);
break;
/* Read mechToken */
case ASN1_CONTEXT(2):
asn1_start_tag(asn1, ASN1_CONTEXT(2));
asn1_read_OctetString(asn1, &token->mechToken);
asn1_end_tag(asn1);
break;
/* Read mecListMIC */
case ASN1_CONTEXT(3):
asn1_start_tag(asn1, ASN1_CONTEXT(3));
if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
asn1_read_OctetString(asn1,
&token->mechListMIC);
} else {
/* RFC 2478 says we have an Octet String here,
but W2k sends something different... */
char *mechListMIC;
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
asn1_push_tag(asn1, ASN1_CONTEXT(0));
asn1_read_GeneralString(asn1, &mechListMIC);
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
token->mechListMIC =
data_blob(mechListMIC, strlen(mechListMIC));
SAFE_FREE(mechListMIC);
}
asn1_end_tag(asn1);
break;
default:
asn1->has_error = True;
break;
}
}
asn1_end_tag(asn1);
asn1_end_tag(asn1);
return !asn1->has_error;
}
static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
{
asn1_push_tag(asn1, ASN1_CONTEXT(0));
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
/* Write mechTypes */
if (token->mechTypes && *token->mechTypes) {
int i;
asn1_push_tag(asn1, ASN1_CONTEXT(0));
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
for (i = 0; token->mechTypes[i]; i++) {
asn1_write_OID(asn1, token->mechTypes[i]);
}
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
}
/* write reqFlags */
if (token->reqFlags & SPNEGO_REQ_FLAG) {
int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
asn1_push_tag(asn1, ASN1_CONTEXT(1));
asn1_write_Integer(asn1, flags);
asn1_pop_tag(asn1);
}
/* write mechToken */
if (token->mechToken.data) {
asn1_push_tag(asn1, ASN1_CONTEXT(2));
asn1_write_OctetString(asn1, token->mechToken.data,
token->mechToken.length);
asn1_pop_tag(asn1);
}
/* write mechListMIC */
if (token->mechListMIC.data) {
asn1_push_tag(asn1, ASN1_CONTEXT(3));
#if 0
/* This is what RFC 2478 says ... */
asn1_write_OctetString(asn1, token->mechListMIC.data,
token->mechListMIC.length);
#else
/* ... but unfortunately this is what Windows
sends/expects */
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
asn1_push_tag(asn1, ASN1_CONTEXT(0));
asn1_push_tag(asn1, ASN1_GENERAL_STRING);
asn1_write(asn1, token->mechListMIC.data,
token->mechListMIC.length);
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
#endif
asn1_pop_tag(asn1);
}
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
return !asn1->has_error;
}
static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
{
ZERO_STRUCTP(token);
asn1_start_tag(asn1, ASN1_CONTEXT(1));
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
switch (asn1->data[asn1->ofs]) {
case ASN1_CONTEXT(0):
asn1_start_tag(asn1, ASN1_CONTEXT(0));
asn1_start_tag(asn1, ASN1_ENUMERATED);
asn1_read_uint8(asn1, &token->negResult);
asn1_end_tag(asn1);
asn1_end_tag(asn1);
break;
case ASN1_CONTEXT(1):
asn1_start_tag(asn1, ASN1_CONTEXT(1));
asn1_read_OID(asn1, &token->supportedMech);
asn1_end_tag(asn1);
break;
case ASN1_CONTEXT(2):
asn1_start_tag(asn1, ASN1_CONTEXT(2));
asn1_read_OctetString(asn1, &token->responseToken);
asn1_end_tag(asn1);
break;
case ASN1_CONTEXT(3):
asn1_start_tag(asn1, ASN1_CONTEXT(3));
asn1_read_OctetString(asn1, &token->mechListMIC);
asn1_end_tag(asn1);
break;
default:
asn1->has_error = True;
break;
}
}
asn1_end_tag(asn1);
asn1_end_tag(asn1);
return !asn1->has_error;
}
static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
{
asn1_push_tag(asn1, ASN1_CONTEXT(1));
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
asn1_push_tag(asn1, ASN1_CONTEXT(0));
asn1_write_enumerated(asn1, token->negResult);
asn1_pop_tag(asn1);
if (token->supportedMech) {
asn1_push_tag(asn1, ASN1_CONTEXT(1));
asn1_write_OID(asn1, token->supportedMech);
asn1_pop_tag(asn1);
}
if (token->responseToken.data) {
asn1_push_tag(asn1, ASN1_CONTEXT(2));
asn1_write_OctetString(asn1, token->responseToken.data,
token->responseToken.length);
asn1_pop_tag(asn1);
}
if (token->mechListMIC.data) {
asn1_push_tag(asn1, ASN1_CONTEXT(3));
asn1_write_OctetString(asn1, token->mechListMIC.data,
token->mechListMIC.length);
asn1_pop_tag(asn1);
}
asn1_pop_tag(asn1);
asn1_pop_tag(asn1);
return !asn1->has_error;
}
ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
{
ASN1_DATA asn1;
ssize_t ret = -1;
ZERO_STRUCTP(token);
ZERO_STRUCT(asn1);
asn1_load(&asn1, data);
switch (asn1.data[asn1.ofs]) {
case ASN1_APPLICATION(0):
asn1_start_tag(&asn1, ASN1_APPLICATION(0));
asn1_check_OID(&asn1, OID_SPNEGO);
if (read_negTokenInit(&asn1, &token->negTokenInit)) {
token->type = SPNEGO_NEG_TOKEN_INIT;
}
asn1_end_tag(&asn1);
break;
case ASN1_CONTEXT(1):
if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
token->type = SPNEGO_NEG_TOKEN_TARG;
}
break;
default:
break;
}
if (!asn1.has_error) ret = asn1.ofs;
asn1_free(&asn1);
return ret;
}
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
{
ASN1_DATA asn1;
ssize_t ret = -1;
ZERO_STRUCT(asn1);
switch (spnego->type) {
case SPNEGO_NEG_TOKEN_INIT:
asn1_push_tag(&asn1, ASN1_APPLICATION(0));
asn1_write_OID(&asn1, OID_SPNEGO);
write_negTokenInit(&asn1, &spnego->negTokenInit);
asn1_pop_tag(&asn1);
break;
case SPNEGO_NEG_TOKEN_TARG:
write_negTokenTarg(&asn1, &spnego->negTokenTarg);
break;
default:
asn1.has_error = True;
break;
}
if (!asn1.has_error) {
*blob = data_blob(asn1.data, asn1.length);
ret = asn1.ofs;
}
asn1_free(&asn1);
return ret;
}
BOOL free_spnego_data(SPNEGO_DATA *spnego)
{
BOOL ret = True;
if (!spnego) goto out;
switch(spnego->type) {
case SPNEGO_NEG_TOKEN_INIT:
if (spnego->negTokenInit.mechTypes) {
int i;
for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
free(spnego->negTokenInit.mechTypes[i]);
}
free(spnego->negTokenInit.mechTypes);
}
data_blob_free(&spnego->negTokenInit.mechToken);
data_blob_free(&spnego->negTokenInit.mechListMIC);
break;
case SPNEGO_NEG_TOKEN_TARG:
if (spnego->negTokenTarg.supportedMech) {
free(spnego->negTokenTarg.supportedMech);
}
data_blob_free(&spnego->negTokenTarg.responseToken);
data_blob_free(&spnego->negTokenTarg.mechListMIC);
break;
default:
ret = False;
break;
}
ZERO_STRUCTP(spnego);
out:
return ret;
On Jun 2, 12:37 am, Bradley Beddoes <bedd...@intient.com> wrote:
> Hello,
> Martijn van der Plaat wrote:
> > Hi Bradley,
> > At the moment i don't have much pratical experience with Samba. I dont
> > really understand the function of SPNEGO.
> This wikipedia article and associated (linked) RFC's etc may be of
> assistance to youhttp://en.wikipedia.org/wiki/SPNEGO
> > I know that SAMBA can be configured with LDAP as backend. On the ESOE
> > website i saw the graphical picture with LDAP as a possible solution
> > beside the Windows Login service (that is i think the Active Directory
> > integration you mean).
> > So the trick lays in the LDAP session? If that LDAP connection to ESOE
> > in the picture means that the LDAP session can be integrated in ESOE
> > it would be great. But again i don't fully understand how things
> > work.
> Essentially your looking at either using native LDAP integration or
> SPNEGO support (you can use both in sequence, if ESOE detects no SPNEGO
> support it will fall through to native LDAP support with an associated
> web form).
> > Maybe you can tell how to do this? I want to take effort in realising
> > this SAMBA-ESOE connection.
> Basically you'd want to configure your PDC and the ESOE to utilize the
> same LDAP server for authentication. When a user logs into their
> workstation their credentials will ultimately be validated against this
> LDAP server. Once this is completed (assuming Samba support for SPNEGO
> is a go) their Windows machines will have access to tokens which ESOE
> (also configured to talk to your PDC) can accept and validate.
> For users not logged into the domain (off site for example) they will be
> presented with a web form to enter their credentials for initial
> authentication, this will be validated directly against your LDAP server
> (no PDC involvement at all here).
> By going with this approach you only have a single store of
> users/credentials and for end users this means the same
> username/password to access their workstations and web tier content.
> The next step is probably to figure out just what level of SPNEGO
> support a SAMBA PDC exports, if it can give everything we require on the
> previous configuration URL i sent you then its probably good to go.
> regards,
> Bradley
> > Greets.
> > Martijn van der Plaat
> > On 1 jun, 08:13, Bradley Beddoes <bedd...@intient.com> wrote:
> >> Hi,
> >> We already have an authentication mechanism in place which allows ESOE
> >> to integrate with a domain controller setup provided by Windows servers
> >> which we've documented here:http://esoeproject.org/confluence/display/eu/ESOE+to+Active+Directory...
> >> Essentially this allows a user to login to their workstation of a
> >> morning and automatically be provided access to ESOE services we call
> >> this "true single sign on" and the clients we have who've deployed it
> >> really love it. In the back end there is a bunch of SPNEGO ticket
> >> validation going on.
> >> Does the Samba PDC provide the SPNEGO type functionality? If so it may
> >> not be much effort to test an ESOE setup against a Samba PDC and
> >> validate this works.
> >> I hope I've interpreted your query below correctly, please correct me if
> >> I've totally misread your requirements :).
> >> regards,
> >> Bradley
> >> --
> >> Bradley Beddoes
> >> Lead Software Architect
> >> Intient Pty Ltd
> >> Join me on LinkedIn:http://www.linkedin.com/in/beddoes
> >> Martijn van der Plaat wrote:
> >>> Hi all,
> >>> I was wondering if it is possible when SAMBA is configured with LDAP
> >>> as authentication backend and ESOE is configured with LDAP as
> >>> authentication source the SAMBA session is available in ESOE.
> >>> This connection is great because when as user logs in to the PDC the
> >>> user is also connected to the applications that are connected to ESOE
> >>> like blackboard, Google Apps, or OpenID or some other application.
> >>> Greets Martijn.
> --
> Bradley Beddoes
> Lead Software Architect
> Intient Pty Ltd
> Join me on LinkedIn:http://www.linkedin.com/in/beddoes- Hide quoted text -
> - Show quoted text -