[SCM] Samba Shared Repository - branch master updated
Stefan Metzmacher
metze at samba.org
Wed May 18 00:49:02 MDT 2011
The branch, master has been updated
via 902b1d9 s4:ntvfs/cifs: return NT_STATUS_INTERNAL_ERROR if no credentials are available
via a7b8593 s4:kdc: split s4u2self and s4u2proxy checks
via 5f48c5d s4:kdc: UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION => flags.trusted_for_delegation
via 053ef0f s4:auth/credentials: S4U2Self should force CRED_MUST_USE_KERBEROS
via a41efe6 s4:auth/credentials: pass 'self_service' to cli_credentials_set_impersonate_principal()
via c6836c8 s4:gensec_gssapi: avoid delegation if s4u2self/proxy is used
via 2c46585 HEIMDAL:kdc: check and regenerate the PAC in the s4u2proxy case
via 3797e46 HEIMDAL:kdc: pass the correct principal name for the resulting service ticket
via cc0ff48 HEIMDAL:kdc: let check_PAC() to verify the incoming server and krbtgt cheksums
from 2873429 Fix bug #8144 - touch /mnt/newfile fails to set timestamp with CIFS client.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 902b1d9a19ca8bbc32c3cf1f67efd9cf6627d711
Author: Stefan Metzmacher <metze at samba.org>
Date: Mon May 2 12:51:58 2011 +0200
s4:ntvfs/cifs: return NT_STATUS_INTERNAL_ERROR if no credentials are available
This is a configuration problem on the server, no invalid parameter
from the client.
metze
Autobuild-User: Stefan Metzmacher <metze at samba.org>
Autobuild-Date: Wed May 18 08:49:00 CEST 2011 on sn-devel-104
commit a7b8593f9c8f43f7861d2a0bc0e249f17d8ce7f5
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Apr 7 11:16:55 2011 +0200
s4:kdc: split s4u2self and s4u2proxy checks
metze
commit 5f48c5df513eecaff162e72bfeff39b9390710e7
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Apr 7 12:16:16 2011 +0200
s4:kdc: UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION => flags.trusted_for_delegation
metze
commit 053ef0f605e8e99bf10e784cf383f954a6940d0a
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Apr 28 17:10:03 2011 +0200
s4:auth/credentials: S4U2Self should force CRED_MUST_USE_KERBEROS
Otherwise we would not impersonate the desired principal.
This still doesn't work for plaintext auth, but should
avoid ntlmssp.
metze
commit a41efe6802da4e81a4af72aa231daa00f5012ab8
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Apr 22 11:22:50 2011 +0200
s4:auth/credentials: pass 'self_service' to cli_credentials_set_impersonate_principal()
This also adds a cli_credentials_get_self_service() helper function.
In order to support S4U2Proxy we need to be able to set
the service principal for the S4U2Self step independent of the
target principal.
metze
commit c6836c8ede90a97a31c208a0057cffe78ed5a3d9
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Mar 25 15:44:50 2011 +0100
s4:gensec_gssapi: avoid delegation if s4u2self/proxy is used
metze
commit 2c46585a428eb224755892884af6bcb0d16df463
Author: Stefan Metzmacher <metze at samba.org>
Date: Thu Apr 7 14:40:54 2011 +0200
HEIMDAL:kdc: check and regenerate the PAC in the s4u2proxy case
TODO: we need to add a S4U_DELEGATION_INFO to the PAC later.
metze
commit 3797e465439ec146cde2b041a553c6dcf1eb9683
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Mar 25 12:36:14 2011 +0100
HEIMDAL:kdc: pass the correct principal name for the resulting service ticket
Depending on S4U2Proxy the principal name for the resulting
ticket is not the principal of the client ticket.
metze
commit cc0ff48f28d13fd155489e08f75e64ff0e11b1de
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Mar 25 14:57:42 2011 +0100
HEIMDAL:kdc: let check_PAC() to verify the incoming server and krbtgt cheksums
For a normal TGS-REQ they're both signed with krbtgt key.
But for S4U2Proxy requests which ask for contrained delegation,
the keys differ.
metze
-----------------------------------------------------------------------
Summary of changes:
source4/auth/credentials/credentials.c | 1 +
source4/auth/credentials/credentials.h | 6 +-
source4/auth/credentials/credentials_krb5.c | 25 +++++-
source4/auth/gensec/gensec_gssapi.c | 4 +
source4/auth/kerberos/kerberos_util.c | 8 ++-
source4/heimdal/kdc/krb5tgs.c | 130 ++++++++++++++++-----------
source4/kdc/db-glue.c | 43 +++++++--
source4/kdc/db-glue.h | 14 ++-
source4/kdc/hdb-samba4.c | 27 +++++--
source4/kdc/mit_samba.c | 8 +-
source4/ntvfs/cifs/vfs_cifs.c | 2 +-
source4/torture/rpc/remote_pac.c | 7 +-
12 files changed, 189 insertions(+), 86 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c
index 015c549..83e9034 100644
--- a/source4/auth/credentials/credentials.c
+++ b/source4/auth/credentials/credentials.c
@@ -64,6 +64,7 @@ _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
cred->principal = NULL;
cred->salt_principal = NULL;
cred->impersonate_principal = NULL;
+ cred->self_service = NULL;
cred->target_service = NULL;
cred->bind_dn = NULL;
diff --git a/source4/auth/credentials/credentials.h b/source4/auth/credentials/credentials.h
index 0b0de59..f8fa2f8 100644
--- a/source4/auth/credentials/credentials.h
+++ b/source4/auth/credentials/credentials.h
@@ -84,6 +84,7 @@ struct cli_credentials {
const char *principal;
char *salt_principal;
char *impersonate_principal;
+ char *self_service;
char *target_service;
const char *bind_dn;
@@ -277,10 +278,13 @@ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials,
void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
enum credentials_obtained obtained);
void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal);
-void cli_credentials_set_impersonate_principal(struct cli_credentials *cred, const char *principal);
+void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
+ const char *principal,
+ const char *self_service);
void cli_credentials_set_target_service(struct cli_credentials *cred, const char *principal);
const char *cli_credentials_get_salt_principal(struct cli_credentials *cred);
const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred);
+const char *cli_credentials_get_self_service(struct cli_credentials *cred);
const char *cli_credentials_get_target_service(struct cli_credentials *cred);
enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds);
enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds);
diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c
index d3925a0..bfba167 100644
--- a/source4/auth/credentials/credentials_krb5.c
+++ b/source4/auth/credentials/credentials_krb5.c
@@ -788,19 +788,36 @@ _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, c
* member of the domain to get the groups of a user. This is also
* known as S4U2Self */
-const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
{
return cred->impersonate_principal;
}
-_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred, const char *principal)
+/*
+ * The 'self_service' is the service principal that
+ * represents the same object (by its objectSid)
+ * as the client principal (typically our machine account).
+ * When trying to impersonate 'impersonate_principal' with
+ * S4U2Self.
+ */
+_PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
+{
+ return cred->self_service;
+}
+
+_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
+ const char *principal,
+ const char *self_service)
{
talloc_free(cred->impersonate_principal);
cred->impersonate_principal = talloc_strdup(cred, principal);
+ talloc_free(cred->self_service);
+ cred->self_service = talloc_strdup(cred, self_service);
+ cli_credentials_set_kerberos_state(cred, CRED_MUST_USE_KERBEROS);
}
-/* when impersonating for S4U2Self we need to set the target principal
- * to ourself, as otherwise we would need additional rights.
+/*
+ * when impersonating for S4U2proxy we need to set the target principal.
* Similarly, we may only be authorized to do general impersonation to
* some particular services.
*
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 4bdd7f8..47f4774 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -302,6 +302,10 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
+ if (cli_credentials_get_impersonate_principal(creds)) {
+ gensec_gssapi_state->want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
+ }
+
gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
if (gensec_gssapi_state->target_principal) {
name_type = GSS_C_NULL_OID;
diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c
index 45b0b07..f05016b 100644
--- a/source4/auth/kerberos/kerberos_util.c
+++ b/source4/auth/kerberos/kerberos_util.c
@@ -338,7 +338,9 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
const char **error_string)
{
krb5_error_code ret;
- const char *password, *target_service;
+ const char *password;
+ const char *self_service;
+ const char *target_service;
time_t kdc_time = 0;
krb5_principal princ;
krb5_principal impersonate_principal;
@@ -363,6 +365,7 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
return ret;
}
+ self_service = cli_credentials_get_self_service(credentials);
target_service = cli_credentials_get_target_service(credentials);
password = cli_credentials_get_password(credentials);
@@ -403,7 +406,8 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
if (password) {
ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache,
princ, password,
- impersonate_principal, target_service,
+ impersonate_principal,
+ self_service,
krb_options,
NULL, &kdc_time);
} else if (impersonate_principal) {
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index 037934f..66170cb 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -282,8 +282,9 @@ check_PAC(krb5_context context,
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
- const EncryptionKey *server_key,
+ const EncryptionKey *server_check_key,
const EncryptionKey *krbtgt_check_key,
+ const EncryptionKey *server_sign_key,
const EncryptionKey *krbtgt_sign_key,
EncTicketPart *tkt,
krb5_data *rspac,
@@ -328,7 +329,7 @@ check_PAC(krb5_context context,
ret = krb5_pac_verify(context, pac, tkt->authtime,
client_principal,
- krbtgt_check_key, NULL);
+ server_check_key, krbtgt_check_key);
if (ret) {
krb5_pac_free(context, pac);
return ret;
@@ -351,7 +352,7 @@ check_PAC(krb5_context context,
*signedpath = 1;
ret = _krb5_pac_sign(context, pac, tkt->authtime,
client_principal,
- server_key, krbtgt_sign_key, rspac);
+ server_sign_key, krbtgt_sign_key, rspac);
}
krb5_pac_free(context, pac);
@@ -1464,10 +1465,9 @@ tgs_build_reply(krb5_context context,
const struct sockaddr *from_addr)
{
krb5_error_code ret;
- krb5_principal cp = NULL, sp = NULL;
- krb5_principal client_principal = NULL;
+ krb5_principal cp = NULL, sp = NULL, tp = NULL;
krb5_principal krbtgt_principal = NULL;
- char *spn = NULL, *cpn = NULL;
+ char *spn = NULL, *cpn = NULL, *tpn = NULL;
hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
HDB *clientdb, *s4u2self_impersonated_clientdb;
krb5_realm ref_realm = NULL;
@@ -1719,16 +1719,16 @@ server_lookup:
krb5_free_principal(context, krbtgt_principal);
if (ret) {
krb5_error_code ret2;
- char *tpn, *tpn2;
- ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
- ret2 = krb5_unparse_name(context, krbtgt->entry.principal, &tpn2);
+ char *ktpn, *ktpn2;
+ ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
+ ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
kdc_log(context, config, 0,
"Request with wrong krbtgt: %s, %s not found in our database",
- (ret == 0) ? tpn : "<unknown>", (ret2 == 0) ? tpn2 : "<unknown>");
+ (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
if(ret == 0)
- free(tpn);
+ free(ktpn);
if(ret2 == 0)
- free(tpn2);
+ free(ktpn2);
ret = KRB5KRB_AP_ERR_NOT_US;
goto out;
}
@@ -1740,13 +1740,13 @@ server_lookup:
* this) before the strcmp() */
if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
- char *tpn;
- ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &tpn);
+ char *ktpn;
+ ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
kdc_log(context, config, 0,
"Request with wrong krbtgt: %s",
- (ret == 0) ? tpn : "<unknown>");
+ (ret == 0) ? ktpn : "<unknown>");
if(ret == 0)
- free(tpn);
+ free(ktpn);
ret = KRB5KRB_AP_ERR_NOT_US;
}
@@ -1789,7 +1789,9 @@ server_lookup:
}
ret = check_PAC(context, config, cp,
- client, server, krbtgt, ekey, &tkey_check->key, &tkey_sign->key,
+ client, server, krbtgt,
+ &tkey_check->key, &tkey_check->key,
+ ekey, &tkey_sign->key,
tgt, &rspac, &signedpath);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
@@ -1821,7 +1823,9 @@ server_lookup:
* Process request
*/
- client_principal = cp;
+ /* by default the tgt principal matches the client principal */
+ tp = cp;
+ tpn = cpn;
if (client) {
const PA_DATA *sdata;
@@ -1832,7 +1836,6 @@ server_lookup:
krb5_crypto crypto;
krb5_data datack;
PA_S4U2Self self;
- char *selfcpn = NULL;
const char *str;
ret = decode_PA_S4U2Self(sdata->padata_value.data,
@@ -1875,14 +1878,14 @@ server_lookup:
}
ret = _krb5_principalname2krb5_principal(context,
- &client_principal,
+ &tp,
self.name,
self.realm);
free_PA_S4U2Self(&self);
if (ret)
goto out;
- ret = krb5_unparse_name(context, client_principal, &selfcpn);
+ ret = krb5_unparse_name(context, tp, &tpn);
if (ret)
goto out;
@@ -1890,7 +1893,7 @@ server_lookup:
if(rspac.data) {
krb5_pac p = NULL;
krb5_data_free(&rspac);
- ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON,
+ ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | HDB_F_CANON,
NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
if (ret) {
const char *msg;
@@ -1904,14 +1907,16 @@ server_lookup:
if (ret == HDB_ERR_NOENTRY)
ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 1, "S2U4Self principal to impersonate %s not found in database: %s", cpn, msg);
+ kdc_log(context, config, 1,
+ "S2U4Self principal to impersonate %s not found in database: %s",
+ tpn, msg);
krb5_free_error_message(context, msg);
goto out;
}
ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
if (ret) {
kdc_log(context, config, 0, "PAC generation failed for -- %s",
- selfcpn);
+ tpn);
goto out;
}
if (p != NULL) {
@@ -1922,7 +1927,7 @@ server_lookup:
krb5_pac_free(context, p);
if (ret) {
kdc_log(context, config, 0, "PAC signing failed for -- %s",
- selfcpn);
+ tpn);
goto out;
}
}
@@ -1937,8 +1942,7 @@ server_lookup:
kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
"to impersonate to service "
"(tried for user %s to service %s)",
- cpn, selfcpn, spn);
- free(selfcpn);
+ cpn, tpn, spn);
goto out;
}
@@ -1954,8 +1958,7 @@ server_lookup:
str = "";
}
kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
- "service %s %s", cpn, selfcpn, spn, str);
- free(selfcpn);
+ "service %s %s", cpn, tpn, spn, str);
}
}
@@ -1971,7 +1974,6 @@ server_lookup:
int ad_signedpath = 0;
Key *clientkey;
Ticket *t;
- char *str;
/*
* Require that the KDC have issued the service's krbtgt (not
@@ -2002,11 +2004,23 @@ server_lookup:
goto out;
}
+ ret = _krb5_principalname2krb5_principal(context,
+ &tp,
+ adtkt.cname,
+ adtkt.crealm);
+ if (ret)
+ goto out;
+
+ ret = krb5_unparse_name(context, tp, &tpn);
+ if (ret)
+ goto out;
+
/* check that ticket is valid */
if (adtkt.flags.forwardable == 0) {
kdc_log(context, config, 0,
"Missing forwardable flag on ticket for "
- "constrained delegation from %s to %s ", cpn, spn);
+ "constrained delegation from %s as %s to %s ",
+ cpn, tpn, spn);
ret = KRB5KDC_ERR_BADOPTION;
goto out;
}
@@ -2015,25 +2029,37 @@ server_lookup:
client, sp);
if (ret) {
kdc_log(context, config, 0,
- "constrained delegation from %s to %s not allowed",
- cpn, spn);
+ "constrained delegation from %s as %s to %s not allowed",
+ cpn, tpn, spn);
goto out;
}
- ret = _krb5_principalname2krb5_principal(context,
- &client_principal,
- adtkt.cname,
- adtkt.crealm);
- if (ret)
- goto out;
-
- ret = krb5_unparse_name(context, client_principal, &str);
- if (ret)
+ ret = verify_flags(context, config, &adtkt, tpn);
+ if (ret) {
goto out;
+ }
- ret = verify_flags(context, config, &adtkt, str);
+ krb5_data_free(&rspac);
+ /*
+ * generate the PAC for the user.
+ *
+ * TODO: pass in t->sname and t->realm and build
+ * a S4U_DELEGATION_INFO blob to the PAC.
+ */
+ ret = check_PAC(context, config, tp,
+ client, server, krbtgt,
+ &clientkey->key, &tkey_check->key,
+ ekey, &tkey_sign->key,
+ &adtkt, &rspac, &ad_signedpath);
+ if (ret == 0 && !ad_signedpath)
+ ret = KRB5KDC_ERR_BADOPTION;
if (ret) {
- free(str);
+ const char *msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 0,
+ "Verify delegated PAC failed to %s for client"
+ "%s as %s from %s with %s",
+ spn, cpn, tpn, from, msg);
+ krb5_free_error_message(context, msg);
goto out;
}
@@ -2043,7 +2069,7 @@ server_lookup:
ret = check_KRB5SignedPath(context,
config,
krbtgt,
- cp,
+ tp,
&adtkt,
NULL,
&ad_signedpath);
@@ -2055,15 +2081,13 @@ server_lookup:
"KRB5SignedPath check from service %s failed "
"for delegation to %s for client %s "
"from %s failed with %s",
- spn, str, cpn, from, msg);
+ spn, tpn, cpn, from, msg);
krb5_free_error_message(context, msg);
- free(str);
goto out;
}
kdc_log(context, config, 0, "constrained delegation for %s "
- "from %s to %s", str, cpn, spn);
- free(str);
+ "from %s to %s", tpn, cpn, spn);
}
/*
@@ -2134,7 +2158,7 @@ server_lookup:
ret = tgs_make_reply(context,
config,
b,
- client_principal,
+ tp,
tgt,
replykey,
rk_is_subkey,
@@ -2156,6 +2180,8 @@ server_lookup:
reply);
out:
+ if (tpn != cpn)
+ free(tpn);
free(spn);
free(cpn);
@@ -2170,8 +2196,8 @@ out:
if(s4u2self_impersonated_client)
_kdc_free_ent(context, s4u2self_impersonated_client);
- if (client_principal && client_principal != cp)
- krb5_free_principal(context, client_principal);
+ if (tp && tp != cp)
+ krb5_free_principal(context, tp);
if (cp)
krb5_free_principal(context, cp);
if (sp)
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 732e553..72262ac 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -159,6 +159,20 @@ static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, e
if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
flags.ok_as_delegate = 1;
}
+ if (userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
+ /*
+ * this is confusing...
+ *
+ * UF_TRUSTED_FOR_DELEGATION
+ * => ok_as_delegate
+ *
+ * and
+ *
+ * UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
+ * => trusted_for_delegation
+ */
+ flags.trusted_for_delegation = 1;
+ }
if (!(userAccountControl & UF_NOT_DELEGATED)) {
flags.forwardable = 1;
flags.proxiable = 1;
@@ -1521,14 +1535,12 @@ krb5_error_code samba_kdc_nextkey(krb5_context context,
/* Check if a given entry may delegate or do s4u2self to this target principal
*
* This is currently a very nasty hack - allowing only delegation to itself.
- *
- * This is shared between the constrained delegation and S4U2Self code.
*/
krb5_error_code
-samba_kdc_check_identical_client_and_server(krb5_context context,
- struct samba_kdc_db_context *kdc_db_ctx,
- hdb_entry_ex *entry,
- krb5_const_principal target_principal)
--
Samba Shared Repository
More information about the samba-cvs
mailing list