r10860: r13507@SERNOX (orig r10836): metze | 2005-10-08 18:35:33 +0200
authorStefan Metzmacher <metze@samba.org>
Mon, 10 Oct 2005 06:37:57 +0000 (06:37 +0000)
committerStefan Metzmacher <metze@samba.org>
Mon, 10 Oct 2005 06:37:57 +0000 (06:37 +0000)
 giving NT_STATUS_NO_MEMORY, when the connection fails wasn't a good idea...

 metze
 r13509@SERNOX (orig r10838):  vlendec | 2005-10-08 19:45:27 +0200
 Get us an schannel'ed netlogon pipe.

 Abartlet, now I think I need some assistance to implement the pam auth & crap
 auth calls.

 Volker

 r13510@SERNOX (orig r10839):  jelmer | 2005-10-08 19:55:28 +0200
 Add some [ref] (required for ethereal and Samba3 parser generators)

 r13511@SERNOX (orig r10840):  jelmer | 2005-10-08 19:55:56 +0200
 Fix indentation

 r13513@SERNOX (orig r10842):  jelmer | 2005-10-08 22:19:35 +0200
 Fix some issues with [out] unions that have a discriminator that is only
 [in]

 r13514@SERNOX (orig r10843):  vlendec | 2005-10-09 10:32:06 +0200
 Reformatting
 r13515@SERNOX (orig r10844):  abartlet | 2005-10-09 14:13:05 +0200
 Add challenge-response authentication to Samba4's winbindd for VL.

 Plaintext should be simple, but I'm going to do some infrustructure
 work first.

 Andrew Bartlett

 r13516@SERNOX (orig r10845):  abartlet | 2005-10-09 14:38:23 +0200
 Add new function to decrypt the session keys in samlogon responses.

 Andrew Bartlett

 r13517@SERNOX (orig r10846):  vlendec | 2005-10-09 14:50:35 +0200
 Create a "wbsrv_domain", change wb_finddcs to the style of the rest of the
 async helpers.

 Volker

 r13518@SERNOX (orig r10847):  abartlet | 2005-10-09 15:03:52 +0200
 Fix up new 'decrypt samlogon reply' routine to be more robust, and use
 it in the RPC-SAMLOGON test.

 Andrew Bartlett

 r13519@SERNOX (orig r10848):  jelmer | 2005-10-09 15:40:55 +0200
 Fix warning

 r13520@SERNOX (orig r10849):  jelmer | 2005-10-09 15:53:48 +0200
 Fix handling of [charset] for strings with fixed or "inline" size

 r13523@SERNOX (orig r10852):  vlendec | 2005-10-09 22:32:24 +0200
 Continuation-based programming can become a bit spaghetti...

 Initialize a domain structure properly. Excerpt from wb_init_domain.c:

 /*
  * Initialize a domain:
  *
  * - With schannel credentials, try to open the SMB connection with the machine
  *   creds. Fall back to anonymous.
  *
  * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
  *   pipe.
  *
  * - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
  *   to schannel and then to anon bind.
  *
  * - With queryinfopolicy, verify that we're talking to the right domain
  *
  * A bit complex, but with all the combinations I think it's the best we can
  * get. NT4, W2k3SP1 and W2k all have different combinations, but in the end we
  * have a signed&sealed lsa connection on all of them.
  *
  * Is this overkill? In particular the authenticated SMB connection seems a
  * bit overkill, given that we do schannel for netlogon and ntlmssp for
  * lsa later on w2k3, the others don't do this anyway.
  */

 Thanks to Jeremy for his detective work, and to the Samba4 team for providing
 such a great infrastructure.

 Next step is to connect to SAM. Do it via LDAP if we can, fall back to samr
 with all we have.

 Volker

 r13524@SERNOX (orig r10853):  vlendec | 2005-10-09 22:57:49 +0200
 Convert wbinfo -n to properly init the domain.

 Volker

 r13525@SERNOX (orig r10854):  jelmer | 2005-10-09 23:30:41 +0200
 talloc_get_type() can return NULL..

 r13526@SERNOX (orig r10855):  abartlet | 2005-10-10 00:19:20 +0200
 Put the domain SID in secrets.ldb by default, and add http as a
 default SPN alias.

 Andrew Bartlett

 r13527@SERNOX (orig r10856):  tridge | 2005-10-10 01:29:26 +0200
 we need aclocal.m4 in ldb for standalone configure
 r13530@SERNOX (orig r10859):  vlendec | 2005-10-10 08:18:17 +0200
 Make the flow a bit clearer

27 files changed:
samba4-winsrepl/source/include/structs.h
samba4-winsrepl/source/lib/ldb/aclocal.m4 [new file with mode: 0644]
samba4-winsrepl/source/lib/ldb/tests/slapd.conf [new file with mode: 0644]
samba4-winsrepl/source/libcli/auth/credentials.c [new file with mode: 0644]
samba4-winsrepl/source/libcli/composite/composite.c
samba4-winsrepl/source/libcli/nbt/nbtname.c
samba4-winsrepl/source/libcli/wrepl/winsrepl.c
samba4-winsrepl/source/librpc/idl/dfs.idl [new file with mode: 0644]
samba4-winsrepl/source/nsswitch/winbindd_nss.h
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba/NDR/Client.pm
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba/NDR/Parser.pm
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba3/Client.pm
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba3/Header.pm
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba3/Parser.pm
samba4-winsrepl/source/pidl/lib/Parse/Pidl/Samba3/Types.pm
samba4-winsrepl/source/rpc_server/spoolss/dcesrv_spoolss.c [new file with mode: 0644]
samba4-winsrepl/source/setup/provision.ldif [new file with mode: 0644]
samba4-winsrepl/source/setup/secrets.ldif [new file with mode: 0644]
samba4-winsrepl/source/torture/rpc/samlogon.c
samba4-winsrepl/source/winbind/config.mk
samba4-winsrepl/source/winbind/wb_async_helpers.c
samba4-winsrepl/source/winbind/wb_async_helpers.h
samba4-winsrepl/source/winbind/wb_init_domain.c [new file with mode: 0644]
samba4-winsrepl/source/winbind/wb_samba3_cmd.c
samba4-winsrepl/source/winbind/wb_samba3_protocol.c
samba4-winsrepl/source/winbind/wb_server.c
samba4-winsrepl/source/winbind/wb_server.h

index 86c134de59c60cc7041e48a6f7dd01d47666ba4a..882fddb0467531bca3a37c2ee9be63bcea1a7a06 100644 (file)
@@ -215,6 +215,8 @@ struct lsa_RightSet;
 
 struct composite_context;
 struct monitor_msg;
+struct irpc_request;
+struct rpc_request;
 
 struct smb_composite_loadfile;
 struct smb_composite_savefile;
@@ -259,7 +261,7 @@ struct nbtd_server;
 struct nbtd_interface;
 struct wins_server;
 
-struct wb_finddcs;
+struct nbt_dc_name;
 struct wb_sid_object;
 
 struct cldap_socket;
@@ -308,6 +310,7 @@ struct samba3_share_info;
 struct samba3;
 
 struct wbsrv_service;
+struct wbsrv_domain;
 struct wbsrv_protocol_ops;
 struct wbsrv_listen_socket;
 struct wbsrv_connection;
diff --git a/samba4-winsrepl/source/lib/ldb/aclocal.m4 b/samba4-winsrepl/source/lib/ldb/aclocal.m4
new file mode 100644 (file)
index 0000000..cdc2a2f
--- /dev/null
@@ -0,0 +1,12 @@
+dnl see if a declaration exists for a function or variable
+dnl defines HAVE_function_DECL if it exists
+dnl AC_HAVE_DECL(var, includes)
+AC_DEFUN(AC_HAVE_DECL,
+[
+ AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[
+    AC_TRY_COMPILE([$2],[int i = (int)$1],
+        ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)])
+ if test x"$ac_cv_have_$1_decl" = x"yes"; then
+    AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL],1,[Whether $1() is available])
+ fi
+])
diff --git a/samba4-winsrepl/source/lib/ldb/tests/slapd.conf b/samba4-winsrepl/source/lib/ldb/tests/slapd.conf
new file mode 100644 (file)
index 0000000..fc9d659
--- /dev/null
@@ -0,0 +1,27 @@
+loglevel 0
+
+include tests/schema/core.schema
+include tests/schema/cosine.schema
+include tests/schema/inetorgperson.schema
+include tests/schema/openldap.schema
+include tests/schema/nis.schema
+
+
+pidfile                tests/tmp/slapd.pid
+argsfile       tests/tmp/slapd.args
+
+access to * by * write
+
+allow update_anon bind_anon_dn
+
+modulepath     /usr/lib/ldap
+moduleload     back_bdb
+
+defaultsearchbase "o=University of Michigan,c=TEST"
+
+backend                bdb
+database        bdb
+suffix         "o=University of Michigan,c=TEST"
+directory      tests/tmp/db
+index           objectClass eq
+index           uid eq
diff --git a/samba4-winsrepl/source/libcli/auth/credentials.c b/samba4-winsrepl/source/libcli/auth/credentials.c
new file mode 100644 (file)
index 0000000..3f055a6
--- /dev/null
@@ -0,0 +1,375 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   code to manipulate domain credentials
+
+   Copyright (C) Andrew Tridgell 1997-2003
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+   
+   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"
+#include "system/time.h"
+#include "auth/auth.h"
+#include "lib/crypto/crypto.h"
+
+/*
+  initialise the credentials state for old-style 64 bit session keys
+
+  this call is made after the netr_ServerReqChallenge call
+*/
+static void creds_init_64bit(struct creds_CredentialState *creds,
+                            const struct netr_Credential *client_challenge,
+                            const struct netr_Credential *server_challenge,
+                            const struct samr_Password *machine_password)
+{
+       uint32_t sum[2];
+       uint8_t sum2[8];
+
+       sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
+       sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
+
+       SIVAL(sum2,0,sum[0]);
+       SIVAL(sum2,4,sum[1]);
+
+       ZERO_STRUCT(creds->session_key);
+
+       des_crypt128(creds->session_key, sum2, machine_password->hash);
+
+       des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
+       des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
+
+       creds->seed = creds->client;
+}
+
+/*
+  initialise the credentials state for ADS-style 128 bit session keys
+
+  this call is made after the netr_ServerReqChallenge call
+*/
+static void creds_init_128bit(struct creds_CredentialState *creds,
+                             const struct netr_Credential *client_challenge,
+                             const struct netr_Credential *server_challenge,
+                             const struct samr_Password *machine_password)
+{
+       unsigned char zero[4], tmp[16];
+       HMACMD5Context ctx;
+       struct MD5Context md5;
+
+       ZERO_STRUCT(creds->session_key);
+
+       memset(zero, 0, sizeof(zero));
+
+       hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
+       MD5Init(&md5);
+       MD5Update(&md5, zero, sizeof(zero));
+       MD5Update(&md5, client_challenge->data, 8);
+       MD5Update(&md5, server_challenge->data, 8);
+       MD5Final(tmp, &md5);
+       hmac_md5_update(tmp, sizeof(tmp), &ctx);
+       hmac_md5_final(creds->session_key, &ctx);
+
+       creds->client = *client_challenge;
+       creds->server = *server_challenge;
+
+       des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
+       des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
+
+       creds->seed = creds->client;
+}
+
+
+/*
+  step the credentials to the next element in the chain, updating the
+  current client and server credentials and the seed
+*/
+static void creds_step(struct creds_CredentialState *creds)
+{
+       struct netr_Credential time_cred;
+
+       DEBUG(5,("\tseed        %08x:%08x\n", 
+                IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
+
+       SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
+       SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+       DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+       des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
+
+       DEBUG(5,("\tCLIENT      %08x:%08x\n", 
+                IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
+
+       SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
+       SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+       DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
+                IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+       des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
+
+       DEBUG(5,("\tSERVER      %08x:%08x\n", 
+                IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
+
+       creds->seed = time_cred;
+}
+
+
+/*
+  DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
+{
+       struct netr_LMSessionKey tmp;
+       des_crypt56(tmp.key, key->key, creds->session_key, 1);
+       *key = tmp;
+}
+
+/*
+  DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
+{
+       struct netr_LMSessionKey tmp;
+       des_crypt56(tmp.key, key->key, creds->session_key, 0);
+       *key = tmp;
+}
+
+/*
+  DES encrypt a 16 byte password buffer using the session key
+*/
+void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
+{
+       struct samr_Password tmp;
+       des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
+       *pass = tmp;
+}
+
+/*
+  DES decrypt a 16 byte password buffer using the session key
+*/
+void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
+{
+       struct samr_Password tmp;
+       des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
+       *pass = tmp;
+}
+
+/*
+  ARCFOUR encrypt/decrypt a password buffer using the session key
+*/
+void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
+{
+       DATA_BLOB session_key = data_blob(creds->session_key, 16);
+
+       arcfour_crypt_blob(data, len, &session_key);
+
+       data_blob_free(&session_key);
+}
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the client specific functions
+******************************************************************/
+
+/*
+  initialise the credentials chain and return the first client
+  credentials
+*/
+void creds_client_init(struct creds_CredentialState *creds,
+                      const struct netr_Credential *client_challenge,
+                      const struct netr_Credential *server_challenge,
+                      const struct samr_Password *machine_password,
+                      struct netr_Credential *initial_credential,
+                      uint32_t negotiate_flags)
+{
+       creds->sequence = time(NULL);
+       creds->negotiate_flags = negotiate_flags;
+
+       dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
+       dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
+       dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
+
+       if (negotiate_flags & NETLOGON_NEG_128BIT) {
+               creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
+       } else {
+               creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
+       }
+
+       dump_data_pw("Session key", creds->session_key, 16);
+       dump_data_pw("Credential ", creds->client.data, 8);
+
+       *initial_credential = creds->client;
+}
+
+/*
+  step the credentials to the next element in the chain, updating the
+  current client and server credentials and the seed
+
+  produce the next authenticator in the sequence ready to send to 
+  the server
+*/
+void creds_client_authenticator(struct creds_CredentialState *creds,
+                               struct netr_Authenticator *next)
+{      
+       creds->sequence += 2;
+       creds_step(creds);
+
+       next->cred = creds->client;
+       next->timestamp = creds->sequence;
+}
+
+/*
+  check that a credentials reply from a server is correct
+*/
+BOOL creds_client_check(struct creds_CredentialState *creds,
+                       const struct netr_Credential *received_credentials)
+{
+       if (!received_credentials || 
+           memcmp(received_credentials->data, creds->server.data, 8) != 0) {
+               DEBUG(2,("credentials check failed\n"));
+               return False;
+       }
+       return True;
+}
+
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the server specific functions
+******************************************************************/
+
+/*
+  initialise the credentials chain and return the first server
+  credentials
+*/
+void creds_server_init(struct creds_CredentialState *creds,
+                      const struct netr_Credential *client_challenge,
+                      const struct netr_Credential *server_challenge,
+                      const struct samr_Password *machine_password,
+                      struct netr_Credential *initial_credential,
+                      uint32_t negotiate_flags)
+{
+       if (negotiate_flags & NETLOGON_NEG_128BIT) {
+               creds_init_128bit(creds, client_challenge, server_challenge, 
+                                 machine_password);
+       } else {
+               creds_init_64bit(creds, client_challenge, server_challenge, 
+                                machine_password);
+       }
+
+       *initial_credential = creds->server;
+       creds->negotiate_flags = negotiate_flags;
+}
+
+/*
+  check that a credentials reply from a server is correct
+*/
+BOOL creds_server_check(const struct creds_CredentialState *creds,
+                       const struct netr_Credential *received_credentials)
+{
+       if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
+               DEBUG(2,("credentials check failed\n"));
+               dump_data_pw("client creds", creds->client.data, 8);
+               dump_data_pw("calc   creds", received_credentials->data, 8);
+               return False;
+       }
+       return True;
+}
+
+NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
+                                struct netr_Authenticator *received_authenticator,
+                                struct netr_Authenticator *return_authenticator) 
+{
+       if (!received_authenticator || !return_authenticator) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!creds) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* TODO: this may allow the a replay attack on a non-signed
+          connection. Should we check that this is increasing? */
+       creds->sequence = received_authenticator->timestamp;
+       creds_step(creds);
+       if (creds_server_check(creds, &received_authenticator->cred)) {
+               return_authenticator->cred = creds->server;
+               return_authenticator->timestamp = creds->sequence;
+               return NT_STATUS_OK;
+       } else {
+               ZERO_STRUCTP(return_authenticator);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+}
+
+void creds_decrypt_samlogon(struct creds_CredentialState *creds,
+                           uint16_t validation_level,
+                           union netr_Validation *validation) 
+{
+       static const char zeros[16];
+
+       struct netr_SamBaseInfo *base = NULL;
+       switch (validation_level) {
+       case 2:
+               if (validation->sam2) {
+                       base = &validation->sam2->base;
+               }
+               break;
+       case 3:
+               if (validation->sam3) {
+                       base = &validation->sam3->base;
+               }
+               break;
+       case 6:
+               if (validation->sam6) {
+                       base = &validation->sam6->base;
+               }
+               break;
+       default:
+               /* If we can't find it, we can't very well decrypt it */
+               return;
+       }
+
+       if (!base) {
+               return;
+       }
+
+       /* find and decyrpt the session keys, return in parameters above */
+       if (validation_level == 6) {
+               /* they aren't encrypted! */
+       } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+               if (memcmp(base->key.key, zeros,  
+                          sizeof(base->key.key)) != 0) {
+                       creds_arcfour_crypt(creds, 
+                                           base->key.key, 
+                                           sizeof(base->key.key));
+               }
+                       
+               if (memcmp(base->LMSessKey.key, zeros,  
+                          sizeof(base->LMSessKey.key)) != 0) {
+                       creds_arcfour_crypt(creds, 
+                                           base->LMSessKey.key, 
+                                           sizeof(base->LMSessKey.key));
+               }
+       } else {
+               if (memcmp(base->LMSessKey.key, zeros,  
+                          sizeof(base->LMSessKey.key)) != 0) {
+                       creds_des_decrypt_LMKey(creds, 
+                                               &base->LMSessKey);
+               }
+       }
+}      
index 4a5247c9ea9b434c040428df136a99fb6340a018..6458a971b434c4fdbc85dddf065213525333e24d 100644 (file)
@@ -25,7 +25,7 @@
 #include "lib/events/events.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
-
+#include "lib/messaging/irpc.h"
 
 /*
   block until a composite function has completed, then return the status
@@ -68,3 +68,75 @@ void composite_trigger_done(struct composite_context *c)
        /* a zero timeout means immediate */
        event_add_timed(c->event_ctx, c, timeval_zero(), composite_trigger, c);
 }
+
+
+/*
+ * Some composite helpers that are handy if you write larger composite
+ * functions.
+ */
+
+BOOL comp_is_ok(struct composite_context *ctx)
+{
+       if (NT_STATUS_IS_OK(ctx->status)) {
+               return True;
+       }
+       ctx->state = COMPOSITE_STATE_ERROR;
+       if (ctx->async.fn != NULL) {
+               ctx->async.fn(ctx);
+       }
+       return False;
+}
+
+void comp_error(struct composite_context *ctx, NTSTATUS status)
+{
+       ctx->status = status;
+       SMB_ASSERT(!comp_is_ok(ctx));
+}
+
+BOOL comp_nomem(const void *p, struct composite_context *ctx)
+{
+       if (p != NULL) {
+               return False;
+       }
+       comp_error(ctx, NT_STATUS_NO_MEMORY);
+       return True;
+}
+
+void comp_done(struct composite_context *ctx)
+{
+       ctx->state = COMPOSITE_STATE_DONE;
+       if (ctx->async.fn != NULL) {
+               ctx->async.fn(ctx);
+       }
+}
+
+void comp_cont(struct composite_context *ctx,
+              struct composite_context *new_ctx,
+              void (*continuation)(struct composite_context *),
+              void *private_data)
+{
+       if (comp_nomem(new_ctx, ctx)) return;
+       new_ctx->async.fn = continuation;
+       new_ctx->async.private_data = private_data;
+}
+
+void rpc_cont(struct composite_context *ctx,
+             struct rpc_request *new_req,
+             void (*continuation)(struct rpc_request *),
+             void *private_data)
+{
+       if (comp_nomem(new_req, ctx)) return;
+       new_req->async.callback = continuation;
+       new_req->async.private = private_data;
+}
+
+void irpc_cont(struct composite_context *ctx,
+              struct irpc_request *new_req,
+              void (*continuation)(struct irpc_request *),
+              void *private_data)
+{
+       if (comp_nomem(new_req, ctx)) return;
+       new_req->async.fn = continuation;
+       new_req->async.private = private_data;
+}
+
index 622d03c1f4a910873d90422cc63f498a36dc2f87..b0424b430fa93551d1287fac6bd12ccca49af2b0 100644 (file)
@@ -474,7 +474,7 @@ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
 /*
   pull a nbt name, WINS Replication uses another on wire format for nbt name
 */
-NTSTATUS ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r)
+NTSTATUS ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name **_r)
 {
        struct nbt_name *r;
        uint8_t *namebuf;
index 31ef1ffbebadbf2898015bda6e3a4e60b7ff8671..82abd766657f42c58f39e39de90976074e9456a5 100644 (file)
@@ -433,6 +433,7 @@ static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
        return req->status;
 }
 
+static void wrepl_request_trigger(struct wrepl_request *req);
 
 /*
   connect a wrepl_socket to a WINS server
@@ -459,7 +460,13 @@ struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
 
        status = socket_connect(wrepl_socket->sock, our_ip, 0, peer_ip, 
                                WINS_REPLICATION_PORT, 0);
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) goto failed;
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               req->wrepl_socket = wrepl_socket;
+               req->state        = WREPL_REQUEST_ERROR;
+               req->status       = status;
+               wrepl_request_trigger(req);
+               return req;
+       }
 
        return req;
 
diff --git a/samba4-winsrepl/source/librpc/idl/dfs.idl b/samba4-winsrepl/source/librpc/idl/dfs.idl
new file mode 100644 (file)
index 0000000..579d855
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+  dfs interface definition
+*/
+
+#include "idl_types.h"
+
+[ uuid("4fc742e0-4a10-11cf-8273-00aa004ae673"),
+  version(3.0),
+  pointer_default(unique),
+  helpstring("Settings for Microsoft Distributed File System")
+] interface netdfs
+{
+       /******************/
+       /* Function: 0x00 */
+       void dfs_GetManagerVersion(
+               [out] uint32 *exist_flag
+               );
+
+
+       /******************/
+       /* Function: 0x01 */
+       WERROR dfs_Add (
+               [in]             unistr *path,
+               [in]             unistr *server,
+               [in,unique]         unistr *share,
+               [in,unique]         unistr *comment,
+               [in]         uint32 flags
+               );
+
+       /******************/
+       /* Function: 0x02 */
+       WERROR dfs_Remove (
+               [in]                    unistr *path,
+               [in,unique]     unistr *server,
+               [in,unique]     unistr *share
+               );
+
+       /******************/
+       /* Function: 0x03 */
+       WERROR dfs_SetInfo ();
+
+       /******************/
+       /* Function: 0x04 */
+
+       typedef struct {
+       } dfs_Info0;
+
+       typedef struct {
+               unistr *path;
+       } dfs_Info1;
+
+       typedef struct {
+               unistr *path;
+               unistr *comment;
+               uint32 state;
+               uint32 num_stores;
+       } dfs_Info2;
+
+       typedef struct {
+               uint32 state;
+               unistr *server;
+               unistr *share;
+       } dfs_StorageInfo;
+
+       typedef struct {
+               unistr *path;
+               unistr *comment;
+               uint32 state;
+               uint32 num_stores;
+               [size_is(num_stores)] dfs_StorageInfo *stores;
+       } dfs_Info3;
+
+       typedef struct {
+               unistr *path;
+               unistr *comment;
+               uint32 state;
+               uint32 timeout;
+               GUID   guid;
+               uint32 num_stores;
+               [size_is(num_stores)] dfs_StorageInfo *stores;
+       } dfs_Info4;
+
+       typedef struct {
+               unistr *comment;
+       } dfs_Info100;
+
+       typedef struct {
+               uint32 state;
+       } dfs_Info101;
+
+       typedef struct {
+               uint32 timeout;
+       } dfs_Info102;
+
+       typedef struct {
+               unistr *dom_root;
+       } dfs_Info200;
+
+       typedef struct {
+               uint32 flags;
+               unistr *dom_root;
+       } dfs_Info300;
+
+       typedef union {
+               [case(0)]       dfs_Info0 *info0;
+               [case(1)]   dfs_Info1 *info1;
+               [case(2)]   dfs_Info2 *info2;
+               [case(3)]   dfs_Info3 *info3;
+               [case(4)]   dfs_Info4 *info4;
+               [case(100)] dfs_Info100 *info100;
+               [case(101)] dfs_Info101 *info101;
+               [case(102)] dfs_Info102 *info102;
+       } dfs_Info;
+
+       WERROR dfs_GetInfo (
+               [in]     unistr *path,
+               [in,unique]     unistr *server,
+               [in,unique]     unistr *share,
+               [in]     uint32 level,
+               [out,switch_is(level)] dfs_Info *info
+               );
+
+       /******************/
+       /* Function: 0x05 */
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info1 *s;
+       } dfs_EnumArray1;
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info2 *s;
+       } dfs_EnumArray2;
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info3 *s;
+       } dfs_EnumArray3;
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info4 *s;
+       } dfs_EnumArray4;
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info200 *s;
+       } dfs_EnumArray200;
+
+       typedef struct {
+               uint32 count;
+               [size_is(count)] dfs_Info300 *s;
+       } dfs_EnumArray300;
+
+
+       typedef union {
+               [case(1)] dfs_EnumArray1 *info1;
+               [case(2)] dfs_EnumArray2 *info2;
+               [case(3)] dfs_EnumArray3 *info3;
+               [case(4)] dfs_EnumArray4 *info4;
+               [case(200)] dfs_EnumArray200 *info200;
+               [case(300)] dfs_EnumArray300 *info300;
+       } dfs_EnumInfo;
+
+       typedef struct {
+               uint32 level;
+               [switch_is(level)] dfs_EnumInfo e;
+       } dfs_EnumStruct;
+
+       WERROR dfs_Enum (
+               [in] uint32 level,
+               [in] uint32 bufsize,
+               [in,out,unique] dfs_EnumStruct *info,
+               [in,unique]     uint32 *unknown,
+               [in,out,unique] uint32 *total
+               );
+
+       /* Function 0x06 */
+       WERROR dfs_Rename();
+
+       /* Function 0x07 */
+       WERROR dfs_Move();
+
+       /* Function 0x08 */
+       WERROR dfs_ManagerGetConfigInfo();
+
+       /* Function 0x09 */
+       WERROR dfs_ManagerSendSiteInfo();
+
+       /* Function 0x0a */
+       WERROR dfs_AddFtRoot();
+
+       /* Function 0x0b */
+       WERROR dfs_RemoveFtRoot();
+
+       /* Function 0x0c */
+       WERROR dfs_AddStdRoot();
+
+       /* Function 0x0d */
+       WERROR dfs_RemoveStdRoot();
+
+       /* Function 0x0e */
+       WERROR dfs_ManagerInitialize();
+
+       /* Function 0x0f */
+       WERROR dfs_AddStdRootForced();
+
+       /* Function 0x10 */
+       WERROR dfs_GetDcAddress();
+
+       /* Function 0x11 */
+       WERROR dfs_SetDcAddress();
+
+       /* Function 0x12 */
+       WERROR dfs_FlushFtTable();
+
+       /* Function 0x13 */
+       WERROR dfs_Add2();
+
+       /* Function 0x14 */
+       WERROR dfs_Remove2();
+
+       /* Function 0x15 */
+       WERROR dfs_EnumEx();
+
+       /* Function 0x16 */
+       WERROR dfs_SetInfo2();
+}
index 34a6dc4a42a2a44afca223570692189bea5b7112..a8830a23799130558f55ed3e2331f3941a073b36 100644 (file)
@@ -186,7 +186,6 @@ struct winbindd_request {
        pid_t pid;               /* pid of calling process */
        uint32_t flags;            /* flags relavant to a given request */
        winbind_string domain_name;     /* name of domain for which the request applies */
-       int msgid;
 
        union {
                winbind_string winsreq;     /* WINS request */
@@ -247,6 +246,8 @@ struct winbindd_request {
                        winbind_string cache_key;
                } dual_sidaliases;
        } data;
+       char *extra_data;
+       size_t extra_len;
        char null_term;
 };
 
index 10b8dc71d8c584cf380825e2bc3a9a08bde64a56..3ec19fa158baf17e99152b46f94db21485960deb 100644 (file)
@@ -40,7 +40,7 @@ NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *
 
        status = dcerpc_ndr_request_recv(req);
 
-        if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
+    if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
                NDR_PRINT_OUT_DEBUG($name, r);          
        }
 ";
index 3f08cbb52739dd582c2a933d5722bdfad69416bb..da60a02059a85116408124e305394236c597b3a1 100644 (file)
@@ -575,8 +575,7 @@ sub ParseElementPushLevel
 
        my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
-       if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING} 
-               or is_charset_array($e, $l))) {
+       if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
                $var_name = get_pointer_to($var_name);
        }
 
@@ -721,8 +720,7 @@ sub ParseElementPrint($$$)
                } elsif ($l->{TYPE} eq "ARRAY") {
                        my $length;
 
-                       if ($l->{IS_CONFORMANT} or $l->{IS_VARYING} or 
-                               is_charset_array($e,$l)) { 
+                       if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
                                $var_name = get_pointer_to($var_name); 
                        }
                        
@@ -927,8 +925,7 @@ sub ParseElementPullLevel
 
        my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
-       if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT} 
-               or is_charset_array($e,$l))) {
+       if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
                $var_name = get_pointer_to($var_name);
        }
 
index ee1ab093248c2d3e40f99de05674232acdd0de92..ceeb81c3d7894bae6aba4351b522ae229578492c 100644 (file)
@@ -84,11 +84,12 @@ sub ParseFunction($$)
        pidl "/* Return variables */";
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless (grep(/out/, @{$e->{DIRECTION}}));
-               
+
                if ($e->{LEVELS}[0]->{TYPE} ne "POINTER") {
                        warning($e->{ORIGINAL}, "First element not a pointer for [out] argument");
                        next;
                }
+
                CopyLevel($e, $e->{LEVELS}[1], $e->{NAME}, "r.$e->{NAME}");
        }
 
index 25102e511af370c74e3e29695e2e7efa2837ba74..d14bac2df7451522986310eb7f3af3582a91d892 100644 (file)
@@ -103,9 +103,13 @@ sub ParseUnion($$$)
 {
        my ($if,$u,$n) = @_;
 
-       my $extra = {};
-       
-       $extra->{switch_value} = $u->{SWITCH_TYPE};
+       my $extra = {
+               switch_value => $u->{SWITCH_TYPE}
+       };
+
+       if (not defined($extra->{switch_value})) {
+               $extra->{switch_value} = "uint32";
+       }
 
        foreach my $e (@{$u->{ELEMENTS}}) {
                foreach my $l (@{$e->{LEVELS}}) {
index c6cc1883912dee1b3bcbf9f01f08d7c8ffe95b20..b87951adee091c16803390991d5de0d56b250bce 100644 (file)
@@ -71,25 +71,7 @@ sub ParseElementLevelData($$$$$$$)
 {
        my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
 
-       my @args = ($e,$l,$varname,$what,$align);
-
-       # See if we need to add a level argument because we're parsing a union
-       foreach (@{$e->{LEVELS}}) {
-               next unless ($_->{TYPE} eq "SWITCH");
-               my $t = getType($l->{DATA_TYPE});
-
-               # Set 0 here because one of the variables referenced in SWITCH_IS 
-               # might be an in variable while this one is [out]
-               if (grep(/in/, @{$e->{DIRECTION}}) or 
-                       not defined($t) or 
-                       has_property($t->{DATA}, "nodiscriminant")) {
-                       push (@args, ParseExpr($_->{SWITCH_IS}, $env));
-               } else {
-                       push (@args, -1);
-               }       
-       }
-
-       my $c = DissectType(@args);
+       my $c = DissectType($e,$l,$varname,$what,$align);
        return if not $c;
 
        if (defined($e->{ALIGN})) {
@@ -261,6 +243,7 @@ sub InitLevel($$$$)
                pidl InitType($e, $l, ParseExpr($e->{NAME}, $env), $varname);
        } elsif ($l->{TYPE} eq "SWITCH") {
                InitLevel($e, GetNextLevel($e,$l), $varname, $env);
+               pidl ParseExpr($e->{NAME}, $env) . ".switch_value = " . ParseExpr($l->{SWITCH_IS}, $env) . ";";
        }
 }
 
@@ -397,20 +380,15 @@ sub ParseUnion($$$)
        my $pfn = "$fn\_p";
        my $dfn = "$fn\_d";
        
-       pidl "BOOL $pfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
+       pidl "BOOL $pfn(const char *desc, $sn* v, prs_struct *ps, int depth)";
        pidl "{";
        indent;
        DeclareArrayVariables($u->{ELEMENTS});
 
        if (defined ($u->{SWITCH_TYPE})) {
-               pidl "if (MARSHALLING(ps)) ";
-               pidl "\tv->switch_value = level;";
-               pidl "";
                pidl "if (!prs_$u->{SWITCH_TYPE}(\"switch_value\", ps, depth, &v->switch_value))";
                pidl "\treturn False;";
                pidl "";
-       } else {
-               pidl "v->switch_value = level;";
        }
 
        # Maybe check here that level and v->switch_value are equal?
@@ -447,7 +425,7 @@ sub ParseUnion($$$)
        pidl "}";
        pidl "";
 
-       pidl "BOOL $dfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
+       pidl "BOOL $dfn(const char *desc, $sn* v, prs_struct *ps, int depth)";
        pidl "{";
        indent;
        DeclareArrayVariables($u->{ELEMENTS});
@@ -483,16 +461,14 @@ sub ParseUnion($$$)
 
 }
 
-sub CreateFnDirection($$$$)
+sub CreateFnDirection($$$$$)
 {
-       my ($fn,$ifn, $s,$es) = @_;
+       my ($fn,$ifn,$s,$all,$es) = @_;
 
        my $args = "";
-       foreach (@$es) {
-               $args .= ", " . DeclLong($_);
-       }
+       foreach (@$all) { $args .= ", " . DeclLong($_); }
 
-       my $env = { "this" => "v" };
+       my $env = { };
        GenerateEnvElement($_, $env) foreach (@$es);
 
        pidl "BOOL $ifn($s *v$args)";
@@ -539,6 +515,7 @@ sub ParseFunction($$)
 
        my @in = ();
        my @out = ();
+       my @all = @{$fn->{ELEMENTS}};
 
        foreach (@{$fn->{ELEMENTS}}) {
                push (@in, $_) if (grep(/in/, @{$_->{DIRECTION}}));
@@ -546,7 +523,7 @@ sub ParseFunction($$)
        }
 
        if (defined($fn->{RETURN_TYPE})) {
-               push (@out, { 
+               my $status = { 
                        NAME => "status", 
                        TYPE => $fn->{RETURN_TYPE},
                        LEVELS => [
@@ -555,17 +532,20 @@ sub ParseFunction($$)
                                        DATA_TYPE => $fn->{RETURN_TYPE}
                                }
                        ]
-               } );
+               };
+
+               push (@out, $status);
+               push (@all, $status);
        }
 
        CreateFnDirection("$if->{NAME}_io_q_$fn->{NAME}", 
                                 "init_$if->{NAME}_q_$fn->{NAME}", 
                                 uc("$if->{NAME}_q_$fn->{NAME}"), 
-                                \@in);
+                                \@in, \@in);
        CreateFnDirection("$if->{NAME}_io_r_$fn->{NAME}", 
                                 "init_$if->{NAME}_r_$fn->{NAME}",
                                 uc("$if->{NAME}_r_$fn->{NAME}"), 
-                                \@out);
+                                \@all, \@out);
 }
 
 sub ParseInterface($)
index 8cb09343acaad8eb1d10f111815d3101e1c2af9c..135b02f1e372ba46c041971b4fea565708327bd8 100644 (file)
@@ -205,12 +205,6 @@ sub AddType($$)
        $known_types->{$t} = $d;
 }
 
-sub GetType($)
-{
-       my $e = shift;
-
-}
-
 # Return type without special stuff, as used in 
 # declarations for internal structs
 sub DeclShort($)
@@ -305,14 +299,9 @@ sub InitType($$$$)
        }
 }
 
-sub DissectType
+sub DissectType($$$$$)
 {
-       my @args = @_;
-       my $e = shift @_;
-       my $l = shift @_;
-       my $varname = shift @_;
-       my $what = shift @_;
-       my $align = shift @_;
+       my ($e,$l,$varname,$what,$align) = @_;
 
        my $t = $known_types->{$l->{DATA_TYPE}};
 
@@ -332,7 +321,7 @@ sub DissectType
 
        # DISSECT can be a function
        if (ref($dissect) eq "CODE") {
-               return $dissect->(@args);
+               return $dissect->($e,$l,$varname,$what,$align);
        } else {
                return $dissect;
        }
@@ -356,31 +345,18 @@ sub LoadTypes($)
                        my $dissect_p;
                        if ($td->{DATA}->{TYPE} eq "UNION") {
                                $decl.="_CTR";
-                                $dissect_p = sub {
-                                       my ($e,$l,$n,$w,$a,$s) = @_;
-
-                                       return "$if->{NAME}_io_$td->{NAME}_p(\"$e->{NAME}\", &$n, $s, ps, depth)";
-                               };
+                       } 
 
-                                $dissect_d = sub {
-                                       my ($e,$l,$n,$w,$a,$s) = @_;
+                        $dissect_p = sub {
+                               my ($e,$l,$n,$w,$a) = @_;
 
-                                       return "$if->{NAME}_io_$td->{NAME}_d(\"$e->{NAME}\", &$n, $s, ps, depth)";
-                               };
-
-                       } else {
-                                $dissect_p = sub {
-                                       my ($e,$l,$n,$w,$a) = @_;
-
-                                       return "$if->{NAME}_io_$td->{NAME}_p(\"$e->{NAME}\", &$n, ps, depth)";
-                               };
-                               $dissect_d = sub {
-                                       my ($e,$l,$n,$w,$a) = @_;
-
-                                       return "$if->{NAME}_io_$td->{NAME}_d(\"$e->{NAME}\", &$n, ps, depth)";
-                               };
+                               return "$if->{NAME}_io_$td->{NAME}_p(\"$e->{NAME}\", &$n, ps, depth)";
+                       };
+                       $dissect_d = sub {
+                               my ($e,$l,$n,$w,$a) = @_;
 
-                       }
+                               return "$if->{NAME}_io_$td->{NAME}_d(\"$e->{NAME}\", &$n, ps, depth)";
+                       };
 
                        AddType($td->{NAME}, {
                                DECL => $decl,
diff --git a/samba4-winsrepl/source/rpc_server/spoolss/dcesrv_spoolss.c b/samba4-winsrepl/source/rpc_server/spoolss/dcesrv_spoolss.c
new file mode 100644 (file)
index 0000000..6936866
--- /dev/null
@@ -0,0 +1,1450 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   endpoint server for the spoolss pipe
+
+   Copyright (C) Tim Potter 2004
+   Copyright (C) Stefan Metzmacher 2005
+   
+   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"
+#include "rpc_server/dcerpc_server.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "rpc_server/common/common.h"
+#include "ntptr/ntptr.h"
+#include "lib/socket/socket.h"
+#include "smbd/service_stream.h"
+
+#define SPOOLSS_BUFFER_UNION(fn,info,level) \
+       ((info)?ndr_size_##fn(info, level, 0):0)
+
+#define SPOOLSS_BUFFER_UNION_ARRAY(fn,info,level,count) \
+       ((info)?ndr_size_##fn##_info(dce_call, level, count, info):0)
+
+#define SPOOLSS_BUFFER_OK(val_true,val_false) ((r->in.offered >= r->out.needed)?val_true:val_false)
+
+static WERROR spoolss_parse_printer_name(TALLOC_CTX *mem_ctx, const char *name,
+                                        const char **_server_name,
+                                        const char **_object_name,
+                                        enum ntptr_HandleType *_object_type)
+{
+       char *p;
+       char *server = NULL;
+       char *server_unc = NULL;
+       const char *object = name;
+
+       /* no printername is there it's like open server */
+       if (!name) {
+               *_server_name = NULL;
+               *_object_name = NULL;
+               *_object_type = NTPTR_HANDLE_SERVER;
+               return WERR_OK;
+       }
+
+       /* just "\\" is invalid */
+       if (strequal("\\\\", name)) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+       if (strncmp("\\\\", name, 2) == 0) {
+               server_unc = talloc_strdup(mem_ctx, name);
+               W_ERROR_HAVE_NO_MEMORY(server_unc);
+               server = server_unc + 2;
+
+               /* here we know we have "\\" in front not followed
+                * by '\0', now see if we have another "\" in the string
+                */
+               p = strchr_m(server, '\\');
+               if (!p) {
+                       /* there's no other "\", so it's ("\\%s",server)
+                        */
+                       *_server_name = server_unc;
+                       *_object_name = NULL;
+                       *_object_type = NTPTR_HANDLE_SERVER;
+                       return WERR_OK;
+               }
+               /* here we know that we have ("\\%s\",server),
+                * if we have '\0' as next then it's an invalid name
+                * otherwise the printer_name
+                */
+               p[0] = '\0';
+               /* everything that follows is the printer name */
+               p++;
+               object = p;
+
+               /* just "" as server is invalid */
+               if (strequal(server, "")) {
+                       return WERR_INVALID_PRINTER_NAME;
+               }
+       }
+
+       /* just "" is invalid */
+       if (strequal(object, "")) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+#define XCV_PORT ",XcvPort "
+#define XCV_MONITOR ",XcvMonitor "
+       if (strncmp(object, XCV_PORT, strlen(XCV_PORT)) == 0) {
+               object += strlen(XCV_PORT);
+
+               /* just "" is invalid */
+               if (strequal(object, "")) {
+                       return WERR_INVALID_PRINTER_NAME;
+               }
+
+               *_server_name = server_unc;
+               *_object_name = object;
+               *_object_type = NTPTR_HANDLE_PORT;
+               return WERR_OK;
+       } else if (strncmp(object, XCV_MONITOR, strlen(XCV_MONITOR)) == 0) {
+               object += strlen(XCV_MONITOR);
+
+               /* just "" is invalid */
+               if (strequal(object, "")) {
+                       return WERR_INVALID_PRINTER_NAME;
+               }
+
+               *_server_name = server_unc;
+               *_object_name = object;
+               *_object_type = NTPTR_HANDLE_MONITOR;
+               return WERR_OK;
+       }
+
+       *_server_name = server_unc;
+       *_object_name = object;
+       *_object_type = NTPTR_HANDLE_PRINTER;
+       return WERR_OK;
+}
+
+/*
+ * Check server_name is:
+ * -  "" , functions that don't allow "",
+ *         should check that on their own, before calling this function
+ * -  our name (only netbios yet, TODO: need to test dns name!)
+ * -  our ip address of the current use socket
+ * otherwise return WERR_INVALID_PRINTER_NAME
+ */
+static WERROR spoolss_check_server_name(struct dcesrv_call_state *dce_call, 
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *server_name)
+{
+       BOOL ret;
+       char *str;
+
+       /* NULL is ok */
+       if (!server_name) return WERR_OK;
+
+       /* "" is ok */
+       ret = strequal("",server_name);
+       if (ret) return WERR_OK;
+
+       /* just "\\" is invalid */
+       if (strequal("\\\\", server_name)) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+       /* then we need "\\" */
+       if (strncmp("\\\\", server_name, 2) != 0) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+       server_name += 2;
+
+       /* NETBIOS NAME is ok */
+       ret = strequal(lp_netbios_name(), server_name);
+       if (ret) return WERR_OK;
+
+       /* DNS NAME is ok
+        * TODO: we need to check if aliases are also ok
+        */
+       if (lp_realm()) {
+               str = talloc_asprintf(mem_ctx, "%s.%s",
+                                               lp_netbios_name(),
+                                               lp_realm());
+               W_ERROR_HAVE_NO_MEMORY(str);
+
+               ret = strequal(str, server_name);
+               talloc_free(str);
+               if (ret) return WERR_OK;
+       }
+
+       str = socket_get_my_addr(dce_call->conn->srv_conn->socket, mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(str);
+
+       ret = strequal(str, server_name);
+       talloc_free(str);
+       if (ret) return WERR_OK;
+
+       return WERR_INVALID_PRINTER_NAME;
+}
+
+static NTSTATUS dcerpc_spoolss_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
+{
+       NTSTATUS status;
+       struct ntptr_context *ntptr;
+
+       status = ntptr_init_context(dce_call->context, lp_ntptr_providor(), &ntptr);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       dce_call->context->private = ntptr;
+
+       return NT_STATUS_OK;
+}
+
+#define DCESRV_INTERFACE_SPOOLSS_BIND dcerpc_spoolss_bind
+
+/* 
+  spoolss_EnumPrinters 
+*/
+static WERROR spoolss_EnumPrinters(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrinters *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       WERROR status;
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, r->in.server);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = ntptr_EnumPrinters(ntptr, mem_ctx, r);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION_ARRAY(spoolss_EnumPrinters, r->out.info, r->in.level, r->out.count);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       r->out.count    = SPOOLSS_BUFFER_OK(r->out.count, 0);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+static WERROR spoolss_OpenPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_OpenPrinterEx *r);
+/* 
+  spoolss_OpenPrinter 
+*/
+static WERROR spoolss_OpenPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_OpenPrinter *r)
+{
+       WERROR status;
+       struct spoolss_OpenPrinterEx *r2;
+
+       r2 = talloc(mem_ctx, struct spoolss_OpenPrinterEx);
+       W_ERROR_HAVE_NO_MEMORY(r2);
+
+       r2->in.printername      = r->in.printername;
+       r2->in.datatype         = r->in.datatype;
+       r2->in.devmode_ctr      = r->in.devmode_ctr;
+       r2->in.access_mask      = r->in.access_mask;
+       r2->in.level            = 1;
+       r2->in.userlevel.level1 = NULL;
+
+       r2->out.handle          = r->out.handle;
+
+       /* TODO: we should take care about async replies here,
+                if spoolss_OpenPrinterEx() would be async!
+        */
+       status = spoolss_OpenPrinterEx(dce_call, mem_ctx, r2);
+
+       r->out.handle           = r2->out.handle;
+
+       return status;
+}
+
+
+/* 
+  spoolss_SetJob 
+*/
+static WERROR spoolss_SetJob(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SetJob *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetJob 
+*/
+static WERROR spoolss_GetJob(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetJob *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumJobs 
+*/
+static WERROR spoolss_EnumJobs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumJobs *r)
+{
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_AddPrinter 
+*/
+static WERROR spoolss_AddPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinter 
+*/
+static WERROR spoolss_DeletePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_SetPrinter 
+*/
+static WERROR spoolss_SetPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SetPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetPrinter 
+*/
+static WERROR spoolss_GetPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPrinterDriver 
+*/
+static WERROR spoolss_AddPrinterDriver(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrinterDriver *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrinterDrivers 
+*/
+static WERROR spoolss_EnumPrinterDrivers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrinterDrivers *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       WERROR status;
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, r->in.server);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = ntptr_EnumPrinterDrivers(ntptr, mem_ctx, r);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION_ARRAY(spoolss_EnumPrinterDrivers, r->out.info, r->in.level, r->out.count);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       r->out.count    = SPOOLSS_BUFFER_OK(r->out.count, 0);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_GetPrinterDriver 
+*/
+static WERROR spoolss_GetPrinterDriver(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinterDriver *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetPrinterDriverDirectory 
+*/
+static WERROR spoolss_GetPrinterDriverDirectory(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinterDriverDirectory *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       WERROR status;
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, r->in.server);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = ntptr_GetPrinterDriverDirectory(ntptr, mem_ctx, r);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION(spoolss_DriverDirectoryInfo, r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_DeletePrinterDriver 
+*/
+static WERROR spoolss_DeletePrinterDriver(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterDriver *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPrintProcessor 
+*/
+static WERROR spoolss_AddPrintProcessor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrintProcessor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrintProcessors 
+*/
+static WERROR spoolss_EnumPrintProcessors(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrintProcessors *r)
+{
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_GetPrintProcessorDirectory 
+*/
+static WERROR spoolss_GetPrintProcessorDirectory(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrintProcessorDirectory *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_StartDocPrinter 
+*/
+static WERROR spoolss_StartDocPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_StartDocPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_StartPagePrinter 
+*/
+static WERROR spoolss_StartPagePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_StartPagePrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_WritePrinter 
+*/
+static WERROR spoolss_WritePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_WritePrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EndPagePrinter 
+*/
+static WERROR spoolss_EndPagePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EndPagePrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AbortPrinter 
+*/
+static WERROR spoolss_AbortPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AbortPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ReadPrinter 
+*/
+static WERROR spoolss_ReadPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ReadPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EndDocPrinter 
+*/
+static WERROR spoolss_EndDocPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EndDocPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddJob 
+*/
+static WERROR spoolss_AddJob(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddJob *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ScheduleJob 
+*/
+static WERROR spoolss_ScheduleJob(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ScheduleJob *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetPrinterData 
+*/
+static WERROR spoolss_GetPrinterData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinterData *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_GetPrintServerData(handle, mem_ctx, r);
+                       break;
+               default:
+                       status = WERR_FOOBAR;
+                       break;
+       }
+
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = ndr_size_spoolss_PrinterData(&r->out.data, r->out.type, 0);
+       r->out.type     = SPOOLSS_BUFFER_OK(r->out.type, SPOOLSS_PRINTER_DATA_TYPE_NULL);
+       r->out.data     = SPOOLSS_BUFFER_OK(r->out.data, r->out.data);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA);
+}
+
+
+/* 
+  spoolss_SetPrinterData 
+*/
+static WERROR spoolss_SetPrinterData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SetPrinterData *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_WaitForPrinterChange 
+*/
+static WERROR spoolss_WaitForPrinterChange(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_WaitForPrinterChange *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ClosePrinter 
+*/
+static WERROR spoolss_ClosePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ClosePrinter *r)
+{
+       struct dcesrv_handle *h;
+
+       *r->out.handle = *r->in.handle;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+
+       talloc_free(h);
+
+       ZERO_STRUCTP(r->out.handle);
+
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_AddForm 
+*/
+static WERROR spoolss_AddForm(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddForm *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_AddPrintServerForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_AddPrinterForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_DeleteForm 
+*/
+static WERROR spoolss_DeleteForm(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeleteForm *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_DeletePrintServerForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_DeletePrinterForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_GetForm 
+*/
+static WERROR spoolss_GetForm(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetForm *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       /*
+                        * stupid, but w2k3 returns WERR_BADFID here?
+                        */
+                       return WERR_BADFID;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_GetPrinterForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION(spoolss_FormInfo, r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_SetForm 
+*/
+static WERROR spoolss_SetForm(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SetForm *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_SetPrintServerForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_SetPrinterForm(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_EnumForms 
+*/
+static WERROR spoolss_EnumForms(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumForms *r)
+{
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       WERROR status;
+
+       DCESRV_PULL_HANDLE_WERR(h, r->in.handle, DCESRV_HANDLE_ANY);
+       handle = talloc_get_type(h->data, struct ntptr_GenericHandle);
+       if (!handle)
+               return WERR_BADFID;
+
+       switch (handle->type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_EnumPrintServerForms(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_EnumPrinterForms(handle, mem_ctx, r);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION_ARRAY(spoolss_EnumForms, r->out.info, r->in.level, r->out.count);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       r->out.count    = SPOOLSS_BUFFER_OK(r->out.count, 0);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_EnumPorts 
+*/
+static WERROR spoolss_EnumPorts(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPorts *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       WERROR status;
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, r->in.servername);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = ntptr_EnumPorts(ntptr, mem_ctx, r);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION_ARRAY(spoolss_EnumPorts, r->out.info, r->in.level, r->out.count);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       r->out.count    = SPOOLSS_BUFFER_OK(r->out.count, 0);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_EnumMonitors 
+*/
+static WERROR spoolss_EnumMonitors(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumMonitors *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       WERROR status;
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, r->in.servername);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = ntptr_EnumMonitors(ntptr, mem_ctx, r);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       r->out.needed   = SPOOLSS_BUFFER_UNION_ARRAY(spoolss_EnumMonitors, r->out.info, r->in.level, r->out.count);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+       r->out.count    = SPOOLSS_BUFFER_OK(r->out.count, 0);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+
+/* 
+  spoolss_AddPort 
+*/
+static WERROR spoolss_AddPort(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPort *r)
+{
+       return WERR_NOT_SUPPORTED;
+}
+
+
+/* 
+  spoolss_ConfigurePort 
+*/
+static WERROR spoolss_ConfigurePort(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ConfigurePort *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePort 
+*/
+static WERROR spoolss_DeletePort(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePort *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_CreatePrinterIC 
+*/
+static WERROR spoolss_CreatePrinterIC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_CreatePrinterIC *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_PlayGDIScriptOnPrinterIC 
+*/
+static WERROR spoolss_PlayGDIScriptOnPrinterIC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_PlayGDIScriptOnPrinterIC *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterIC 
+*/
+static WERROR spoolss_DeletePrinterIC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterIC *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPrinterConnection 
+*/
+static WERROR spoolss_AddPrinterConnection(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrinterConnection *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterConnection 
+*/
+static WERROR spoolss_DeletePrinterConnection(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterConnection *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_PrinterMessageBox 
+*/
+static WERROR spoolss_PrinterMessageBox(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_PrinterMessageBox *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddMonitor 
+*/
+static WERROR spoolss_AddMonitor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddMonitor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeleteMonitor 
+*/
+static WERROR spoolss_DeleteMonitor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeleteMonitor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrintProcessor 
+*/
+static WERROR spoolss_DeletePrintProcessor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrintProcessor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPrintProvidor 
+*/
+static WERROR spoolss_AddPrintProvidor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrintProvidor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrintProvidor 
+*/
+static WERROR spoolss_DeletePrintProvidor(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrintProvidor *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrintProcDataTypes 
+*/
+static WERROR spoolss_EnumPrintProcDataTypes(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrintProcDataTypes *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ResetPrinter 
+*/
+static WERROR spoolss_ResetPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ResetPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetPrinterDriver2 
+*/
+static WERROR spoolss_GetPrinterDriver2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinterDriver2 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_FindFirstPrinterChangeNotification 
+*/
+static WERROR spoolss_FindFirstPrinterChangeNotification(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_FindFirstPrinterChangeNotification *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_FindNextPrinterChangeNotification 
+*/
+static WERROR spoolss_FindNextPrinterChangeNotification(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_FindNextPrinterChangeNotification *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_FindClosePrinterNotify 
+*/
+static WERROR spoolss_FindClosePrinterNotify(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_FindClosePrinterNotify *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_RouterFindFirstPrinterChangeNotificationOld 
+*/
+static WERROR spoolss_RouterFindFirstPrinterChangeNotificationOld(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RouterFindFirstPrinterChangeNotificationOld *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ReplyOpenPrinter 
+*/
+static WERROR spoolss_ReplyOpenPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ReplyOpenPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_RouterReplyPrinter 
+*/
+static WERROR spoolss_RouterReplyPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RouterReplyPrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ReplyClosePrinter 
+*/
+static WERROR spoolss_ReplyClosePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ReplyClosePrinter *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPortEx 
+*/
+static WERROR spoolss_AddPortEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPortEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_RouterFindFirstPrinterChangeNotification 
+*/
+static WERROR spoolss_RouterFindFirstPrinterChangeNotification(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RouterFindFirstPrinterChangeNotification *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_SpoolerInit 
+*/
+static WERROR spoolss_SpoolerInit(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SpoolerInit *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_ResetPrinterEx 
+*/
+static WERROR spoolss_ResetPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_ResetPrinterEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_RemoteFindFirstPrinterChangeNotifyEx 
+*/
+static WERROR spoolss_RemoteFindFirstPrinterChangeNotifyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r)
+{
+       /*
+        * TODO: for now just return ok,
+        *       to keep the w2k3 PrintServer 
+        *       happy to allow to open the Add Printer GUI
+        */
+       return WERR_OK;
+}
+
+
+/* 
+  spoolss_RouterRefreshPrinterChangeNotification 
+*/
+static WERROR spoolss_RouterRefreshPrinterChangeNotification(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RouterRefreshPrinterChangeNotification *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_RemoteFindNextPrinterChangeNotifyEx 
+*/
+static WERROR spoolss_RemoteFindNextPrinterChangeNotifyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_RemoteFindNextPrinterChangeNotifyEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_44 
+*/
+static WERROR spoolss_44(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_44 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/* 
+  spoolss_OpenPrinterEx 
+*/
+static WERROR spoolss_OpenPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_OpenPrinterEx *r)
+{
+       struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private, struct ntptr_context);
+       struct ntptr_GenericHandle *handle;
+       struct dcesrv_handle *h;
+       const char *server;
+       const char *object;
+       enum ntptr_HandleType type;
+       WERROR status;
+
+       ZERO_STRUCTP(r->out.handle);
+
+       status = spoolss_parse_printer_name(mem_ctx, r->in.printername, &server, &object, &type);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       status = spoolss_check_server_name(dce_call, mem_ctx, server);
+       W_ERROR_NOT_OK_RETURN(status);
+
+       switch (type) {
+               case NTPTR_HANDLE_SERVER:
+                       status = ntptr_OpenPrintServer(ntptr, mem_ctx, r, server, &handle);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PORT:
+                       status = ntptr_OpenPort(ntptr, mem_ctx, r, object, &handle);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_MONITOR:
+                       status = ntptr_OpenMonitor(ntptr, mem_ctx, r, object, &handle);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               case NTPTR_HANDLE_PRINTER:
+                       status = ntptr_OpenPrinter(ntptr, mem_ctx, r, object, &handle);
+                       W_ERROR_NOT_OK_RETURN(status);
+                       break;
+               default:
+                       return WERR_FOOBAR;
+       }
+
+       h = dcesrv_handle_new(dce_call->context, handle->type);
+       W_ERROR_HAVE_NO_MEMORY(h);
+
+       h->data = talloc_steal(h, handle);
+
+       *r->out.handle  = h->wire_handle;
+
+       return WERR_OK;
+}
+
+/* 
+  spoolss_AddPrinterEx 
+*/
+static WERROR spoolss_AddPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrinterEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_47 
+*/
+static WERROR spoolss_47(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_47 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrinterData 
+*/
+static WERROR spoolss_EnumPrinterData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrinterData *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterData 
+*/
+static WERROR spoolss_DeletePrinterData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterData *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_4a 
+*/
+static WERROR spoolss_4a(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_4a *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_4b 
+*/
+static WERROR spoolss_4b(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_4b *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_4c 
+*/
+static WERROR spoolss_4c(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_4c *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_SetPrinterDataEx 
+*/
+static WERROR spoolss_SetPrinterDataEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_SetPrinterDataEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_GetPrinterDataEx 
+*/
+static WERROR spoolss_GetPrinterDataEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_GetPrinterDataEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrinterDataEx 
+*/
+static WERROR spoolss_EnumPrinterDataEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrinterDataEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_EnumPrinterKey 
+*/
+static WERROR spoolss_EnumPrinterKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_EnumPrinterKey *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterDataEx 
+*/
+static WERROR spoolss_DeletePrinterDataEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterDataEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterKey 
+*/
+static WERROR spoolss_DeletePrinterKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterKey *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_53 
+*/
+static WERROR spoolss_53(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_53 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_DeletePrinterDriverEx 
+*/
+static WERROR spoolss_DeletePrinterDriverEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_DeletePrinterDriverEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_55 
+*/
+static WERROR spoolss_55(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_55 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_56 
+*/
+static WERROR spoolss_56(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_56 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_57 
+*/
+static WERROR spoolss_57(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_57 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_58 
+*/
+static WERROR spoolss_58(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_58 *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_AddPrinterDriverEx 
+*/
+static WERROR spoolss_AddPrinterDriverEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_AddPrinterDriverEx *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5a 
+*/
+static WERROR spoolss_5a(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5a *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5b 
+*/
+static WERROR spoolss_5b(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5b *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5c 
+*/
+static WERROR spoolss_5c(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5c *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5d 
+*/
+static WERROR spoolss_5d(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5d *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5e 
+*/
+static WERROR spoolss_5e(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5e *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* 
+  spoolss_5f 
+*/
+static WERROR spoolss_5f(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct spoolss_5f *r)
+{
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_spoolss_s.c"
diff --git a/samba4-winsrepl/source/setup/provision.ldif b/samba4-winsrepl/source/setup/provision.ldif
new file mode 100644 (file)
index 0000000..8c336b8
--- /dev/null
@@ -0,0 +1,355 @@
+###############################
+# Domain Naming Context
+###############################
+dn: ${BASEDN}
+objectClass: top
+objectClass: domain
+objectClass: domainDNS
+dnsDomain: ${DNSDOMAIN}
+dc: ${RDN_DC}
+objectGUID: ${DOMAINGUID}
+creationTime: ${NTTIME}
+forceLogoff: 0x8000000000000000
+lockoutDuration: -18000000000
+lockOutObservationWindow: -18000000000
+lockoutThreshold: 0
+uSNCreated: 1
+uSNChanged: 1
+maxPwdAge: -37108517437440
+minPwdAge: 0
+minPwdLength: 7
+modifiedCountAtLastProm: 0
+nextRid: 1001
+pwdProperties: 1
+pwdHistoryLength: 24
+objectSid: ${DOMAINSID}
+oEMInformation: Provisioned by Samba4: ${LDAPTIME}
+serverState: 1
+nTMixedDomain: 1
+msDS-Behavior-Version: 0
+ridManagerReference: CN=RID Manager$,CN=System,${BASEDN}
+uASCompat: 1
+modifiedCount: 1
+objectCategory: CN=Domain-DNS,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+subRefs: CN=Configuration,${BASEDN}
+subRefs: CN=Schema,CN=Configuration,${BASEDN}
+canonicalName: ${REALM}/
+
+dn: CN=Users,${BASEDN}
+objectClass: top
+objectClass: container
+cn: Users
+description: Default container for upgraded user accounts
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+dn: CN=Computers,${BASEDN}
+objectClass: top
+objectClass: container
+cn: Computers
+description: Default container for upgraded computer accounts
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+dn: OU=Domain Controllers,${BASEDN}
+objectClass: top
+objectClass: organizationalUnit
+ou: Domain Controllers
+description: Default container for domain controllers
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+systemFlags: 0x8c000000
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+dn: CN=ForeignSecurityPrincipals,${BASEDN}
+objectClass: top
+objectClass: container
+cn: ForeignSecurityPrincipals
+description: Default container for security identifiers (SIDs) associated with objects from external, trusted domains
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+dn: CN=System,${BASEDN}
+objectClass: top
+objectClass: container
+cn: System
+description: Builtin system settings
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+dn: CN=RID Manager$,CN=System,${BASEDN}
+objectclass: top
+objectclass: rIDManager
+cn: RID Manager$
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x8c000000
+objectCategory: CN=RID-Manager,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+fSMORoleOwner: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+rIDAvailablePool: 4611686014132423217
+
+dn: CN=DomainUpdates,CN=System,${BASEDN}
+objectClass: top
+objectClass: container
+cn: DomainUpdates
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=Windows2003Update,CN=DomainUpdates,CN=System,${BASEDN}
+objectClass: top
+objectClass: container
+cn: Windows2003Update
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+revision: 8
+
+dn: CN=Infrastructure,${BASEDN}
+objectclass: top
+objectclass: infrastructureUpdate
+cn: Infrastructure
+instanceType: 4
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x8c000000
+objectCategory: CN=Infrastructure-Update,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+fSMORoleOwner: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+
+dn: CN=Builtin,${BASEDN}
+objectClass: top
+objectClass: builtinDomain
+cn: Builtin
+instanceType: 4
+showInAdvancedViewOnly: FALSE
+forceLogoff: 0x8000000000000000
+lockoutDuration: -18000000000
+lockOutObservationWindow: -18000000000
+lockoutThreshold: 0
+maxPwdAge: -37108517437440
+minPwdAge: 0
+minPwdLength: 0
+modifiedCountAtLastProm: 0
+nextRid: 1000
+pwdProperties: 0
+pwdHistoryLength: 0
+objectSid: S-1-5-32
+serverState: 1
+uASCompat: 1
+modifiedCount: 1
+objectCategory: CN=Builtin-Domain,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
+###############################
+# Configuration Naming Context
+###############################
+dn: CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: configuration
+cn: Configuration
+instanceType: 13
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=Configuration,CN=Schema,CN=Configuration,${BASEDN}
+subRefs: CN=Schema,CN=Configuration,${BASEDN}
+masteredBy: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+msDs-masteredBy: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+
+dn: CN=Partitions,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: crossRefContainer
+cn: Partitions
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x80000000
+objectCategory: CN=Cross-Ref-Container,CN=Schema,CN=Configuration,${BASEDN}
+msDS-Behavior-Version: 0
+fSMORoleOwner: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+
+dn: CN=Enterprise Configuration,CN=Partitions,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: crossRef
+cn: Enterprise Configuration
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x00000001
+objectCategory: CN=Cross-Ref,CN=Schema,CN=Configuration,${BASEDN}
+nCName: CN=Configuration,${BASEDN}
+dnsRoot: ${DNSDOMAIN}
+
+dn: CN=Enterprise Schema,CN=Partitions,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: crossRef
+cn: Enterprise Schema
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x00000001
+objectCategory: CN=Cross-Ref,CN=Schema,CN=Configuration,${BASEDN}
+nCName: CN=Schema,CN=Configuration,${BASEDN}
+dnsRoot: ${DNSDOMAIN}
+
+dn: CN=${DOMAIN},CN=Partitions,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: crossRef
+cn: ${DOMAIN}
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x00000003
+objectCategory: CN=Cross-Ref,CN=Schema,CN=Configuration,${BASEDN}
+nCName: ${BASEDN}
+nETBIOSName: ${DOMAIN}
+dnsRoot: ${DNSDOMAIN}
+
+dn: CN=Sites,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: sitesContainer
+cn: Sites
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x82000000
+objectCategory: CN=Sites-Container,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: site
+cn: ${DEFAULTSITE}
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x82000000
+objectCategory: CN=Site,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: serversContainer
+cn: Servers
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x82000000
+objectCategory: CN=Servers-Container,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: server
+cn: ${NETBIOSNAME}
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x52000000
+objectCategory: CN=Server,CN=Schema,CN=Configuration,${BASEDN}
+dNSHostName: ${DNSNAME}
+serverReference: CN=${NETBIOSNAME},OU=Domain Controllers,${BASEDN}
+
+dn: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: applicationSettings
+objectClass: nTDSDSA
+cn: NTDS Settings
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x02000000
+objectCategory: CN=NTDS-DSA,CN=Schema,CN=Configuration,${BASEDN}
+dMDLocation: CN=Schema,CN=Configuration,${BASEDN}
+objectGUID: ${INVOCATIONID}
+invocationId: ${INVOCATIONID}
+msDS-Behavior-Version: 2
+
+dn: CN=Services,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: container
+cn: Services
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+systemFlags: 0x80000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=Windows NT,CN=Services,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: container
+cn: Windows NT
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+
+dn: CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: nTDSService
+cn: Directory Service
+instanceType: 4
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=NTDS-Service,CN=Schema,CN=Configuration,${BASEDN}
+sPNMappings: host=ldap,dns,cifs,http
+
+
+###############################
+# Schema Naming Context
+###############################
+dn: CN=Schema,CN=Configuration,${BASEDN}
+objectClass: top
+objectClass: dMD
+cn: Schema
+instanceType: 13
+uSNCreated: ${USN}
+uSNChanged: ${USN}
+showInAdvancedViewOnly: TRUE
+objectCategory: CN=DMD,CN=Schema,CN=Configuration,${BASEDN}
+masteredBy: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+msDs-masteredBy: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+fSMORoleOwner: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=${DEFAULTSITE},CN=Sites,CN=Configuration,${BASEDN}
+objectVersion: 30
diff --git a/samba4-winsrepl/source/setup/secrets.ldif b/samba4-winsrepl/source/setup/secrets.ldif
new file mode 100644 (file)
index 0000000..9ba0952
--- /dev/null
@@ -0,0 +1,37 @@
+dn: @INDEXLIST
+@IDXATTR: cn
+@IDXATTR: flatname
+@IDXATTR: realm
+
+dn: @ATTRIBUTES
+realm: CASE_INSENSITIVE
+flatname: CASE_INSENSITIVE
+sAMAccountName: CASE_INSENSITIVE
+
+#Add modules to the list to activate them by default
+#beware often order is important
+dn: @MODULES
+@LIST: timestamps
+
+dn: CN=LSA Secrets
+objectClass: top
+objectClass: container
+cn: LSA Secrets
+
+dn: CN=Primary Domains
+objectClass: top
+objectClass: container
+cn: Primary Domains
+
+dn: flatname=${DOMAIN},CN=Primary Domains
+objectClass: top
+objectClass: primaryDomain
+flatname: ${DOMAIN}
+realm: ${REALM}
+secret: ${MACHINEPASS}
+secureChannelType: 6
+sAMAccountName: ${NETBIOSNAME}$
+whenCreated: ${LDAPTIME}
+whenChanged: ${LDAPTIME}
+msDS-KeyVersionNumber: 1
+objectSid: ${DOMAINSID}
index e5e205a061fab4ac28f620315f32d8eef6dff97d..a77b3eaf7b6748caa8c8e627e72fc964104adb97 100644 (file)
@@ -151,9 +151,13 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
 
                validation_level = r->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r->out.validation.sam2->base;
@@ -172,9 +176,13 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
 
                validation_level = r_ex->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_ex->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r_ex->out.validation.sam2->base;
@@ -201,9 +209,13 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
-
+               
                validation_level = r_flags->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_flags->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r_flags->out.validation.sam2->base;
@@ -218,68 +230,18 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                break;
        }
                
-
-       if (!NT_STATUS_IS_OK(status)) {
-               /* we cannot check the session key, if the logon failed... */
-               return status;
-       }
-
        if (!base) {
                printf("No user info returned from 'successful' SamLogon*() call!\n");
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       /* find and decyrpt the session keys, return in parameters above */
-       if (validation_level == 6) {
-               /* they aren't encrypted! */
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
-       } else if (samlogon_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
-               static const char zeros[16];
-                       
-               if (memcmp(base->key.key, zeros,  
-                          sizeof(base->key.key)) != 0) {
-                       creds_arcfour_crypt(samlogon_state->creds, 
-                                           base->key.key, 
-                                           sizeof(base->key.key));
-               }
-                       
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-                       
-               if (memcmp(base->LMSessKey.key, zeros,  
-                          sizeof(base->LMSessKey.key)) != 0) {
-                       creds_arcfour_crypt(samlogon_state->creds, 
-                                           base->LMSessKey.key, 
-                                           sizeof(base->LMSessKey.key));
-               }
-                       
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
-       } else {
-               static const char zeros[16];
-                       
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-
-               if (memcmp(base->LMSessKey.key, zeros,  
-                          sizeof(base->LMSessKey.key)) != 0) {
-                       creds_des_decrypt_LMKey(samlogon_state->creds, 
-                                               &base->LMSessKey);
-               }
-                       
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
+       if (user_session_key) {
+               memcpy(user_session_key, base->key.key, 16);
        }
-       
+       if (lm_key) {
+               memcpy(lm_key, base->LMSessKey.key, 8);
+       }
+                       
        return status;
 } 
 
index 3b56eea552c623d17ecf0da886881f60b198b516..991cce198aa28808c585814f5ae4f55b27a936b1 100644 (file)
@@ -9,6 +9,7 @@ INIT_OBJ_FILES = \
                winbind/wb_server.o \
                winbind/wb_samba3_protocol.o \
                winbind/wb_samba3_cmd.o \
+               winbind/wb_init_domain.o \
                winbind/wb_async_helpers.o
 REQUIRED_SUBSYSTEMS = RPC_NDR_LSA
 # End MODULE server_service_winbind
index d77e4d12adb6df8abd3788529cc4c2ce97e90058..001b14730709f2d3e3fdc2c3828d7b20061245eb 100644 (file)
 #include "librpc/gen_ndr/ndr_lsa.h"
 #include "libcli/auth/credentials.h"
 
-static BOOL comp_is_ok(struct composite_context *ctx)
-{
-       if (NT_STATUS_IS_OK(ctx->status)) {
-               return True;
-       }
-       ctx->state = COMPOSITE_STATE_ERROR;
-       if (ctx->async.fn != NULL) {
-               ctx->async.fn(ctx);
-       }
-       return False;
-}
+struct finddcs_state {
+       struct composite_context *ctx;
+       struct messaging_context *msg_ctx;
 
-static void comp_error(struct composite_context *ctx, NTSTATUS status)
-{
-       ctx->status = status;
-       SMB_ASSERT(!comp_is_ok(ctx));
-}
+       const char *domain_name;
+       const struct dom_sid *domain_sid;
 
-static BOOL comp_nomem(const void *p, struct composite_context *ctx)
-{
-       if (p != NULL) {
-               return False;
-       }
-       comp_error(ctx, NT_STATUS_NO_MEMORY);
-       return True;
-}
+       struct nbtd_getdcname r;
 
-static void comp_done(struct composite_context *ctx)
-{
-       ctx->state = COMPOSITE_STATE_DONE;
-       if (ctx->async.fn != NULL) {
-               ctx->async.fn(ctx);
-       }
-}
+       int num_dcs;
+       struct nbt_dc_name *dcs;
+};
 
-static void comp_cont(struct composite_context *ctx,
-                     struct composite_context *new_ctx,
-                     void (*continuation)(struct composite_context *),
-                     void *private_data)
-{
-       if (comp_nomem(new_ctx, ctx)) return;
-       new_ctx->async.fn = continuation;
-       new_ctx->async.private_data = private_data;
-}
+static void finddcs_resolve(struct composite_context *ctx);
+static void finddcs_getdc(struct irpc_request *ireq);
 
-static void rpc_cont(struct composite_context *ctx,
-                    struct rpc_request *new_req,
-                    void (*continuation)(struct rpc_request *),
-                    void *private_data)
+struct composite_context *wb_finddcs_send(const char *domain_name,
+                                         const struct dom_sid *domain_sid,
+                                         struct event_context *event_ctx,
+                                         struct messaging_context *msg_ctx)
 {
-       if (comp_nomem(new_req, ctx)) return;
-       new_req->async.callback = continuation;
-       new_req->async.private = private_data;
-}
+       struct composite_context *result, *ctx;
+       struct finddcs_state *state;
+       struct nbt_name name;
 
-struct finddcs_state {
-       struct wb_finddcs *io;
-       struct composite_context *creq;
+       result = talloc_zero(NULL, struct composite_context);
+       if (result == NULL) goto failed;
+       result->state = COMPOSITE_STATE_IN_PROGRESS;
+       result->event_ctx = event_ctx;
 
-       struct nbtd_getdcname *r;
-       struct irpc_request *ireq;
-};
+       state = talloc(result, struct finddcs_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
 
-static void finddcs_getdc(struct irpc_request *ireq)
-{
-       struct composite_context *c = talloc_get_type(ireq->async.private,
-                                                     struct composite_context);
-       struct finddcs_state *state = talloc_get_type(c->private_data,
-                                                     struct finddcs_state);
+       state->domain_name = talloc_strdup(state, domain_name);
+       if (state->domain_name == NULL) goto failed;
+       state->domain_sid = dom_sid_dup(state, domain_sid);
+       if (state->domain_sid == NULL) goto failed;
+       state->msg_ctx = msg_ctx;
 
-       c->status = irpc_call_recv(ireq);
-       if (!comp_is_ok(c)) return;
+       make_nbt_name(&name, state->domain_name, 0x1c);
+       ctx = resolve_name_send(&name, result->event_ctx,
+                               lp_name_resolve_order());
 
-       state->io->out.dcs[0].name = talloc_steal(state->io->out.dcs,
-                                                 state->r->out.dcname);
-       comp_done(c);
+       if (ctx == NULL) goto failed;
+       ctx->async.fn = finddcs_resolve;
+       ctx->async.private_data = state;
+
+       return result;
+
+failed:
+       talloc_free(result);
+       return NULL;
 }
 
-/*
-  called when name resolution is finished
-*/
-static void finddcs_resolve(struct composite_context *res_ctx)
+static void finddcs_resolve(struct composite_context *ctx)
 {
-       struct composite_context *c = talloc_get_type(res_ctx->async.private_data,
-                                                     struct composite_context);
-       struct finddcs_state *state = talloc_get_type(c->private_data,
-                                                     struct finddcs_state);
+       struct finddcs_state *state =
+               talloc_get_type(ctx->async.private_data, struct finddcs_state);
+       struct irpc_request *ireq;
        uint32_t *nbt_servers;
+       const char *address;
 
-       state->io->out.num_dcs = 1;
-       state->io->out.dcs = talloc_array(state, struct nbt_dc_name,
-                                         state->io->out.num_dcs);
-       if (comp_nomem(state->io->out.dcs, c)) return;
+       state->ctx->status = resolve_name_recv(ctx, state, &address);
+       if (!comp_is_ok(state->ctx)) return;
 
-       c->status = resolve_name_recv(res_ctx, state->io->out.dcs,
-                                     &state->io->out.dcs[0].address);
-       if (!comp_is_ok(c)) return;
+       state->num_dcs = 1;
+       state->dcs = talloc_array(state, struct nbt_dc_name, state->num_dcs);
+       if (comp_nomem(state->dcs, state->ctx)) return;
 
-       nbt_servers = irpc_servers_byname(state->io->in.msg_ctx, "nbt_server");
-       if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
-               comp_error(c, NT_STATUS_NO_LOGON_SERVERS);
-               return;
-       }
+       state->dcs[0].address = talloc_steal(state->dcs, address);
 
-       state->r = talloc(state, struct nbtd_getdcname);
-       if (comp_nomem(state->r, c)) return;
-
-       state->r->in.domainname = talloc_strdup(state->r, lp_workgroup());
-       if (comp_nomem(state->r->in.domainname, c)) return;
-       state->r->in.ip_address = state->io->out.dcs[0].address;
-       state->r->in.my_computername = lp_netbios_name();
-       state->r->in.my_accountname =
-               talloc_asprintf(state->r, "%s$", lp_netbios_name());
-       if (comp_nomem(state->r->in.my_accountname, c)) return;
-       state->r->in.account_control = ACB_WSTRUST;
-       state->r->in.domain_sid =
-               secrets_get_domain_sid(state->r, lp_workgroup());
-
-       if (state->r->in.domain_sid == NULL) {
-               comp_error(c, NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+       nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
+       if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+               comp_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS);
                return;
        }
 
-       state->ireq = irpc_call_send(state->io->in.msg_ctx, nbt_servers[0],
-                                    &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME,
-                                    state->r, state);
-       if (comp_nomem(state->ireq, c)) return;
+       state->r.in.domainname = state->domain_name;
+       state->r.in.ip_address = state->dcs[0].address;
+       state->r.in.my_computername = lp_netbios_name();
+       state->r.in.my_accountname = talloc_asprintf(state, "%s$",
+                                                    lp_netbios_name());
+       if (comp_nomem(state->r.in.my_accountname, state->ctx)) return;
+       state->r.in.account_control = ACB_WSTRUST;
+       state->r.in.domain_sid = dom_sid_dup(state, state->domain_sid);
+       if (comp_nomem(state->r.in.domain_sid, state->ctx)) return;
 
-       c->status = NT_STATUS_OK;
-       state->ireq->async.fn = finddcs_getdc;
-       state->ireq->async.private = c;
+       ireq = irpc_call_send(state->msg_ctx, nbt_servers[0],
+                             &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME,
+                             &state->r, state);
+       irpc_cont(state->ctx, ireq, finddcs_getdc, state);
 }
 
-struct composite_context *wb_finddcs_send(struct wb_finddcs *io,
-                                         struct event_context *event_ctx)
+static void finddcs_getdc(struct irpc_request *ireq)
 {
-       struct composite_context *c;
-       struct finddcs_state *state;
-       struct nbt_name name;
-
-       c = talloc_zero(NULL, struct composite_context);
-       if (c == NULL) goto failed;
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
-       c->event_ctx = event_ctx;
-
-       state = talloc(c, struct finddcs_state);
-       if (state == NULL) goto failed;
-       state->io = io;
+       struct finddcs_state *state =
+               talloc_get_type(ireq->async.private, struct finddcs_state);
 
-       make_nbt_name(&name, io->in.domain, 0x1c);
-       state->creq = resolve_name_send(&name, c->event_ctx,
-                                       lp_name_resolve_order());
-
-       if (state->creq == NULL) goto failed;
-       state->creq->async.private_data = c;
-       state->creq->async.fn = finddcs_resolve;
-       c->private_data = state;
+       state->ctx->status = irpc_call_recv(ireq);
+       if (!comp_is_ok(state->ctx)) return;
 
-       return c;
-failed:
-       talloc_free(c);
-       return NULL;
+       state->dcs[0].name = talloc_steal(state->dcs, state->r.out.dcname);
+       comp_done(state->ctx);
 }
 
-NTSTATUS wb_finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
+NTSTATUS wb_finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                        int *num_dcs, struct nbt_dc_name **dcs)
 {
-       NTSTATUS status;
-
-       status = composite_wait(c);
-
+       NTSTATUS status =composite_wait(c);
        if (NT_STATUS_IS_OK(status)) {
-               struct finddcs_state *state = talloc_get_type(c->private_data,
-                                                             struct finddcs_state);
-               talloc_steal(mem_ctx, state->io->out.dcs);
+               struct finddcs_state *state =
+                       talloc_get_type(c->private_data, struct finddcs_state);
+               *num_dcs = state->num_dcs;
+               *dcs = talloc_steal(mem_ctx, state->dcs);
        }
-
        talloc_free(c);
        return status;
 }
 
-NTSTATUS wb_finddcs(struct wb_finddcs *io, TALLOC_CTX *mem_ctx,
-                   struct event_context *ev)
+NTSTATUS wb_finddcs(const char *domain_name, const struct dom_sid *domain_sid,
+                   struct event_context *event_ctx,
+                   struct messaging_context *msg_ctx,
+                   TALLOC_CTX *mem_ctx,
+                   int *num_dcs, struct nbt_dc_name **dcs)
 {
-       struct composite_context *c = wb_finddcs_send(io, ev);
-       return wb_finddcs_recv(c, mem_ctx);
+       struct composite_context *c = wb_finddcs_send(domain_name, domain_sid,
+                                                     event_ctx, msg_ctx);
+       return wb_finddcs_recv(c, mem_ctx, num_dcs, dcs);
 }
 
 struct get_schannel_creds_state {
@@ -290,7 +235,6 @@ static void get_schannel_creds_recv_pipe(struct composite_context *ctx)
                                                   DCERPC_NETLOGON_VERSION);
        if (!comp_is_ok(state->ctx)) return;
 
-       ZERO_STRUCT(state->r);
        state->r.in.computer_name =
                cli_credentials_get_workstation(state->wks_creds);
        state->r.in.server_name =
@@ -335,7 +279,6 @@ static void get_schannel_creds_recv_chal(struct rpc_request *req)
                          state->r.out.credentials, mach_pwd,
                          &state->netr_cred, state->negotiate_flags);
 
-       ZERO_STRUCT(state->a);
        state->a.in.server_name =
                talloc_reference(state, state->r.in.server_name);
        state->a.in.account_name =
@@ -411,226 +354,6 @@ NTSTATUS wb_get_schannel_creds(struct cli_credentials *wks_creds,
        return wb_get_schannel_creds_recv(c, mem_ctx, netlogon_pipe);
 }
 
-struct get_lsa_pipe_state {
-       struct composite_context *ctx;
-       const char *domain;
-
-       struct wb_finddcs *finddcs;
-       struct smb_composite_connect *conn;
-       struct dcerpc_pipe *lsa_pipe;
-
-       struct lsa_ObjectAttribute objectattr;
-       struct lsa_OpenPolicy2 openpolicy;
-       struct policy_handle policy_handle;
-
-       struct lsa_QueryInfoPolicy queryinfo;
-
-       struct lsa_Close close;
-};
-
-static void get_lsa_pipe_recv_dcs(struct composite_context *ctx);
-static void get_lsa_pipe_recv_tree(struct composite_context *ctx);
-static void get_lsa_pipe_recv_pipe(struct composite_context *ctx);
-static void get_lsa_pipe_recv_openpol(struct rpc_request *req);
-static void get_lsa_pipe_recv_queryinfo(struct rpc_request *req);
-static void get_lsa_pipe_recv_close(struct rpc_request *req);
-
-struct composite_context *wb_get_lsa_pipe_send(struct event_context *event_ctx,
-                                              struct messaging_context *msg_ctx,
-                                              const char *domain)
-{
-       struct composite_context *result, *ctx;
-       struct get_lsa_pipe_state *state;
-
-       result = talloc_zero(NULL, struct composite_context);
-       if (result == NULL) goto failed;
-       result->state = COMPOSITE_STATE_IN_PROGRESS;
-       result->event_ctx = event_ctx;
-
-       state = talloc(result, struct get_lsa_pipe_state);
-       if (state == NULL) goto failed;
-       result->private_data = state;
-       state->ctx = result;
-
-       state->domain = domain;
-
-       state->finddcs = talloc(state, struct wb_finddcs);
-       if (state->finddcs == NULL) goto failed;
-
-       state->finddcs->in.msg_ctx = msg_ctx;
-       state->finddcs->in.domain = lp_workgroup();
-
-       ctx = wb_finddcs_send(state->finddcs, event_ctx);
-       if (ctx == NULL) goto failed;
-
-       ctx->async.fn = get_lsa_pipe_recv_dcs;
-       ctx->async.private_data = state;
-       return result;
-
- failed:
-       talloc_free(result);
-       return NULL;
-}
-
-static void get_lsa_pipe_recv_dcs(struct composite_context *ctx)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct get_lsa_pipe_state);
-
-       state->ctx->status = wb_finddcs_recv(ctx, state);
-       if (!comp_is_ok(state->ctx)) return;
-
-       state->conn = talloc(state, struct smb_composite_connect);
-       if (comp_nomem(state->conn, state->ctx)) return;
-
-       state->conn->in.dest_host = state->finddcs->out.dcs[0].address;
-       state->conn->in.port = 0;
-       state->conn->in.called_name = state->finddcs->out.dcs[0].name;
-       state->conn->in.service = "IPC$";
-       state->conn->in.service_type = "IPC";
-       state->conn->in.workgroup = lp_workgroup();
-
-       state->conn->in.credentials = cli_credentials_init(state->conn);
-       if (comp_nomem(state->conn->in.credentials, state->ctx)) return;
-       cli_credentials_set_conf(state->conn->in.credentials);
-       cli_credentials_set_anonymous(state->conn->in.credentials);
-
-       ctx = smb_composite_connect_send(state->conn, state, 
-                                        state->ctx->event_ctx);
-       comp_cont(state->ctx, ctx, get_lsa_pipe_recv_tree, state);
-}
-
-static void get_lsa_pipe_recv_tree(struct composite_context *ctx)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct get_lsa_pipe_state);
-
-       state->ctx->status = smb_composite_connect_recv(ctx, state);
-       if (!comp_is_ok(state->ctx)) return;
-
-       state->lsa_pipe = dcerpc_pipe_init(state, state->ctx->event_ctx);
-       if (comp_nomem(state->lsa_pipe, state->ctx)) return;
-
-       ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn,
-                                       state->conn->out.tree, "\\lsarpc");
-       comp_cont(state->ctx, ctx, get_lsa_pipe_recv_pipe, state);
-}
-
-static void get_lsa_pipe_recv_pipe(struct composite_context *ctx)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct get_lsa_pipe_state);
-       struct rpc_request *req;
-
-       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
-       if (!comp_is_ok(state->ctx)) return;
-
-       talloc_unlink(state, state->conn->out.tree); /* The pipe owns it now */
-       state->conn->out.tree = NULL;
-
-       state->ctx->status = dcerpc_bind_auth_none(state->lsa_pipe,
-                                                  DCERPC_LSARPC_UUID,
-                                                  DCERPC_LSARPC_VERSION);
-       if (!comp_is_ok(state->ctx)) return;
-
-       ZERO_STRUCT(state->openpolicy);
-       state->openpolicy.in.system_name =
-               talloc_asprintf(state, "\\\\%s",
-                               dcerpc_server_name(state->lsa_pipe));
-       if (comp_nomem(state->openpolicy.in.system_name, state->ctx)) return;
-
-       ZERO_STRUCT(state->objectattr);
-       state->openpolicy.in.attr = &state->objectattr;
-       state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       state->openpolicy.out.handle = &state->policy_handle;
-
-       req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
-                                         &state->openpolicy);
-       rpc_cont(state->ctx, req, get_lsa_pipe_recv_openpol, state);
-}
-
-static void get_lsa_pipe_recv_openpol(struct rpc_request *req)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(req->async.private, struct get_lsa_pipe_state);
-
-       state->ctx->status = dcerpc_ndr_request_recv(req);
-       if (!comp_is_ok(state->ctx)) return;
-       state->ctx->status = state->openpolicy.out.result;
-       if (!comp_is_ok(state->ctx)) return;
-
-       ZERO_STRUCT(state->queryinfo);
-       state->queryinfo.in.handle = &state->policy_handle;
-       state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
-
-       req = dcerpc_lsa_QueryInfoPolicy_send(state->lsa_pipe, state,
-                                             &state->queryinfo);
-       rpc_cont(state->ctx, req, get_lsa_pipe_recv_queryinfo, state);
-}
-
-static void get_lsa_pipe_recv_queryinfo(struct rpc_request *req)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(req->async.private, struct get_lsa_pipe_state);
-
-       state->ctx->status = dcerpc_ndr_request_recv(req);
-       if (!comp_is_ok(state->ctx)) return;
-       state->ctx->status = state->queryinfo.out.result;
-       if (!comp_is_ok(state->ctx)) return;
-
-       ZERO_STRUCT(state->close);
-       state->close.in.handle = &state->policy_handle;
-       state->close.out.handle = &state->policy_handle;
-
-       req = dcerpc_lsa_Close_send(state->lsa_pipe, state,
-                                   &state->close);
-       rpc_cont(state->ctx, req, get_lsa_pipe_recv_close, state);
-}
-
-static void get_lsa_pipe_recv_close(struct rpc_request *req)
-{
-       struct get_lsa_pipe_state *state =
-               talloc_get_type(req->async.private, struct get_lsa_pipe_state);
-
-       state->ctx->status = dcerpc_ndr_request_recv(req);
-       if (!comp_is_ok(state->ctx)) return;
-       state->ctx->status = state->close.out.result;
-       if (!comp_is_ok(state->ctx)) return;
-
-       comp_done(state->ctx);
-}
-
-NTSTATUS wb_get_lsa_pipe_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
-                             struct dom_sid **sid, struct dcerpc_pipe **pipe)
-{
-       NTSTATUS status = composite_wait(c);
-       if (NT_STATUS_IS_OK(status)) {
-               struct get_lsa_pipe_state *state =
-                       talloc_get_type(c->private_data,
-                                       struct get_lsa_pipe_state);
-               *sid = talloc_steal(mem_ctx,
-                                   state->queryinfo.out.info->domain.sid);
-               *pipe = talloc_steal(mem_ctx, state->lsa_pipe);
-       }
-       talloc_free(c);
-       return status;
-}
-
-NTSTATUS wb_get_lsa_pipe(struct event_context *event_ctx,
-                        struct messaging_context *msg_ctx,
-                        const char *domain,
-                        TALLOC_CTX *mem_ctx,
-                        struct dom_sid **sid,
-                        struct dcerpc_pipe **pipe)
-{
-       struct composite_context *c =
-               wb_get_lsa_pipe_send(event_ctx, msg_ctx, domain);
-       return wb_get_lsa_pipe_recv(c, mem_ctx, sid, pipe);
-}
-
 struct lsa_lookupnames_state {
        struct composite_context *ctx;
        uint32_t num_names;
@@ -770,143 +493,15 @@ NTSTATUS wb_lsa_lookupnames(struct dcerpc_pipe *lsa_pipe,
        return wb_lsa_lookupnames_recv(c, mem_ctx, sids);
 }
 
-struct lsa_lookupname_state {
-       struct composite_context *ctx;
-       struct dcerpc_pipe *lsa_pipe;
-       const char *name;
-       struct wb_sid_object *sid;
-
-       struct lsa_ObjectAttribute objectattr;
-       struct lsa_OpenPolicy2 openpolicy;
-       struct policy_handle policy_handle;
-       struct lsa_Close close;
-};
-
-static void lsa_lookupname_recv_open(struct rpc_request *req);
-static void lsa_lookupname_recv_sids(struct composite_context *ctx);
-
-struct composite_context *wb_lsa_lookupname_send(struct dcerpc_pipe *lsa_pipe,
-                                                const char *name)
-{
-       struct composite_context *result;
-       struct rpc_request *req;
-       struct lsa_lookupname_state *state;
-
-       result = talloc_zero(NULL, struct composite_context);
-       if (result == NULL) goto failed;
-       result->state = COMPOSITE_STATE_IN_PROGRESS;
-       result->event_ctx = lsa_pipe->conn->event_ctx;
-
-       state = talloc(result, struct lsa_lookupname_state);
-       if (state == NULL) goto failed;
-       result->private_data = state;
-
-       state->lsa_pipe = lsa_pipe;
-       state->name = talloc_strdup(state, name);
-       if (state->name == NULL) goto failed;
-       state->ctx = result;
-
-       ZERO_STRUCT(state->openpolicy);
-       state->openpolicy.in.system_name =
-               talloc_asprintf(state, "\\\\%s",
-                               dcerpc_server_name(state->lsa_pipe));
-       ZERO_STRUCT(state->objectattr);
-       state->openpolicy.in.attr = &state->objectattr;
-       state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       state->openpolicy.out.handle = &state->policy_handle;
-
-       req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
-                                         &state->openpolicy);
-       if (req == NULL) goto failed;
-
-       req->async.callback = lsa_lookupname_recv_open;
-       req->async.private = state;
-       return result;
-
- failed:
-       talloc_free(result);
-       return NULL;
-}
-
-static void lsa_lookupname_recv_open(struct rpc_request *req)
-{
-       struct lsa_lookupname_state *state =
-               talloc_get_type(req->async.private,
-                               struct lsa_lookupname_state);
-       struct composite_context *ctx;
-
-       state->ctx->status = dcerpc_ndr_request_recv(req);
-       if (!comp_is_ok(state->ctx)) return;
-       state->ctx->status = state->openpolicy.out.result;
-       if (!comp_is_ok(state->ctx)) return;
-
-       ctx = wb_lsa_lookupnames_send(state->lsa_pipe, &state->policy_handle,
-                                     1, &state->name);
-       comp_cont(state->ctx, ctx, lsa_lookupname_recv_sids, state);
-}
-
-static void lsa_lookupname_recv_sids(struct composite_context *ctx)
-{
-       struct lsa_lookupname_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct lsa_lookupname_state);
-       struct rpc_request *req;
-       struct wb_sid_object **sids;
-
-       state->ctx->status = wb_lsa_lookupnames_recv(ctx, state, &sids);
-
-       if (NT_STATUS_IS_OK(state->ctx->status)) {
-               state->sid = NULL;
-               if (sids != NULL) {
-                       state->sid = sids[0];
-               }
-       }
-
-       ZERO_STRUCT(state->close);
-       state->close.in.handle = &state->policy_handle;
-       state->close.out.handle = &state->policy_handle;
-
-       req = dcerpc_lsa_Close_send(state->lsa_pipe, state,
-                                   &state->close);
-       if (req != NULL) {
-               req->async.callback =
-                       (void(*)(struct rpc_request *))talloc_free;
-       }
-
-       comp_done(state->ctx);
-}
-
-NTSTATUS wb_lsa_lookupname_recv(struct composite_context *c,
-                               TALLOC_CTX *mem_ctx,
-                               struct wb_sid_object **sid)
-{
-       NTSTATUS status = composite_wait(c);
-       if (NT_STATUS_IS_OK(status)) {
-               struct lsa_lookupname_state *state =
-                       talloc_get_type(c->private_data,
-                                       struct lsa_lookupname_state);
-               *sid = talloc_steal(mem_ctx, state->sid);
-       }
-       talloc_free(c);
-       return status;
-}
-
-NTSTATUS wb_lsa_lookupname(struct dcerpc_pipe *lsa_pipe, const char *name,
-                          TALLOC_CTX *mem_ctx, struct wb_sid_object **sid)
-{
-       struct composite_context *c =
-               wb_lsa_lookupname_send(lsa_pipe, name);
-       return wb_lsa_lookupname_recv(c, mem_ctx, sid);
-}
-
 struct cmd_lookupname_state {
        struct composite_context *ctx;
        struct wbsrv_call *call;
+       struct wbsrv_domain *domain;
        const char *name;
        struct wb_sid_object *result;
 };
 
-static void cmd_lookupname_recv_lsa(struct composite_context *ctx);
+static void cmd_lookupname_recv_init(struct composite_context *ctx);
 static void cmd_lookupname_recv_sid(struct composite_context *ctx);
 
 struct composite_context *wb_cmd_lookupname_send(struct wbsrv_call *call,
@@ -929,19 +524,23 @@ struct composite_context *wb_cmd_lookupname_send(struct wbsrv_call *call,
        state->call = call;
        state->name = talloc_strdup(state, name);
 
-       if (service->lsa_pipe != NULL) {
-               ctx = wb_lsa_lookupname_send(service->lsa_pipe, name);
+       state->domain = service->domains;
+
+       if (state->domain->initialized) {
+               ctx = wb_lsa_lookupnames_send(state->domain->lsa_pipe,
+                                             state->domain->lsa_policy,
+                                             1, &name);
                if (ctx == NULL) goto failed;
                ctx->async.fn = cmd_lookupname_recv_sid;
                ctx->async.private_data = state;
                return result;
        }
 
-       ctx = wb_get_lsa_pipe_send(result->event_ctx, 
-                                  call->wbconn->conn->msg_ctx,
-                                  lp_workgroup());
+       ctx = wb_init_domain_send(state->domain,
+                                 result->event_ctx, 
+                                 call->wbconn->conn->msg_ctx);
        if (ctx == NULL) goto failed;
-       ctx->async.fn = cmd_lookupname_recv_lsa;
+       ctx->async.fn = cmd_lookupname_recv_init;
        ctx->async.private_data = state;
        return result;
 
@@ -950,26 +549,18 @@ struct composite_context *wb_cmd_lookupname_send(struct wbsrv_call *call,
        return NULL;
 }
 
-static void cmd_lookupname_recv_lsa(struct composite_context *ctx)
+static void cmd_lookupname_recv_init(struct composite_context *ctx)
 {
        struct cmd_lookupname_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct cmd_lookupname_state);
-       struct wbsrv_service *service =
-               state->call->wbconn->listen_socket->service;
 
-       struct dom_sid *sid;
-       struct dcerpc_pipe *pipe;
-
-       state->ctx->status = wb_get_lsa_pipe_recv(ctx, state, &sid, &pipe);
+       state->ctx->status = wb_init_domain_recv(ctx);
        if (!comp_is_ok(state->ctx)) return;
 
-       if (service->lsa_pipe == NULL) {
-               /* Only put the new pipe in if nobody else was faster. */
-               service->lsa_pipe = talloc_steal(service, pipe);
-       }
-
-       ctx = wb_lsa_lookupname_send(service->lsa_pipe, state->name);
+       ctx = wb_lsa_lookupnames_send(state->domain->lsa_pipe,
+                                     state->domain->lsa_policy,
+                                     1, &state->name);
        comp_cont(state->ctx, ctx, cmd_lookupname_recv_sid, state);
 }
 
@@ -978,9 +569,11 @@ static void cmd_lookupname_recv_sid(struct composite_context *ctx)
        struct cmd_lookupname_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct cmd_lookupname_state);
+       struct wb_sid_object **sids;
+
+       state->ctx->status = wb_lsa_lookupnames_recv(ctx, state, &sids);
+       state->result = sids[0];
 
-       state->ctx->status = wb_lsa_lookupname_recv(ctx, state,
-                                                   &state->result);
        if (!comp_is_ok(state->ctx)) return;
 
        comp_done(state->ctx);
@@ -1012,11 +605,10 @@ NTSTATUS wb_cmd_lookupname(struct wbsrv_call *call, const char *name,
 struct cmd_checkmachacc_state {
        struct composite_context *ctx;
        struct wbsrv_call *call;
-       struct cli_credentials *wks_creds;
+       struct wbsrv_domain *domain;
 };
 
-static void cmd_checkmachacc_recv_lsa(struct composite_context *ctx);
-static void cmd_checkmachacc_recv_creds(struct composite_context *ctx);
+static void cmd_checkmachacc_recv_init(struct composite_context *ctx);
 
 struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
 {
@@ -1035,40 +627,12 @@ struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
        result->private_data = state;
        state->call = call;
 
-       state->wks_creds = cli_credentials_init(state);
-       if (state->wks_creds == NULL) goto failed;
-
-       cli_credentials_set_conf(state->wks_creds);
-
-       state->ctx->status =
-               cli_credentials_set_machine_account(state->wks_creds);
-       if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
-
-       if (service->netlogon_pipe != NULL) {
-               talloc_free(service->netlogon_pipe);
-               service->netlogon_pipe = NULL;
-       }
-
-       if (service->lsa_pipe != NULL) {
-               struct smbcli_tree *tree =
-                       dcerpc_smb_tree(service->lsa_pipe->conn);
-
-               if (tree == NULL) goto failed;
-
-               ctx = wb_get_schannel_creds_send(state->wks_creds, tree,
-                                                result->event_ctx);
-               if (ctx == NULL) goto failed;
-
-               ctx->async.fn = cmd_checkmachacc_recv_creds;
-               ctx->async.private_data = state;
-               return result;
-       }
+       state->domain = service->domains;
 
-       ctx = wb_get_lsa_pipe_send(result->event_ctx, 
-                                  call->wbconn->conn->msg_ctx,
-                                  lp_workgroup());
+       ctx = wb_init_domain_send(state->domain, result->event_ctx, 
+                                 call->wbconn->conn->msg_ctx);
        if (ctx == NULL) goto failed;
-       ctx->async.fn = cmd_checkmachacc_recv_lsa;
+       ctx->async.fn = cmd_checkmachacc_recv_init;
        ctx->async.private_data = state;
 
        return result;
@@ -1078,63 +642,23 @@ struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
        return NULL;
 }
 
-static void cmd_checkmachacc_recv_lsa(struct composite_context *ctx)
-{
-       struct cmd_checkmachacc_state *state =
-               talloc_get_type(ctx->async.private_data,
-                               struct cmd_checkmachacc_state);
-       struct wbsrv_service *service =
-               state->call->wbconn->listen_socket->service;
-
-       struct dom_sid *sid;
-       struct dcerpc_pipe *pipe;
-       struct smbcli_tree *tree;
-
-       state->ctx->status = wb_get_lsa_pipe_recv(ctx, state, &sid, &pipe);
-       if (!comp_is_ok(state->ctx)) return;
-
-       if (service->lsa_pipe == NULL) {
-               service->lsa_pipe = talloc_steal(service, pipe);
-       }
-
-       tree = dcerpc_smb_tree(service->lsa_pipe->conn);
-
-       if (tree == NULL) {
-               comp_error(state->ctx, NT_STATUS_INVALID_PARAMETER);
-               return;
-       }
-
-       ctx = wb_get_schannel_creds_send(state->wks_creds, tree,
-                                        state->ctx->event_ctx);
-       comp_cont(state->ctx, ctx, cmd_checkmachacc_recv_creds, state);
-}
-
-static void cmd_checkmachacc_recv_creds(struct composite_context *ctx)
+static void cmd_checkmachacc_recv_init(struct composite_context *ctx)
 {
        struct cmd_checkmachacc_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct cmd_checkmachacc_state);
-       struct wbsrv_service *service =
-               state->call->wbconn->listen_socket->service;
-       struct dcerpc_pipe *pipe;
 
-       state->ctx->status = wb_get_schannel_creds_recv(ctx, state, &pipe);
+       state->ctx->status = wb_init_domain_recv(ctx);
        if (!comp_is_ok(state->ctx)) return;
 
-       if (service->netlogon_pipe != NULL) {
-               /* Someone else was faster, we need to replace it with our
-                * pipe */
-               talloc_free(service->netlogon_pipe);
-       }
-
-       service->netlogon_pipe = talloc_steal(service, pipe);
-
        comp_done(state->ctx);
 }
 
 NTSTATUS wb_cmd_checkmachacc_recv(struct composite_context *c)
 {
-       return composite_wait(c);
+       NTSTATUS status = composite_wait(c);
+       talloc_free(c);
+       return status;
 }
 
 NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call)
index e2fa7e369891e40648de6ca75d280ab1a54ce005..1bf1c78ca83953c1877503d33d76a6fcfee302f6 100644 (file)
 
 #include "librpc/gen_ndr/lsa.h"
 
-struct wb_finddcs {
-       struct {
-               struct messaging_context *msg_ctx;
-               const char *domain;
-       } in;
-
-       struct {
-               int num_dcs;
-               struct nbt_dc_name {
-                       const char *address;
-                       const char *name;
-               } *dcs;
-       } out;
+struct nbt_dc_name {
+       const char *address;
+       const char *name;
 };
 
 struct wb_sid_object {
diff --git a/samba4-winsrepl/source/winbind/wb_init_domain.c b/samba4-winsrepl/source/winbind/wb_init_domain.c
new file mode 100644 (file)
index 0000000..0ac7d11
--- /dev/null
@@ -0,0 +1,575 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Volker Lendecke 2005
+   
+   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.
+*/
+/*
+  a composite API for initializing a domain
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_stream.h"
+
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/gen_ndr/samr.h"
+#include "lib/messaging/irpc.h"
+#include "librpc/gen_ndr/irpc.h"
+#include "librpc/gen_ndr/ndr_irpc.h"
+#include "libcli/raw/libcliraw.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "libcli/auth/credentials.h"
+
+
+/* Helper to initialize LSA with different auth methods and opening the lsa
+ * policy */
+
+struct init_lsa_state {
+       struct composite_context *ctx;
+       struct dcerpc_pipe *lsa_pipe;
+
+       uint8_t auth_type;
+       struct cli_credentials *creds;
+
+       struct lsa_ObjectAttribute objectattr;
+       struct lsa_OpenPolicy2 openpolicy;
+       struct policy_handle *handle;
+};
+
+static void init_lsa_recv_pipe(struct composite_context *ctx);
+static void init_lsa_recv_openpol(struct rpc_request *req);
+
+static struct composite_context *wb_init_lsa_send(struct smbcli_tree *tree,
+                                                 uint8_t auth_type,
+                                                 struct cli_credentials *creds)
+{
+       struct composite_context *result, *ctx;
+       struct init_lsa_state *state;
+
+       result = talloc(NULL, struct composite_context);
+       if (result == NULL) goto failed;
+       result->state = COMPOSITE_STATE_IN_PROGRESS;
+       result->event_ctx = tree->session->transport->socket->event.ctx;
+
+       state = talloc(result, struct init_lsa_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
+
+       state->auth_type = auth_type;
+       state->creds = creds;
+
+       state->lsa_pipe = dcerpc_pipe_init(state, result->event_ctx);
+       if (state->lsa_pipe == NULL) goto failed;
+
+       ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
+                                       "\\lsarpc");
+       ctx->async.fn = init_lsa_recv_pipe;
+       ctx->async.private_data = state;
+       return result;
+       
+ failed:
+       talloc_free(result);
+       return NULL;
+}
+
+static void init_lsa_recv_pipe(struct composite_context *ctx)
+{
+       struct init_lsa_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_lsa_state);
+       struct rpc_request *req;
+
+       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
+       if (!comp_is_ok(state->ctx)) return;
+
+       switch (state->auth_type) {
+       case DCERPC_AUTH_TYPE_NONE:
+               state->ctx->status =
+                       dcerpc_bind_auth_none(state->lsa_pipe,
+                                             DCERPC_LSARPC_UUID,
+                                             DCERPC_LSARPC_VERSION);
+               break;
+       case DCERPC_AUTH_TYPE_NTLMSSP:
+       case DCERPC_AUTH_TYPE_SCHANNEL:
+               if (state->creds == NULL) {
+                       comp_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
+                       return;
+               }
+               state->lsa_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
+               state->ctx->status =
+                       dcerpc_bind_auth_password(state->lsa_pipe,
+                                                 DCERPC_LSARPC_UUID,
+                                                 DCERPC_LSARPC_VERSION,
+                                                 state->creds,
+                                                 state->auth_type,
+                                                 NULL);
+               break;
+       default:
+               state->ctx->status = NT_STATUS_INTERNAL_ERROR;
+               
+       }
+                       
+       state->handle = talloc(state, struct policy_handle);
+       if (comp_nomem(state->handle, state->ctx)) return;
+
+       state->openpolicy.in.system_name =
+               talloc_asprintf(state, "\\\\%s",
+                               dcerpc_server_name(state->lsa_pipe));
+       ZERO_STRUCT(state->objectattr);
+       state->openpolicy.in.attr = &state->objectattr;
+       state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       state->openpolicy.out.handle = state->handle;
+
+       req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
+                                         &state->openpolicy);
+       rpc_cont(state->ctx, req, init_lsa_recv_openpol, state);
+}
+
+static void init_lsa_recv_openpol(struct rpc_request *req)
+{
+       struct init_lsa_state *state =
+               talloc_get_type(req->async.private,
+                               struct init_lsa_state);
+
+       state->ctx->status = dcerpc_ndr_request_recv(req);
+       if (!comp_is_ok(state->ctx)) return;
+       state->ctx->status = state->openpolicy.out.result;
+       if (!comp_is_ok(state->ctx)) return;
+
+       comp_done(state->ctx);
+}
+
+static NTSTATUS wb_init_lsa_recv(struct composite_context *c,
+                                TALLOC_CTX *mem_ctx,
+                                struct dcerpc_pipe **lsa_pipe,
+                                struct policy_handle **lsa_policy)
+{
+       NTSTATUS status = composite_wait(c);
+       if (NT_STATUS_IS_OK(status)) {
+               struct init_lsa_state *state =
+                       talloc_get_type(c->private_data,
+                                       struct init_lsa_state);
+               *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
+               *lsa_policy = talloc_steal(mem_ctx, state->handle);
+       }
+       talloc_free(c);
+       return status;
+}
+
+/*
+ * Initialize a domain:
+ *
+ * - With schannel credentials, try to open the SMB connection with the machine
+ *   creds. Fall back to anonymous.
+ *
+ * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
+ *   pipe.
+ *
+ * - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
+ *   to schannel and then to anon bind.
+ *
+ * - With queryinfopolicy, verify that we're talking to the right domain
+ *
+ * A bit complex, but with all the combinations I think it's the best we can
+ * get. NT4, W2k3 and W2k all have different combinations, but in the end we
+ * have a signed&sealed lsa connection on all of them.
+ *
+ * Not sure if it is overkill, but it seems to work.
+ */
+
+struct init_domain_state {
+       struct composite_context *ctx;
+       struct wbsrv_domain *domain;
+
+       int num_dcs;
+       struct nbt_dc_name *dcs;
+
+       struct smb_composite_connect conn;
+
+       struct dcerpc_pipe *auth2_pipe;
+       struct dcerpc_pipe *netlogon_pipe;
+
+       struct dcerpc_pipe *lsa_pipe;
+       struct policy_handle *lsa_policy;
+
+       struct lsa_QueryInfoPolicy queryinfo;
+};
+
+static void init_domain_recv_dcs(struct composite_context *ctx);
+static void init_domain_recv_authsmb(struct composite_context *ctx);
+static void init_domain_anonsmb(struct init_domain_state *state);
+static void init_domain_recv_anonsmb(struct composite_context *ctx);
+static void init_domain_openpipes(struct init_domain_state *state);
+static void init_domain_openlsa(struct init_domain_state *state);
+static void init_domain_recv_netlogoncreds(struct composite_context *ctx);
+static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
+static void init_domain_recv_lsa_ntlmssp(struct composite_context *ctx);
+static void init_domain_recv_lsa_schannel(struct composite_context *ctx);
+static void init_domain_recv_lsa_none(struct composite_context *ctx);
+static void init_domain_check_lsa(struct init_domain_state *state);
+static void init_domain_recv_queryinfo(struct rpc_request *req);
+
+struct composite_context *wb_init_domain_send(struct wbsrv_domain *domain,
+                                             struct event_context *event_ctx,
+                                             struct messaging_context *msg_ctx)
+{
+       struct composite_context *result, *ctx;
+       struct init_domain_state *state;
+
+       result = talloc(domain, struct composite_context);
+       if (result == NULL) goto failed;
+       result->state = COMPOSITE_STATE_IN_PROGRESS;
+       result->async.fn = NULL;
+       result->event_ctx = event_ctx;
+
+       state = talloc_zero(result, struct init_domain_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
+
+       state->domain = domain;
+
+       if (state->domain->schannel_creds != NULL) {
+               talloc_free(state->domain->schannel_creds);
+       }
+
+       state->domain->schannel_creds = cli_credentials_init(state->domain);
+       if (state->domain->schannel_creds == NULL) goto failed;
+       cli_credentials_set_conf(state->domain->schannel_creds);
+       state->ctx->status =
+               cli_credentials_set_machine_account(state->domain->
+                                                   schannel_creds);
+       if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
+
+       ctx = wb_finddcs_send(domain->name, domain->sid, event_ctx, msg_ctx);
+       if (ctx == NULL) goto failed;
+
+       ctx->async.fn = init_domain_recv_dcs;
+       ctx->async.private_data = state;
+       return result;
+
+ failed:
+       talloc_free(result);
+       return NULL;
+}
+
+static void init_domain_recv_dcs(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = wb_finddcs_recv(ctx, state, &state->num_dcs,
+                                            &state->dcs);
+       if (!comp_is_ok(state->ctx)) return;
+
+       if (state->num_dcs < 1) {
+               comp_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS);
+               return;
+       }
+
+       state->conn.in.dest_host = state->dcs[0].address;
+       state->conn.in.port = 0;
+       state->conn.in.called_name = state->dcs[0].name;
+       state->conn.in.service = "IPC$";
+       state->conn.in.service_type = "IPC";
+       state->conn.in.workgroup = state->domain->name;
+
+       if (state->domain->schannel_creds != NULL) {
+               /* Try to connect as workstation */
+               state->conn.in.credentials = state->domain->schannel_creds;
+               ctx = smb_composite_connect_send(&state->conn, state,
+                                                state->ctx->event_ctx);
+               comp_cont(state->ctx, ctx, init_domain_recv_authsmb, state);
+               return;
+       }
+
+       init_domain_anonsmb(state);
+}
+
+static void init_domain_recv_authsmb(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = smb_composite_connect_recv(ctx, state);
+       if (NT_STATUS_IS_OK(state->ctx->status)) {
+               init_domain_openpipes(state);
+               return;
+       }
+
+       init_domain_anonsmb(state);
+}
+
+static void init_domain_anonsmb(struct init_domain_state *state)
+{
+       struct composite_context *ctx;
+
+       state->conn.in.credentials = cli_credentials_init(state);
+       if (comp_nomem(state->conn.in.credentials, state->ctx)) return;
+       cli_credentials_set_conf(state->conn.in.credentials);
+       cli_credentials_set_anonymous(state->conn.in.credentials);
+       ctx = smb_composite_connect_send(&state->conn, state,
+                                        state->ctx->event_ctx);
+       comp_cont(state->ctx, ctx, init_domain_recv_anonsmb, state);
+}
+
+static void init_domain_recv_anonsmb(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = smb_composite_connect_recv(ctx, state);
+       if (!comp_is_ok(state->ctx)) return;
+
+       init_domain_openpipes(state);
+}
+
+static void init_domain_openpipes(struct init_domain_state *state)
+{
+       struct composite_context *ctx;
+
+       if (state->domain->schannel_creds == NULL) {
+               /* No chance to open netlogon */
+               init_domain_openlsa(state);
+               return;
+       }
+
+       ctx = wb_get_schannel_creds_send(state->domain->schannel_creds,
+                                        state->conn.out.tree,
+                                        state->ctx->event_ctx);
+       comp_cont(state->ctx, ctx, init_domain_recv_netlogoncreds, state);
+}
+
+static void init_domain_recv_netlogoncreds(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+       struct smbcli_tree *tree = NULL;
+
+       state->ctx->status = wb_get_schannel_creds_recv(ctx, state,
+                                                       &state->auth2_pipe);
+       if (!comp_is_ok(state->ctx)) return;
+
+       talloc_unlink(state, state->conn.out.tree); /* The pipe owns it now */
+
+       state->netlogon_pipe = dcerpc_pipe_init(state, state->ctx->event_ctx);
+       if (comp_nomem(state->netlogon_pipe, state->ctx)) return;
+
+       if (state->auth2_pipe != NULL) {
+               tree = dcerpc_smb_tree(state->auth2_pipe->conn);
+       }
+
+       if (tree == NULL) {
+               comp_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
+               return;
+       }
+
+       ctx = dcerpc_pipe_open_smb_send(state->netlogon_pipe->conn, tree,
+                                       "\\netlogon");
+       comp_cont(state->ctx, ctx, init_domain_recv_netlogonpipe, state);
+}
+
+static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
+       if (!comp_is_ok(state->ctx)) return;
+
+       state->netlogon_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
+       state->ctx->status =
+               dcerpc_bind_auth_password(state->netlogon_pipe,
+                                         DCERPC_NETLOGON_UUID,
+                                         DCERPC_NETLOGON_VERSION, 
+                                         state->domain->schannel_creds,
+                                         DCERPC_AUTH_TYPE_SCHANNEL,
+                                         NULL);
+       if (!comp_is_ok(state->ctx)) return;
+
+       init_domain_openlsa(state);
+}
+
+static void init_domain_openlsa(struct init_domain_state *state)
+{
+       struct composite_context *ctx;
+
+       if (state->domain->schannel_creds == NULL) {
+               ctx = wb_init_lsa_send(state->conn.out.tree,
+                                      DCERPC_AUTH_TYPE_NONE,
+                                      NULL);
+               comp_cont(state->ctx, ctx, init_domain_recv_lsa_none, state);
+               return;
+       }
+
+       ctx = wb_init_lsa_send(state->conn.out.tree, DCERPC_AUTH_TYPE_NTLMSSP,
+                              state->domain->schannel_creds);
+       comp_cont(state->ctx, ctx, init_domain_recv_lsa_ntlmssp, state);
+}
+
+static void init_domain_recv_lsa_ntlmssp(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
+                                             &state->lsa_policy);
+       if (NT_STATUS_IS_OK(state->ctx->status)) {
+               init_domain_check_lsa(state);
+               return;
+       }
+
+       ctx = wb_init_lsa_send(state->conn.out.tree,
+                              DCERPC_AUTH_TYPE_SCHANNEL,
+                              state->domain->schannel_creds);
+       comp_cont(state->ctx, ctx, init_domain_recv_lsa_schannel, state);
+}
+
+static void init_domain_recv_lsa_schannel(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
+                                             &state->lsa_policy);
+       if (NT_STATUS_IS_OK(state->ctx->status)) {
+               init_domain_check_lsa(state);
+               return;
+       }
+
+       ctx = wb_init_lsa_send(state->conn.out.tree,
+                              DCERPC_AUTH_TYPE_NONE, NULL);
+       comp_cont(state->ctx, ctx, init_domain_recv_lsa_none, state);
+}
+
+static void init_domain_recv_lsa_none(struct composite_context *ctx)
+{
+       struct init_domain_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct init_domain_state);
+
+       state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
+                                             &state->lsa_policy);
+       if (!comp_is_ok(state->ctx)) return;
+
+       init_domain_check_lsa(state);
+}
+
+static void init_domain_check_lsa(struct init_domain_state *state)
+{
+       struct rpc_request *req;
+
+       if (state->auth2_pipe == NULL) {
+               /* Give the tree to the LSA pipe, otherwise it has been given
+                * to the auth2 pipe already */
+               talloc_unlink(state, state->conn.out.tree);
+               state->conn.out.tree = NULL;
+       }
+
+       state->queryinfo.in.handle = state->lsa_policy;
+       state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
+
+       req = dcerpc_lsa_QueryInfoPolicy_send(state->lsa_pipe, state,
+                                             &state->queryinfo);
+       rpc_cont(state->ctx, req, init_domain_recv_queryinfo, state);
+}
+
+static void init_domain_recv_queryinfo(struct rpc_request *req)
+{
+       struct init_domain_state *state =
+               talloc_get_type(req->async.private, struct init_domain_state);
+       struct lsa_DomainInfo *dominfo;
+
+       state->ctx->status = dcerpc_ndr_request_recv(req);
+       if (!comp_is_ok(state->ctx)) return;
+       state->ctx->status = state->queryinfo.out.result;
+       if (!comp_is_ok(state->ctx)) return;
+
+       dominfo = &state->queryinfo.out.info->account_domain;
+
+       if (strcasecmp(state->domain->name, dominfo->name.string) != 0) {
+               DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
+                         state->domain->name,
+                         dcerpc_server_name(state->lsa_pipe),
+                         dominfo->name.string));
+               comp_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
+               return;
+       }
+
+       if (!dom_sid_equal(state->domain->sid, dominfo->sid)) {
+               DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
+                         dom_sid_string(state, state->domain->sid),
+                         dcerpc_server_name(state->lsa_pipe),
+                         dom_sid_string(state, dominfo->sid)));
+               comp_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
+               return;
+       }
+
+       comp_done(state->ctx);
+}
+
+NTSTATUS wb_init_domain_recv(struct composite_context *c)
+{
+       NTSTATUS status = composite_wait(c);
+       if (NT_STATUS_IS_OK(status)) {
+               struct init_domain_state *state =
+                       talloc_get_type(c->private_data,
+                                       struct init_domain_state);
+               struct wbsrv_domain *domain = state->domain;
+
+               talloc_free(domain->netlogon_auth2_pipe);
+               domain->netlogon_auth2_pipe =
+                       talloc_steal(domain, state->auth2_pipe);
+
+               talloc_free(domain->netlogon_pipe);
+               domain->netlogon_pipe =
+                       talloc_steal(domain, state->netlogon_pipe);
+
+               talloc_free(domain->lsa_pipe);
+               domain->lsa_pipe =
+                       talloc_steal(domain, state->lsa_pipe);
+
+               talloc_free(domain->lsa_policy);
+               domain->lsa_policy =
+                       talloc_steal(domain, state->lsa_policy);
+
+               domain->initialized = True;
+       }
+       talloc_free(c);
+       return status;
+}
+
+NTSTATUS wb_init_domain(struct wbsrv_domain *domain,
+                       struct event_context *event_ctx,
+                       struct messaging_context *messaging_ctx)
+{
+       struct composite_context *c =
+               wb_init_domain_send(domain, event_ctx, messaging_ctx);
+       return wb_init_domain_recv(c);
+}
index 23e04ba0e09c2a2417aa093956d924d42dd52fec..64d75016bb05baaec5c2be9a6d255923071fe38c 100644 (file)
@@ -33,6 +33,7 @@
 #include "libcli/smb_composite/smb_composite.h"
 #include "include/version.h"
 #include "lib/events/events.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
 
 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
 {
@@ -175,3 +176,122 @@ static void lookupname_recv_sid(struct composite_context *ctx)
                return;
        }
 }
+
+NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
+{
+       struct wbsrv_service *service =
+               s3call->call->wbconn->listen_socket->service;
+       
+       s3call->response.result                 = WINBINDD_ERROR;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
+{
+       struct wbsrv_service *service =
+               s3call->call->wbconn->listen_socket->service;
+       struct creds_CredentialState *creds_state;
+       struct netr_Authenticator auth, auth2;
+       struct netr_NetworkInfo ninfo;
+       struct netr_LogonSamLogon r;
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx = talloc_new(s3call);
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ZERO_STRUCT(auth2);
+       creds_state = cli_credentials_get_netlogon_creds(service->domains->schannel_creds);
+       
+       creds_client_authenticator(creds_state, &auth);
+
+       ninfo.identity_info.account_name.string = s3call->request.data.auth_crap.user;
+       ninfo.identity_info.domain_name.string = s3call->request.data.auth_crap.domain;
+       ninfo.identity_info.parameter_control = 0;
+       ninfo.identity_info.logon_id_low = 0;
+       ninfo.identity_info.logon_id_high = 0;
+       ninfo.identity_info.workstation.string = s3call->request.data.auth_crap.workstation;
+       memcpy(ninfo.challenge, s3call->request.data.auth_crap.chal,
+              sizeof(ninfo.challenge));
+       ninfo.nt.length = s3call->request.data.auth_crap.nt_resp_len;
+       ninfo.nt.data = s3call->request.data.auth_crap.nt_resp;
+       ninfo.lm.length = s3call->request.data.auth_crap.lm_resp_len;
+       ninfo.lm.data = s3call->request.data.auth_crap.lm_resp;
+
+       r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(service->domains->netlogon_pipe));
+       r.in.workstation = cli_credentials_get_workstation(service->domains->schannel_creds);
+       r.in.credential = &auth;
+       r.in.return_authenticator = &auth2;
+       r.in.logon_level = 2;
+       r.in.validation_level = 3;
+       r.in.logon.network = &ninfo;
+
+       r.out.return_authenticator = NULL;
+       status = dcerpc_netr_LogonSamLogon(service->domains->netlogon_pipe, mem_ctx, &r);
+       if (!r.out.return_authenticator || 
+           !creds_client_check(creds_state, &r.out.return_authenticator->cred)) {
+               DEBUG(0, ("Credentials check failed!\n"));
+               status = NT_STATUS_ACCESS_DENIED;
+       }
+       if (NT_STATUS_IS_OK(status)) {
+               struct netr_SamBaseInfo *base;
+               switch (r.in.validation_level) {
+               case 2:
+                       base = &r.out.validation.sam2->base;
+                       break;
+               case 3:
+                       base = &r.out.validation.sam3->base;
+                       break;
+               case 6:
+                       base = &r.out.validation.sam6->base;
+                       break;
+               }
+
+               creds_decrypt_samlogon(creds_state, 
+                                      r.in.validation_level, 
+                                      &r.out.validation);
+
+               if ((s3call->request.flags & WBFLAG_PAM_INFO3_NDR) 
+                   && (r.in.validation_level == 3)) {
+                       DATA_BLOB tmp_blob, tmp_blob2;
+                       status = ndr_push_struct_blob(&tmp_blob, mem_ctx, r.out.validation.sam3,
+                                                     (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
+                       if (NT_STATUS_IS_OK(status)) {
+                               tmp_blob2 = data_blob_talloc(mem_ctx, NULL, tmp_blob.length + 4);
+                               if (!tmp_blob2.data) {
+                                       status = NT_STATUS_NO_MEMORY;
+                               }
+                       }
+                       /* Ugly Samba3 winbind pipe compatability */
+                       if (NT_STATUS_IS_OK(status)) {
+                               SIVAL(tmp_blob2.data, 0, 1);
+                               memcpy(tmp_blob2.data + 4, tmp_blob.data, tmp_blob.length); 
+                       }
+                       s3call->response.extra_data = talloc_steal(s3call, tmp_blob2.data);
+                       s3call->response.length += tmp_blob2.length;
+               }
+               if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
+                       memcpy(s3call->response.data.auth.user_session_key, 
+                              base->key.key, sizeof(s3call->response.data.auth.user_session_key) /* 16 */);
+               }
+               if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
+                       memcpy(s3call->response.data.auth.first_8_lm_hash, 
+                              base->LMSessKey.key, sizeof(s3call->response.data.auth.first_8_lm_hash) /* 8 */);
+               }
+       }
+               
+       if (!NT_STATUS_IS_OK(status)) {
+               struct winbindd_response *resp = &s3call->response;
+               resp->result = WINBINDD_ERROR;
+       } else {
+               struct winbindd_response *resp = &s3call->response;
+               resp->result = WINBINDD_OK;
+       }
+               
+       WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
+                               nt_errstr(status));
+       WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
+                               nt_errstr(status));
+       s3call->response.data.auth.pam_error = nt_status_to_pam(status);
+       return NT_STATUS_OK;
+}
index f5e6fb71cf7ec8b4bf1e1dbadcea7dfa4f84c5e1..e99952be96c88a8ceee34f1d11bb58fb8bead8c8 100644 (file)
@@ -93,6 +93,12 @@ NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_call *call)
 
        case WINBINDD_LOOKUPNAME:
                return wbsrv_samba3_lookupname(s3call);
+
+       case WINBINDD_PAM_AUTH:
+               return wbsrv_samba3_pam_auth(s3call);
+
+       case WINBINDD_PAM_AUTH_CRAP:
+               return wbsrv_samba3_pam_auth_crap(s3call);
        }
 
        s3call->response.result = WINBINDD_ERROR;
index e18ea166629ac69c4bdb7d1544e9cd5542e75f0b..a835067dd01cc8a2eb09133d0aeca44531709c88 100644 (file)
@@ -42,13 +42,14 @@ void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *rea
 */
 static void wbsrv_accept(struct stream_connection *conn)
 {
-       struct wbsrv_listen_socket *listen_socket = talloc_get_type(conn->private,
-                                                                   struct wbsrv_listen_socket);
+       struct wbsrv_listen_socket *listen_socket =
+               talloc_get_type(conn->private, struct wbsrv_listen_socket);
        struct wbsrv_connection *wbconn;
 
        wbconn = talloc_zero(conn, struct wbsrv_connection);
        if (!wbconn) {
-               stream_terminate_connection(conn, "wbsrv_accept: out of memory");
+               stream_terminate_connection(conn,
+                                           "wbsrv_accept: out of memory");
                return;
        }
        wbconn->conn            = conn;
@@ -61,7 +62,8 @@ static void wbsrv_accept(struct stream_connection *conn)
 */
 static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
 {
-       struct wbsrv_connection *wbconn = talloc_get_type(conn->private, struct wbsrv_connection);
+       struct wbsrv_connection *wbconn =
+               talloc_get_type(conn->private, struct wbsrv_connection);
        const struct wbsrv_protocol_ops *ops = wbconn->listen_socket->ops;
        struct wbsrv_call *call;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -73,7 +75,8 @@ static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
                return;
        }
 
-       /* if the used protocol doesn't support pending requests disallow them */
+       /* if the used protocol doesn't support pending requests disallow
+        * them */
        if (wbconn->pending_calls && !ops->allow_pending_calls) {
                EVENT_FD_NOT_READABLE(conn->event.fde);
                return;
@@ -91,7 +94,7 @@ static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
                uint32_t packet_length;
 
                status = socket_recv(conn->socket, 
-                                    wbconn->partial.data + wbconn->partial_read,
+                                    wbconn->partial.data+wbconn->partial_read,
                                     4 - wbconn->partial_read,
                                     &nread, 0);
                if (NT_STATUS_IS_ERR(status)) goto failed;
@@ -102,8 +105,9 @@ static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
 
                packet_length = ops->packet_length(wbconn->partial);
 
-               wbconn->partial.data = talloc_realloc(wbconn, wbconn->partial.data, 
-                                                     uint8_t, packet_length);
+               wbconn->partial.data =
+                       talloc_realloc(wbconn, wbconn->partial.data, uint8_t,
+                                      packet_length);
                if (!wbconn->partial.data) goto nomem;
 
                wbconn->partial.length = packet_length;
@@ -127,9 +131,9 @@ static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
        call->event_ctx = conn->event.ctx;
 
        /*
-        * we have parsed the request, so we can reset the wbconn->partial_read,
-        * maybe we could also free wbconn->partial, but for now we keep it,
-        * and overwrite it the next time
+        * we have parsed the request, so we can reset the
+        * wbconn->partial_read, maybe we could also free wbconn->partial, but
+        * for now we keep it, and overwrite it the next time
         */
        wbconn->partial_read = 0;
 
@@ -244,6 +248,32 @@ static const struct wbsrv_protocol_ops wbsrv_samba3_protocol_ops = {
        .push_reply             = wbsrv_samba3_push_reply
 };
 
+static NTSTATUS init_my_domain(TALLOC_CTX *mem_ctx,
+                              struct wbsrv_domain **domain)
+{
+       struct wbsrv_domain *result;
+
+       result = talloc_zero(mem_ctx, struct wbsrv_domain);
+       NT_STATUS_HAVE_NO_MEMORY(result);
+
+       result->name = talloc_strdup(result, lp_workgroup());
+       if (result->name == NULL) {
+               talloc_free(result);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       result->sid = secrets_get_domain_sid(result, lp_workgroup());
+       if (result->sid == NULL) {
+               talloc_free(result);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       result->initialized = False;
+
+       *domain = result;
+       return NT_STATUS_OK;
+}
+
 /*
   startup the winbind task
 */
@@ -260,7 +290,8 @@ static void winbind_task_init(struct task_server *task)
           stream_setup_socket() call. */
        model_ops = process_model_byname("single");
        if (!model_ops) {
-               task_server_terminate(task, "Can't find 'single' process model_ops");
+               task_server_terminate(task,
+                                     "Can't find 'single' process model_ops");
                return;
        }
 
@@ -273,6 +304,14 @@ static void winbind_task_init(struct task_server *task)
        if (!service) goto nomem;
        service->task   = task;
 
+       status = init_my_domain(service, &service->domains);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Could not init my domain: %s\n",
+                         nt_errstr(status)));
+               task_server_terminate(task, nt_errstr(status));
+               return;
+       }
+
        /* setup the unprivileged samba3 socket */
        listen_socket = talloc(service, struct wbsrv_listen_socket);
        if (!listen_socket) goto nomem;
@@ -283,20 +322,24 @@ static void winbind_task_init(struct task_server *task)
        listen_socket->ops              = &wbsrv_samba3_protocol_ops;
        status = stream_setup_socket(task->event_ctx, model_ops,
                                     &wbsrv_ops, "unix",
-                                    listen_socket->socket_path, &port, listen_socket);
+                                    listen_socket->socket_path, &port,
+                                    listen_socket);
        if (!NT_STATUS_IS_OK(status)) goto listen_failed;
 
        /* setup the privileged samba3 socket */
        listen_socket = talloc(service, struct wbsrv_listen_socket);
        if (!listen_socket) goto nomem;
-       listen_socket->socket_path      = smbd_tmp_path(listen_socket, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
+       listen_socket->socket_path      =
+               smbd_tmp_path(listen_socket,
+                             WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
        if (!listen_socket->socket_path) goto nomem;
        listen_socket->service          = service;
        listen_socket->privileged       = True;
        listen_socket->ops              = &wbsrv_samba3_protocol_ops;
        status = stream_setup_socket(task->event_ctx, model_ops,
                                     &wbsrv_ops, "unix",
-                                    listen_socket->socket_path, &port, listen_socket);
+                                    listen_socket->socket_path, &port,
+                                    listen_socket);
        if (!NT_STATUS_IS_OK(status)) goto listen_failed;
 
        return;
@@ -314,7 +357,8 @@ nomem:
 /*
   initialise the winbind server
  */
-static NTSTATUS winbind_init(struct event_context *event_ctx, const struct model_ops *model_ops)
+static NTSTATUS winbind_init(struct event_context *event_ctx,
+                            const struct model_ops *model_ops)
 {
        return task_server_startup(event_ctx, model_ops, winbind_task_init);
 }
index 9d7f0c8336cabd40271c93f97b992b44c0f30ad2..df871f4c254008766b57d2a3bd37c3b0ab76e30f 100644 (file)
 /* this struct stores global data for the winbind task */
 struct wbsrv_service {
        struct task_server *task;
-       struct dcerpc_pipe *netlogon_pipe;
+
+       struct wbsrv_domain *domains;
+};
+
+struct wbsrv_samconn {
+       struct wbsrv_domain *domain;
+       void *private_data;
+
+       struct composite_context (*seqnum_send)(struct wbsrv_samconn *);
+       NTSTATUS (*seqnum_recv)(struct composite_context *, uint64_t *);
+};
+
+struct wbsrv_domain {
+       struct wbsrv_domain *next, *prev;
+
+       BOOL initialized;
+
+       const char *name;
+       const struct dom_sid *sid;
+
        struct dcerpc_pipe *lsa_pipe;
+       struct policy_handle *lsa_policy;
+
+       struct dcerpc_pipe *netlogon_auth2_pipe;
+       struct dcerpc_pipe *netlogon_pipe;
+       struct cli_credentials *schannel_creds;
 };
 
 /*