* big change -- volker's new async winbindd from trunk
authorjerry <jerry@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Wed, 8 Jun 2005 22:10:34 +0000 (22:10 +0000)
committerjerry <jerry@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Wed, 8 Jun 2005 22:10:34 +0000 (22:10 +0000)
git-svn-id: svn+ssh://svn.samba.org/data/svn/samba/branches/SAMBA_3_0@7415 0c0555d6-39d7-0310-84fc-f1cc0bd64818

51 files changed:
source/Makefile.in
source/include/client.h
source/include/idmap.h
source/include/includes.h
source/include/messages.h
source/include/rpc_client.h
source/lib/util.c
source/lib/util_sid.c
source/lib/util_str.c
source/libads/kerberos.c
source/libsmb/clidgram.c
source/libsmb/clientgen.c
source/libsmb/clitrans.c
source/nmbd/nmbd.c
source/nsswitch/wb_client.c
source/nsswitch/wbinfo.c
source/nsswitch/winbindd.c
source/nsswitch/winbindd.h
source/nsswitch/winbindd_ads.c
source/nsswitch/winbindd_async.c [new file with mode: 0644]
source/nsswitch/winbindd_cache.c
source/nsswitch/winbindd_cm.c
source/nsswitch/winbindd_dual.c
source/nsswitch/winbindd_group.c
source/nsswitch/winbindd_ldap.c [new file with mode: 0644]
source/nsswitch/winbindd_misc.c
source/nsswitch/winbindd_nss.h
source/nsswitch/winbindd_pam.c
source/nsswitch/winbindd_passdb.c
source/nsswitch/winbindd_reconnect.c [new file with mode: 0644]
source/nsswitch/winbindd_rpc.c
source/nsswitch/winbindd_sid.c
source/nsswitch/winbindd_user.c
source/nsswitch/winbindd_util.c
source/param/loadparm.c
source/passdb/lookup_sid.c
source/registry/reg_printing.c
source/rpc_client/cli_ds.c
source/rpc_client/cli_lsarpc.c
source/rpc_client/cli_netlogon.c
source/rpc_client/cli_pipe.c
source/rpc_client/cli_samr.c
source/rpc_parse/parse_prs.c
source/rpcclient/rpcclient.c
source/sam/idmap.c
source/sam/idmap_ldap.c
source/sam/idmap_util.c
source/torture/rpctorture.c
source/utils/net_rpc.c
source/utils/net_rpc_join.c
source/utils/smbcontrol.c

index e02ca033947ea2d31d925d5c2c68d71d235d0bde..1bac47f91958640b8f6e67e2f85e749351735901 100644 (file)
@@ -328,7 +328,6 @@ GROUPDB_OBJ = groupdb/mapping.o
 
 PROFILE_OBJ = profile/profile.o
 PROFILES_OBJ = utils/profiles.o
-EDITREG_OBJ = utils/editreg.o
 
 OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
 
@@ -655,9 +654,11 @@ WINBINDD_OBJ1 = \
                nsswitch/winbindd_cm.o \
                nsswitch/winbindd_wins.o \
                nsswitch/winbindd_rpc.o \
+               nsswitch/winbindd_reconnect.o \
                nsswitch/winbindd_ads.o \
                nsswitch/winbindd_passdb.o \
-               nsswitch/winbindd_dual.o 
+               nsswitch/winbindd_dual.o \
+               nsswitch/winbindd_async.o
 
 WINBINDD_OBJ = \
                $(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
@@ -689,8 +690,8 @@ NTLM_AUTH_OBJ1 = utils/ntlm_auth.o utils/ntlm_auth_diagnostics.o
 NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
                libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \
                libads/kerberos_verify.o $(SECRETS_OBJ) $(SERVER_MUTEX_OBJ) \
-               libads/authdata.o $(RPC_PARSE_OBJ0) \
-               $(DOSERR_OBJ)
+               libads/authdata.o $(RPC_PARSE_OBJ0) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
+               $(SMBLDAP_OBJ) $(DOSERR_OBJ)
 
 ######################################################################
 # now the rules...
@@ -852,10 +853,6 @@ bin/profiles@EXEEXT@: $(PROFILES_OBJ) @BUILD_POPT@ bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ @SOCKWRAP@
 
-bin/editreg@EXEEXT@: $(EDITREG_OBJ) @BUILD_POPT@ bin/.dummy
-       @echo Linking $@
-       @$(CC) $(FLAGS) -o $@ $(EDITREG_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@
-
 bin/smbspool@EXEEXT@: $(CUPS_OBJ) bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
@@ -1056,6 +1053,11 @@ bin/librpc_spoolss.@SHLIBEXT@: $(RPC_SPOOLSS_OBJ)
        @$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_SPOOLSS_OBJ) -lc \
                @SONAMEFLAG@`basename $@`
 
+bin/librpc_eventlog.@SHLIBEXT@: $(RPC_EVENTLOG_OBJ)
+       @echo "Linking $@"
+       @$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_EVENTLOG_OBJ) -lc \
+               @SONAMEFLAG@`basename $@`
+
 bin/librpc_netdfs.@SHLIBEXT@: $(RPC_DFS_OBJ)
        @echo "Linking $@"
        @$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_DFS_OBJ) -lc \
@@ -1496,7 +1498,8 @@ headers:
        $(MAKE) nsswitch/winbindd_proto.h; \
        $(MAKE) web/swat_proto.h; \
        $(MAKE) client/client_proto.h; \
-       $(MAKE) utils/net_proto.h
+       $(MAKE) utils/ntlm_auth_proto.h; \
+       $(MAKE) utils/net_proto.h;
 
 proto: headers 
 
index 61c420c06b104859a38a3a642c8348492a3f6a2a..e9d40c3b7c9480eea1a631bd89df57b65da1cc7f 100644 (file)
@@ -57,6 +57,27 @@ struct print_job_info
        time_t t;
 };
 
+struct rpc_pipe_client {
+       TALLOC_CTX *mem_ctx;
+
+       struct cli_state *cli;
+
+       int pipe_idx;
+       uint16 fnum;
+
+       int pipe_auth_flags;
+
+       NTLMSSP_STATE *ntlmssp_pipe_state;
+       const char *user_name;
+       const char *domain;
+       struct pwd_info pwd;
+
+       struct netsec_auth_struct auth_info;
+
+       uint16 max_xmit_frag;
+       uint16 max_recv_frag;
+};
+
 struct cli_state {
        int port;
        int fd;
@@ -124,25 +145,19 @@ struct cli_state {
                                              of the pipe we're talking to, 
                                              if any */
 
-       uint16 nt_pipe_fnum[PI_MAX_PIPES]; /* Pipe handle. */
+       struct rpc_pipe_client pipes[PI_MAX_PIPES];
 
        /* Secure pipe parameters */
        int pipe_auth_flags;
 
-       uint16 saved_netlogon_pipe_fnum;   /* The "first" pipe to get
-                                              the session key for the
-                                              schannel. */
-       struct netsec_auth_struct auth_info;
-
-       NTLMSSP_STATE *ntlmssp_pipe_state;
-
+       struct rpc_pipe_client netlogon_pipe;  /* The "first" pipe to get
+                                                 the session key for the
+                                                 schannel. */
        unsigned char sess_key[16];        /* Current session key. */
        DOM_CRED clnt_cred;                /* Client credential. */
        fstring mach_acct;                 /* MYNAME$. */
        fstring srv_name_slash;            /* \\remote server. */
        fstring clnt_name_slash;           /* \\local client. */
-       uint16 max_xmit_frag;
-       uint16 max_recv_frag;
 
        BOOL use_kerberos;
        BOOL fallback_after_kerberos;
index 20b1015285ee266a93cc8bbedfff867b3ad80c5f..7205058ee8758bb7834f68b6baaef4b06a7dc8ef 100644 (file)
@@ -35,6 +35,7 @@
 #define ID_TYPEMASK    0x0f
 
 #define ID_QUERY_ONLY  0x10
+#define ID_CACHE_ONLY   0x20
 
 /* Filled out by IDMAP backends */
 struct idmap_methods {
index 1fabe44e0e74b4b759bac5d107ff0cd16659683f..da4c98fc726bf6c579716c08be4817cce6d4f82a 100644 (file)
@@ -804,7 +804,12 @@ extern int errno;
 #include "tdb/tdb.h"
 #include "tdb/spinlock.h"
 #include "tdb/tdbutil.h"
+
 #include "talloc.h"
+/* And a little extension. Abort on type mismatch */
+#define talloc_get_type_abort(ptr, type) \
+       (type *)talloc_check_name_abort(ptr, #type)
+
 #include "nt_status.h"
 #include "ads.h"
 #include "interfaces.h"
index a87659f49849db84b99306d729f07d7e7a44181b..1039e0d9a7074d31a85461418a9b5c30b3844f44 100644 (file)
@@ -46,6 +46,7 @@
 /* nmbd messages */
 #define MSG_FORCE_ELECTION 1001
 #define MSG_WINS_NEW_ENTRY 1002
+#define MSG_SEND_PACKET    1003
 
 /* printing messages */
 /* #define MSG_PRINTER_NOTIFY  2001*/ /* Obsolete */
 #define MSG_SMB_SAM_REPL     3004
 #define MSG_SMB_UNLOCK       3005
 
+/* winbind messages */
+#define MSG_WINBIND_FINISHED     4001
+#define MSG_WINBIND_FORGET_STATE 4002
+
 /* Flags to classify messages - used in message_send_all() */
 /* Sender will filter by flag. */
 
index 4ac2f43ee00a5424db87d7cd4765d2b19a9fbc69..9ca2d5aa8c9f78108b14edb3b69f8995d3d21ba4 100644 (file)
 #ifndef _RPC_CLIENT_H
 #define _RPC_CLIENT_H
 
-/* macro to expand cookie-cutter code in cli_xxx() */
+/* macro to expand cookie-cutter code in cli_xxx() using rpc_api_pipe_req() */
                   
-#define CLI_DO_RPC( pcli, ctx, pipe_num, opnum, q_in, r_out, q_ps, r_ps, q_io_fn, r_io_fn, default_error) \
+#define CLI_DO_RPC( pcli, ctx, pipe_num, opnum, q_in, r_out, \
+                             q_ps, r_ps, q_io_fn, r_io_fn, default_error ) \
 {      r_out.status = default_error;\
        prs_init( &q_ps, MAX_PDU_FRAG_LEN, ctx, MARSHALL ); \
        prs_init( &r_ps, 0, ctx, UNMARSHALL );\
        prs_mem_free( &r_ps );\
 }
 
+/* macro to expand cookie-cutter code in cli_xxx() using rpc_api_pipe_req_int() */
+
+#define CLI_DO_RPC_EX( pcli, ctx, pipe_num, opnum, q_in, r_out, \
+                             q_ps, r_ps, q_io_fn, r_io_fn, default_error ) \
+{      r_out.status = default_error;\
+       prs_init( &q_ps, MAX_PDU_FRAG_LEN, ctx, MARSHALL ); \
+       prs_init( &r_ps, 0, ctx, UNMARSHALL );\
+       if ( q_io_fn("", &q_in, &q_ps, 0) ) {\
+               if ( rpc_api_pipe_req_int(pcli, opnum, &q_ps, &r_ps) ) {\
+                       if (!r_io_fn("", &r_out, &r_ps, 0)) {\
+                               r_out.status = default_error;\
+                       }\
+               }\
+       }\
+       prs_mem_free( &q_ps );\
+       prs_mem_free( &r_ps );\
+}
+
 #endif /* _RPC_CLIENT_H */
index 00b08af7c39ebda4f3509906d427b29e3f1c206f..297eeb4d03000ae758e2405096a04e4185bc5c52 100644 (file)
@@ -2668,6 +2668,29 @@ void name_to_fqdn(fstring fqdn, const char *name)
        }
 }
 
+/**********************************************************************
+ Extension to talloc_get_type: Abort on type mismatch
+***********************************************************************/
+
+void *talloc_check_name_abort(const void *ptr, const char *name)
+{
+       void *result;
+
+       if (ptr == NULL)
+               return NULL;
+
+       result = talloc_check_name(ptr, name);
+       if (result != NULL)
+               return result;
+
+       DEBUG(0, ("Talloc type mismatch, expected %s, got %s\n",
+                 name, talloc_get_name(ptr)));
+       smb_panic("aborting");
+       /* Keep the compiler happy */
+       return NULL;
+}
+
+
 #ifdef __INSURE__
 
 /*******************************************************************
index 1838da1313d7a315788bc6bd1731e4232dfcccd3..b9b4aff42018a0a40c632606146d61b31765b998 100644 (file)
@@ -342,6 +342,12 @@ BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
        return False;
 }
 
+BOOL sid_compose(DOM_SID *dst, const DOM_SID *domain_sid, uint32 rid)
+{
+       sid_copy(dst, domain_sid);
+       return sid_append_rid(dst, rid);
+}
+
 /*****************************************************************
  Removes the last rid from the end of a sid
 *****************************************************************/  
@@ -630,7 +636,7 @@ DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src)
  Add SID to an array SIDs
 ********************************************************************/
 
-void add_sid_to_array(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+void add_sid_to_array(TALLOC_CTX *mem_ctx, const DOM_SID *sid, 
                      DOM_SID **sids, int *num)
 {
        if (mem_ctx != NULL)
index b13ec1f0dad9920f777bddd7c8957249fa2b0968..f600d1704e06ccf328a22cdc074343254790c6f4 100644 (file)
@@ -2128,3 +2128,69 @@ BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
        *num += 1;
        return True;
 }
+
+/* Append an sprintf'ed string. Double buffer size on demand. Usable without
+ * error checking in between. The indiation that something weird happened is
+ * string==NULL */
+
+void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
+                   size_t *bufsize, const char *fmt, ...)
+{
+       va_list ap;
+       char *newstr;
+       int ret;
+       BOOL increased;
+
+       /* len<0 is an internal marker that something failed */
+       if (*len < 0)
+               goto error;
+
+       if (*string == NULL) {
+               if (*bufsize == 0)
+                       *bufsize = 128;
+
+               if (mem_ctx != NULL)
+                       *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
+               else
+                       *string = SMB_MALLOC_ARRAY(char, *bufsize);
+
+               if (*string == NULL)
+                       goto error;
+       }
+
+       va_start(ap, fmt);
+       ret = vasprintf(&newstr, fmt, ap);
+       va_end(ap);
+
+       if (ret < 0)
+               goto error;
+
+       increased = False;
+
+       while ((*len)+ret >= *bufsize) {
+               increased = True;
+               *bufsize *= 2;
+               if (*bufsize >= (1024*1024*256))
+                       goto error;
+       }
+
+       if (increased) {
+               if (mem_ctx != NULL)
+                       *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
+                                                      *bufsize);
+               else
+                       *string = SMB_REALLOC_ARRAY(*string, char, *bufsize);
+
+               if (*string == NULL)
+                       goto error;
+       }
+
+       StrnCpy((*string)+(*len), newstr, ret);
+       (*len) += ret;
+       free(newstr);
+       return;
+
+ error:
+       *len = -1;
+       *string = NULL;
+}
index 902feb2eeeb280129976d6acd79d026c2c684979..c25f9e4bdeb3335b1028b75836e4fa998e9231bc 100644 (file)
@@ -88,8 +88,7 @@ int kerberos_kinit_password(const char *principal,
                return code;
        }
        
-       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me,
-                                                 CONST_DISCARD(char *, password), 
+       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password, 
                                                 kerb_prompter, 
                                                 NULL, 0, NULL, NULL))) {
                krb5_free_principal(ctx, me);
index ba65c46d16efc0ae63d6f8825d7f0d9e14b896df..819616105edc9d274a76fd26bf0f4fb76d8a6ef9 100644 (file)
  * cli_send_mailslot, send a mailslot for client code ...
  */
 
-int cli_send_mailslot(int dgram_sock, BOOL unique, const char *mailslot, 
-                     char *buf, int len,
-                     const char *srcname, int src_type, 
-                     const char *dstname, int dest_type,
-                     struct in_addr dest_ip, struct in_addr src_ip,
-                     int dest_port, int src_port)
+BOOL cli_send_mailslot(BOOL unique, const char *mailslot,
+                      uint16 priority,
+                      char *buf, int len,
+                      const char *srcname, int src_type, 
+                      const char *dstname, int dest_type,
+                      struct in_addr dest_ip)
 {
-  struct packet_struct p;
-  struct dgram_packet *dgram = &p.packet.dgram;
-  char *ptr, *p2;
-  char tmp[4];
-
-  memset((char *)&p, '\0', sizeof(p));
-
-  /*
-   * Next, build the DGRAM ...
-   */
-
-  /* DIRECT GROUP or UNIQUE datagram. */
-  dgram->header.msg_type = unique ? 0x10 : 0x11; 
-  dgram->header.flags.node_type = M_NODE;
-  dgram->header.flags.first = True;
-  dgram->header.flags.more = False;
-  dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
-  dgram->header.source_ip.s_addr = src_ip.s_addr;
-  dgram->header.source_port = ntohs(src_port);
-  dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
-  dgram->header.packet_offset = 0;
+       struct packet_struct p;
+       struct dgram_packet *dgram = &p.packet.dgram;
+       char *ptr, *p2;
+       char tmp[4];
+       pid_t nmbd_pid;
+
+       if ((nmbd_pid = pidfile_pid("nmbd")) == 0) {
+               DEBUG(3, ("No nmbd found\n"));
+               return False;
+       }
+
+       if (!message_init())
+               return False;
+
+       memset((char *)&p, '\0', sizeof(p));
+
+       /*
+        * Next, build the DGRAM ...
+        */
+
+       /* DIRECT GROUP or UNIQUE datagram. */
+       dgram->header.msg_type = unique ? 0x10 : 0x11; 
+       dgram->header.flags.node_type = M_NODE;
+       dgram->header.flags.first = True;
+       dgram->header.flags.more = False;
+       dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
+               ((unsigned)sys_getpid()%(unsigned)100);
+       /* source ip is filled by nmbd */
+       dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+       dgram->header.packet_offset = 0;
   
-  make_nmb_name(&dgram->source_name,srcname,src_type);
-  make_nmb_name(&dgram->dest_name,dstname,dest_type);
-
-  ptr = &dgram->data[0];
-
-  /* Setup the smb part. */
-  ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
-  memcpy(tmp,ptr,4);
-  set_message(ptr,17,strlen(mailslot) + 1 + len,True);
-  memcpy(ptr,tmp,4);
-
-  SCVAL(ptr,smb_com,SMBtrans);
-  SSVAL(ptr,smb_vwv1,len);
-  SSVAL(ptr,smb_vwv11,len);
-  SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
-  SSVAL(ptr,smb_vwv13,3);
-  SSVAL(ptr,smb_vwv14,1);
-  SSVAL(ptr,smb_vwv15,1);
-  SSVAL(ptr,smb_vwv16,2);
-  p2 = smb_buf(ptr);
-  fstrcpy(p2,mailslot);
-  p2 = skip_string(p2,1);
-
-  memcpy(p2,buf,len);
-  p2 += len;
-
-  dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
-
-  p.ip = dest_ip;
-  p.port = dest_port;
-  p.fd = dgram_sock;
-  p.timestamp = time(NULL);
-  p.packet_type = DGRAM_PACKET;
-
-  DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
-                    nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
-  DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
-
-  return send_packet(&p);
-
+       make_nmb_name(&dgram->source_name,srcname,src_type);
+       make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+       ptr = &dgram->data[0];
+
+       /* Setup the smb part. */
+       ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+       memcpy(tmp,ptr,4);
+       set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+       memcpy(ptr,tmp,4);
+
+       SCVAL(ptr,smb_com,SMBtrans);
+       SSVAL(ptr,smb_vwv1,len);
+       SSVAL(ptr,smb_vwv11,len);
+       SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+       SSVAL(ptr,smb_vwv13,3);
+       SSVAL(ptr,smb_vwv14,1);
+       SSVAL(ptr,smb_vwv15,priority);
+       SSVAL(ptr,smb_vwv16,2);
+       p2 = smb_buf(ptr);
+       fstrcpy(p2,mailslot);
+       p2 = skip_string(p2,1);
+
+       memcpy(p2,buf,len);
+       p2 += len;
+
+       dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+       p.packet_type = DGRAM_PACKET;
+       p.ip = dest_ip;
+       p.timestamp = time(NULL);
+
+       DEBUG(4,("send_mailslot: Sending to mailslot %s from %s ",
+                mailslot, nmb_namestr(&dgram->source_name)));
+       DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name),
+                   inet_ntoa(dest_ip)));
+
+       return message_send_pid(nmbd_pid, MSG_SEND_PACKET, &p, sizeof(p),
+                               False);
 }
 
 /*
  * cli_get_response: Get a response ...
  */
-int cli_get_response(int dgram_sock, BOOL unique, const char *mailslot, char *buf, int bufsiz)
+BOOL cli_get_response(const char *mailslot, char *buf, int bufsiz)
 {
-  struct packet_struct *packet;
-
-  packet = receive_dgram_packet(dgram_sock, 5, mailslot);
-
-  if (packet) { /* We got one, pull what we want out of the SMB data ... */
-
-    struct dgram_packet *dgram = &packet->packet.dgram;
-
-    /*
-     * We should probably parse the SMB, but for now, we will pull what
-     * from fixed, known locations ...
-     */
+       struct packet_struct *p;
 
-    /* Copy the data to buffer, respecting sizes ... */
+       p = receive_unexpected(DGRAM_PACKET, 0, mailslot);
 
-    memcpy(buf, &dgram->data[92], MIN(bufsiz, (dgram->datasize - 92)));
+       if (p == NULL)
+               return False;
 
-  }
-  else 
-    return -1;
-
-  return 0;
+       memcpy(buf, &p->packet.dgram.data[92],
+              MIN(bufsiz, p->packet.dgram.datasize-92));
 
+       return True;
 }
 
 /*
@@ -135,108 +131,43 @@ static char cli_backup_list[1024];
 
 int cli_get_backup_list(const char *myname, const char *send_to_name)
 {
-  pstring outbuf;
-  char *p;
-  struct in_addr sendto_ip, my_ip;
-  int dgram_sock;
-  struct sockaddr_in sock_out;
-  socklen_t name_size;
-
-  if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
-
-    DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
-    return False;
-
-  }
-
-  my_ip.s_addr = inet_addr("0.0.0.0");
-  if (!resolve_name(myname, &my_ip, 0x00)) { /* FIXME: Call others here */
-
-    DEBUG(0, ("Could not resolve name: %s<00>\n", myname));
-
-  }
-
-  if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) {
-
-    DEBUG(4, ("open_sock_out failed ..."));
-    return False;
-
-  }
-
-  /* Make it a broadcast socket ... */
+       pstring outbuf;
+       char *p;
+       struct in_addr sendto_ip;
 
-  set_socket_options(dgram_sock, "SO_BROADCAST");
+       if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
 
-  /* Make it non-blocking??? */
+               DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
+               return False;
 
-  if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) {
+       }
 
-    DEBUG(0, ("Unable to set non blocking on dgram sock\n"));
+       memset(cli_backup_list, '\0', sizeof(cli_backup_list));
+       memset(outbuf, '\0', sizeof(outbuf));
 
-  }
-
-  /* Now, bind a local addr to it ... Try port 138 first ... */
-
-  memset((char *)&sock_out, '\0', sizeof(sock_out));
-  sock_out.sin_addr.s_addr = INADDR_ANY;
-  sock_out.sin_port = htons(138);
-  sock_out.sin_family = AF_INET;
-
-  if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
-
-    /* Try again on any port ... */
-
-    sock_out.sin_port = INADDR_ANY;
-
-    if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
-
-      DEBUG(4, ("failed to bind socket to address ...\n"));
-      return False;
-       
-    }
-
-  }
+       p = outbuf;
 
-  /* Now, figure out what socket name we were bound to. We want the port */
+       SCVAL(p, 0, ANN_GetBackupListReq);
+       p++;
 
-  name_size = sizeof(sock_out);
+       SCVAL(p, 0, 1); /* Count pointer ... */
+       p++;
 
-  getsockname(dgram_sock, (struct sockaddr *)&sock_out, &name_size);
+       SIVAL(p, 0, 1); /* The sender's token ... */
+       p += 4;
 
-  DEBUG(5, ("Socket bound to IP:%s, port: %d\n", inet_ntoa(sock_out.sin_addr), ntohs(sock_out.sin_port)));
+       cli_send_mailslot(True, "\\MAILSLOT\\BROWSE", 1, outbuf, 
+                         PTR_DIFF(p, outbuf), myname, 0, send_to_name, 
+                         0x1d, sendto_ip);
 
-  /* Now, build the request */
+       /* We should check the error and return if we got one */
 
-  memset(cli_backup_list, '\0', sizeof(cli_backup_list));
-  memset(outbuf, '\0', sizeof(outbuf));
+       /* Now, get the response ... */
 
-  p = outbuf;
+       cli_get_response("\\MAILSLOT\\BROWSE",
+                        cli_backup_list, sizeof(cli_backup_list));
 
-  SCVAL(p, 0, ANN_GetBackupListReq);
-  p++;
-
-  SCVAL(p, 0, 1); /* Count pointer ... */
-  p++;
-
-  SIVAL(p, 0, 1); /* The sender's token ... */
-  p += 4;
-
-  cli_send_mailslot(dgram_sock, True, "\\MAILSLOT\\BROWSE", outbuf, 
-                   PTR_DIFF(p, outbuf), myname, 0, send_to_name, 
-                   0x1d, sendto_ip, my_ip, 138, sock_out.sin_port);
-
-  /* We should check the error and return if we got one */
-
-  /* Now, get the response ... */
-
-  cli_get_response(dgram_sock, True, "\\MAILSLOT\\BROWSE", cli_backup_list, sizeof(cli_backup_list));
-
-  /* Should check the response here ... FIXME */
-
-  close(dgram_sock);
-
-  return True;
+       return True;
 
 }
 
index e787650c2f5388f35849348bc0874bef56d14bb5..2977099f7d768c7926a30d1def52685434df2cd2 100644 (file)
@@ -22,8 +22,6 @@
 
 #include "includes.h"
 
-extern int smb_read_error;
-
 /****************************************************************************
  Change the timeout (in milliseconds).
 ****************************************************************************/
@@ -83,6 +81,7 @@ static BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
 
 BOOL cli_receive_smb(struct cli_state *cli)
 {
+       extern int smb_read_error;
        BOOL ret;
 
        /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
@@ -321,9 +320,9 @@ struct cli_state *cli_initialise(struct cli_state *cli)
        cli_null_set_signing(cli);
 
        for (i=0; i<PI_MAX_PIPES; i++)
-               cli->nt_pipe_fnum[i] = 0;
+               cli->pipes[i].fnum = 0;
 
-       cli->saved_netlogon_pipe_fnum = 0;
+       cli->netlogon_pipe.fnum = 0;
 
        cli->initialised = 1;
        cli->allocated = alloced_cli;
@@ -353,14 +352,14 @@ void cli_nt_session_close(struct cli_state *cli)
 {
        int i;
 
-       if (cli->ntlmssp_pipe_state) {
-               ntlmssp_end(&cli->ntlmssp_pipe_state);
-       }
-
        for (i=0; i<PI_MAX_PIPES; i++) {
-               if (cli->nt_pipe_fnum[i] != 0)
-                       cli_close(cli, cli->nt_pipe_fnum[i]);
-               cli->nt_pipe_fnum[i] = 0;
+               if (cli->pipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+                       ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state);
+               }
+
+               if (cli->pipes[i].fnum != 0)
+                       cli_close(cli, cli->pipes[i].fnum);
+               cli->pipes[i].fnum = 0;
        }
        cli->pipe_idx = -1;
 }
@@ -371,9 +370,9 @@ close the NETLOGON session holding the session key for NETSEC
 
 void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
 {
-       if (cli->saved_netlogon_pipe_fnum != 0) {
-               cli_close(cli, cli->saved_netlogon_pipe_fnum);
-               cli->saved_netlogon_pipe_fnum = 0;
+       if (cli->netlogon_pipe.fnum != 0) {
+               cli_close(cli, cli->netlogon_pipe.fnum);
+               cli->netlogon_pipe.fnum = 0;
        }
 }
 
@@ -408,8 +407,8 @@ void cli_close_connection(struct cli_state *cli)
        data_blob_free(&cli->secblob);
        data_blob_free(&cli->user_session_key);
 
-       if (cli->ntlmssp_pipe_state
-               ntlmssp_end(&cli->ntlmssp_pipe_state);
+       if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP
+               ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state);
 
        if (cli->mem_ctx) {
                talloc_destroy(cli->mem_ctx);
index 27da63ccdad53659cd7752e53c49288462da3275..75afe5195ed8e7f842ffb4dc3f4e43adcd6d257b 100644 (file)
@@ -505,7 +505,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
         */
        if (cli_is_dos_error(cli)) {
                 cli_dos_error(cli, &eclass, &ecode);
-               if (cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
+               if (cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
                        cli_signing_trans_stop(cli);
                        return(False);
                }
@@ -639,7 +639,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
                }
                if (cli_is_dos_error(cli)) {
                         cli_dos_error(cli, &eclass, &ecode);
-                       if(cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
+                       if(cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
                                cli_signing_trans_stop(cli);
                                return(False);
                        }
index 532b578f3c79b8937775c49a6da42394f643d8a3..af93bf5197cad6a1f76b0c6a35c7cdb7384fe1c3 100644 (file)
@@ -323,6 +323,56 @@ static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t
        }
 }
 
+static void msg_nmbd_send_packet(int msg_type, pid_t src,
+                                void *buf, size_t len)
+{
+       struct packet_struct *p = (struct packet_struct *)buf;
+       struct subnet_record *subrec;
+       struct in_addr *local_ip;
+
+       DEBUG(10, ("Received send_packet from %d\n", src));
+
+       if (len != sizeof(struct packet_struct)) {
+               DEBUG(2, ("Discarding invalid packet length from %d\n", src));
+               return;
+       }
+
+       if ((p->packet_type != NMB_PACKET) &&
+           (p->packet_type != DGRAM_PACKET)) {
+               DEBUG(2, ("Discarding invalid packet type from %d: %d\n",
+                         src, p->packet_type));
+               return;
+       }
+
+       local_ip = iface_ip(p->ip);
+
+       if (local_ip == NULL) {
+               DEBUG(2, ("Could not find ip for packet from %d\n", src));
+               return;
+       }
+
+       subrec = FIRST_SUBNET;
+
+       p->fd = (p->packet_type == NMB_PACKET) ?
+               subrec->nmb_sock : subrec->dgram_sock;
+
+       for (subrec = FIRST_SUBNET; subrec != NULL;
+            subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+               if (ip_equal(*local_ip, subrec->myip)) {
+                       p->fd = (p->packet_type == NMB_PACKET) ?
+                               subrec->nmb_sock : subrec->dgram_sock;
+                       break;
+               }
+       }
+
+       if (p->packet_type == DGRAM_PACKET) {
+               p->port = 138;
+               p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
+               p->packet.dgram.header.source_port = 138;
+       }
+
+       send_packet(p);
+}
 
 /**************************************************************************** **
  The main select loop.
@@ -720,6 +770,7 @@ static BOOL open_sockets(BOOL isdaemon, int port)
        message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
        message_register(MSG_SHUTDOWN, nmbd_terminate);
        message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
+       message_register(MSG_SEND_PACKET, msg_nmbd_send_packet);
 
        DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
 
index 5005f72457a02f4be056c0e4c229bfb352aa3c9f..32ac4319a0382bd65f0b10ed1f886d0c45de0f24 100644 (file)
@@ -257,6 +257,32 @@ BOOL winbind_allocate_rid(uint32 *rid)
        return True;
 }
 
+BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Make request */
+
+       result = winbindd_request(WINBINDD_ALLOCATE_RID_AND_GID, &request,
+                                 &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       /* Copy out result */
+       *rid = response.data.rid_and_gid.rid;
+       *gid = response.data.rid_and_gid.gid;
+
+       return True;
+}
+
 /* Fetch the list of groups a user is a member of from winbindd.  This is
    used by winbind_getgroups. */
 
index baa35d7cfbee8de7e0c0109fb4db3496bafb68e9..8407bb1e3a2fae4b5d8d51a2802a3677cff2842b 100644 (file)
@@ -167,6 +167,32 @@ static BOOL wbinfo_get_usersids(char *user_sid)
        return True;
 }
 
+static BOOL wbinfo_get_userdomgroups(const char *user_sid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+
+       ZERO_STRUCT(response);
+
+       /* Send request */
+       fstrcpy(request.data.sid, user_sid);
+
+       result = winbindd_request(WINBINDD_GETUSERDOMGROUPS, &request,
+                                 &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       if (response.data.num_entries != 0)
+               printf("%s", (char *)response.extra_data);
+       
+       SAFE_FREE(response.extra_data);
+
+       return True;
+}
+
+
 /* Convert NetBIOS name to IP */
 
 static BOOL wbinfo_wins_byname(char *name)
@@ -224,7 +250,6 @@ static BOOL wbinfo_wins_byip(char *ip)
 static BOOL wbinfo_list_domains(void)
 {
        struct winbindd_response response;
-       fstring name;
 
        ZERO_STRUCT(response);
 
@@ -238,9 +263,19 @@ static BOOL wbinfo_list_domains(void)
 
        if (response.extra_data) {
                const char *extra_data = (char *)response.extra_data;
-
-               while(next_token(&extra_data, name, ",", sizeof(fstring)))
+               fstring name;
+               char *p;
+
+               while(next_token(&extra_data, name, "\n", sizeof(fstring))) {
+                       p = strchr(name, '\\');
+                       if (p == 0) {
+                               d_printf("Got invalid response: %s\n",
+                                        extra_data);
+                               return False;
+                       }
+                       *p = 0;
                        d_printf("%s\n", name);
+               }
 
                SAFE_FREE(response.extra_data);
        }
@@ -316,6 +351,32 @@ static BOOL wbinfo_domain_info(const char *domain_name)
        return True;
 }
 
+/* Get a foreign DC's name */
+static BOOL wbinfo_getdcname(const char *domain_name)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.domain_name, domain_name);
+
+       /* Send request */
+
+       if (winbindd_request(WINBINDD_GETDCNAME, &request, &response) !=
+           NSS_STATUS_SUCCESS) {
+               d_printf("Could not get dc name for %s\n", domain_name);
+               return False;
+       }
+
+       /* Display response */
+
+       d_printf("%s\n", response.data.dc_name);
+
+       return True;
+}
+
 /* Check trust account password */
 
 static BOOL wbinfo_check_secret(void)
@@ -889,6 +950,8 @@ enum {
        OPT_GET_AUTH_USER,
        OPT_DOMAIN_NAME,
        OPT_SEQUENCE,
+       OPT_GETDCNAME,
+       OPT_USERDOMGROUPS,
        OPT_USERSIDS
 };
 
@@ -924,9 +987,13 @@ int main(int argc, char **argv)
                { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
                { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
                { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
+               { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
+                 OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
                { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
                { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
                { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
+               { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
+                 "Get a DC name for a foreign domain", "domainname" },
                { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
                { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
                { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
@@ -1079,6 +1146,13 @@ int main(int argc, char **argv)
                                goto done;
                        }
                        break;
+               case OPT_USERDOMGROUPS:
+                       if (!wbinfo_get_userdomgroups(string_arg)) {
+                               d_printf("Could not get user's domain groups "
+                                        "for user SID %s\n", string_arg);
+                               goto done;
+                       }
+                       break;
                case 'a': {
                                BOOL got_error = False;
 
@@ -1116,6 +1190,9 @@ int main(int argc, char **argv)
                case OPT_GET_AUTH_USER:
                        wbinfo_get_auth_user();
                        break;
+               case OPT_GETDCNAME:
+                       wbinfo_getdcname(string_arg);
+                       break;
                /* generic configuration options */
                case OPT_DOMAIN_NAME:
                        break;
index 81dbf327fcc9c739457f6f7596eb3107220385b0..f083dfe44ac6bcd6a75afeadb89bc08c0ea21dd0 100644 (file)
@@ -6,6 +6,7 @@
    Copyright (C) by Tim Potter 2000-2002
    Copyright (C) Andrew Tridgell 2002
    Copyright (C) Jelmer Vernooij 2003
+   Copyright (C) Volker Lendecke 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
@@ -27,6 +28,7 @@
 
 BOOL opt_nocache = False;
 BOOL opt_dual_daemon = True;
+static BOOL interactive = False;
 
 extern BOOL override_logfile;
 
@@ -131,7 +133,6 @@ static void winbindd_status(void)
 static void print_winbindd_status(void)
 {
        winbindd_status();
-       winbindd_cm_status();
 }
 
 /* Flush client cache */
@@ -163,6 +164,17 @@ static void terminate(void)
        pstr_sprintf(path, "%s/%s", 
                 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
        unlink(path);
+
+#if 0
+       if (interactive) {
+               TALLOC_CTX *mem_ctx = talloc_init("end_description");
+               char *description = talloc_describe_all(mem_ctx);
+
+               DEBUG(3, ("tallocs left:\n%s\n", description));
+               talloc_destroy(mem_ctx);
+       }
+#endif
+
        exit(0);
 }
 
@@ -190,14 +202,11 @@ static void sighup_handler(int signum)
        sys_select_signal();
 }
 
+static BOOL do_sigchld;
+
 static void sigchld_handler(int signum)
 {
-       pid_t pid;
-       int status;
-
-       while ((pid = wait(&status)) != -1 || errno == EINTR) {
-               continue; /* Reap children */
-       }
+       do_sigchld = True;
        sys_select_signal();
 }
 
@@ -215,13 +224,7 @@ static void msg_shutdown(int msg_type, pid_t src, void *buf, size_t len)
        terminate();
 }
 
-struct dispatch_table {
-       enum winbindd_cmd cmd;
-       enum winbindd_result (*fn)(struct winbindd_cli_state *state);
-       const char *winbindd_cmd_name;
-};
-
-static struct dispatch_table dispatch_table[] = {
+static struct winbindd_dispatch_table dispatch_table[] = {
        
        /* User functions */
 
@@ -234,6 +237,8 @@ static struct dispatch_table dispatch_table[] = {
 
        { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
        { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
+       { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
+         "GETUSERDOMGROUPS" },
 
        /* Group functions */
 
@@ -247,14 +252,15 @@ static struct dispatch_table dispatch_table[] = {
        /* PAM auth functions */
 
        { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
-       { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
+       { WINBINDD_PAM_AUTH_CRAP, winbindd_crap_auth, "AUTH_CRAP" },
        { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
 
        /* Enumeration functions */
 
        { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
        { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
-       { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
+       { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
+         "LIST_TRUSTDOM" },
        { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
 
        /* SID related functions */
@@ -266,20 +272,25 @@ static struct dispatch_table dispatch_table[] = {
 
        { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
        { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
-       { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
        { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
+       { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
        { WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
+       { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid,
+         "ALLOCATE_RID_AND_GID" },
 
        /* Miscellaneous */
 
        { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
        { WINBINDD_PING, winbindd_ping, "PING" },
        { WINBINDD_INFO, winbindd_info, "INFO" },
-       { WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
+       { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
+         "INTERFACE_VERSION" },
        { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
        { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
        { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
-       { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" },
+       { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
+         "WINBINDD_PRIV_PIPE_DIR" },
+       { WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
 
        /* WINS functions */
 
@@ -293,7 +304,7 @@ static struct dispatch_table dispatch_table[] = {
 
 static void process_request(struct winbindd_cli_state *state)
 {
-       struct dispatch_table *table = dispatch_table;
+       struct winbindd_dispatch_table *table = dispatch_table;
 
        /* Free response data - we may be interrupted and receive another
           command before being able to send this data off. */
@@ -302,26 +313,255 @@ static void process_request(struct winbindd_cli_state *state)
 
        ZERO_STRUCT(state->response);
 
-       state->response.result = WINBINDD_ERROR;
+       state->response.result = WINBINDD_PENDING;
        state->response.length = sizeof(struct winbindd_response);
 
+       state->mem_ctx = talloc_init("winbind request");
+       if (state->mem_ctx == NULL)
+               return;
+
        /* Process command */
 
        for (table = dispatch_table; table->fn; table++) {
                if (state->request.cmd == table->cmd) {
-                       DEBUG(10,("process_request: request fn %s\n", table->winbindd_cmd_name ));
+                       DEBUG(10,("process_request: request fn %s\n",
+                                 table->winbindd_cmd_name ));
                        state->response.result = table->fn(state);
                        break;
                }
        }
 
-       if (!table->fn)
-               DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd ));
+       if (!table->fn) {
+               DEBUG(10,("process_request: unknown request fn number %d\n",
+                         (int)state->request.cmd ));
+               state->response.result = WINBINDD_ERROR;
+       }
+}
+
+/*
+ * A list of file descriptors being monitored by select in the main processing
+ * loop. fd_event->handler is called whenever the socket is readable/writable.
+ */
+
+static struct fd_event *fd_events = NULL;
+
+void add_fd_event(struct fd_event *ev)
+{
+       struct fd_event *match;
+
+       /* only add unique fd_event structs */
+
+       for (match=fd_events; match; match=match->next ) {
+#ifdef DEVELOPER
+               SMB_ASSERT( match != ev );
+#else
+               if ( match == ev )
+                       return;
+#endif
+       }
+
+       DLIST_ADD(fd_events, ev);
+}
+
+void remove_fd_event(struct fd_event *ev)
+{
+       DLIST_REMOVE(fd_events, ev);
+}
+
+/*
+ * Handler for fd_events to complete a read/write request, set up by
+ * setup_async_read/setup_async_write.
+ */
+
+static void rw_callback(struct fd_event *event, int flags)
+{
+       size_t todo;
+       ssize_t done = 0;
+
+       todo = event->length - event->done;
+
+       if (event->flags & EVENT_FD_WRITE) {
+               SMB_ASSERT(flags == EVENT_FD_WRITE);
+               done = sys_write(event->fd,
+                                &((char *)event->data)[event->done],
+                                todo);
+
+               if (done <= 0) {
+                       event->flags = 0;
+                       event->finished(event->private, False);
+                       return;
+               }
+       }
+
+       if (event->flags & EVENT_FD_READ) {
+               SMB_ASSERT(flags == EVENT_FD_READ);
+               done = sys_read(event->fd, &((char *)event->data)[event->done],
+                               todo);
 
-       /* In case extra data pointer is NULL */
+               if (done <= 0) {
+                       event->flags = 0;
+                       event->finished(event->private, False);
+                       return;
+               }
+       }
+
+       event->done += done;
+
+       if (event->done == event->length) {
+               event->flags = 0;
+               event->finished(event->private, True);
+       }
+}
+
+/*
+ * Request an async read/write on a fd_event structure. (*finished) is called
+ * when the request is completed or an error had occurred.
+ */
+
+void setup_async_read(struct fd_event *event, void *data, size_t length,
+                     void (*finished)(void *private, BOOL success),
+                     void *private)
+{
+       SMB_ASSERT(event->flags == 0);
+       event->data = data;
+       event->length = length;
+       event->done = 0;
+       event->handler = rw_callback;
+       event->finished = finished;
+       event->private = private;
+       event->flags = EVENT_FD_READ;
+}
+
+void setup_async_write(struct fd_event *event, void *data, size_t length,
+                      void (*finished)(void *private, BOOL success),
+                      void *private)
+{
+       SMB_ASSERT(event->flags == 0);
+       event->data = data;
+       event->length = length;
+       event->done = 0;
+       event->handler = rw_callback;
+       event->finished = finished;
+       event->private = private;
+       event->flags = EVENT_FD_WRITE;
+}
+
+/*
+ * This is the main event loop of winbind requests. It goes through a
+ * state-machine of 3 read/write requests, 4 if you have extra data to send.
+ *
+ * An idle winbind client has a read request of 4 bytes outstanding,
+ * finalizing function is request_len_recv, checking the length. request_recv
+ * then processes the packet. The processing function then at some point has
+ * to call request_finished which schedules sending the response.
+ */
+
+static void request_len_recv(void *private, BOOL success);
+static void request_recv(void *private, BOOL success);
+void request_finished(struct winbindd_cli_state *state);
+void request_finished_cont(void *private, BOOL success);
+static void response_main_sent(void *private, BOOL success);
+static void response_extra_sent(void *private, BOOL success);
+
+static void response_extra_sent(void *private, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (state->mem_ctx != NULL) {
+               talloc_destroy(state->mem_ctx);
+               state->mem_ctx = NULL;
+       }
+
+       if (!success) {
+               state->finished = True;
+               return;
+       }
+
+       SAFE_FREE(state->response.extra_data);
+
+       setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+                        request_len_recv, state);
+}
+
+static void response_main_sent(void *private, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               state->finished = True;
+               return;
+       }
+
+       if (state->response.length == sizeof(state->response)) {
+               if (state->mem_ctx != NULL) {
+                       talloc_destroy(state->mem_ctx);
+                       state->mem_ctx = NULL;
+               }
+
+               setup_async_read(&state->fd_event, &state->request,
+                                sizeof(uint32), request_len_recv, state);
+               return;
+       }
+
+       setup_async_write(&state->fd_event, state->response.extra_data,
+                         state->response.length - sizeof(state->response),
+                         response_extra_sent, state);
+}
+
+void request_finished(struct winbindd_cli_state *state)
+{
+       setup_async_write(&state->fd_event, &state->response,
+                         sizeof(state->response), response_main_sent, state);
+}
+
+void request_finished_cont(void *private, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success)
+               state->response.result = WINBINDD_ERROR;
+       request_finished(state);
+}
+
+static void request_recv(void *private, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               state->finished = True;
+               return;
+       }
+
+       process_request(state);
+
+       if (state->response.result != WINBINDD_PENDING)
+               request_finished(state);
+}
+
+static void request_len_recv(void *private, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               state->finished = True;
+               return;
+       }
+
+       if (*(uint32 *)(&state->request) != sizeof(state->request)) {
+               DEBUG(0,("process_loop: Invalid request size received: %d\n",
+                        *(uint32 *)(&state->request)));
+               state->finished = True;
+               return;
+       }
 
-       if (!state->response.extra_data)
-               state->response.length = sizeof(struct winbindd_response);
+       setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1,
+                        sizeof(state->request) - sizeof(uint32),
+                        request_recv, state);
 }
 
 /* Process a new connection by adding it to the client connection list */
@@ -348,16 +588,22 @@ static void new_connection(int listen_sock, BOOL privileged)
        
        /* Create new connection structure */
        
-       if ((state = SMB_MALLOC_P(struct winbindd_cli_state)) == NULL)
+       if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL)
                return;
        
-       ZERO_STRUCTP(state);
        state->sock = sock;
 
        state->last_access = time(NULL);        
 
        state->privileged = privileged;
 
+       state->fd_event.fd = state->sock;
+       state->fd_event.flags = 0;
+       add_fd_event(&state->fd_event);
+
+       setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
+                        request_len_recv, state);
+
        /* Add to connection list */
        
        winbindd_add_client(state);
@@ -384,11 +630,18 @@ static void remove_client(struct winbindd_cli_state *state)
                   client was killed unexpectedly */
 
                SAFE_FREE(state->response.extra_data);
+
+               if (state->mem_ctx != NULL) {
+                       talloc_destroy(state->mem_ctx);
+                       state->mem_ctx = NULL;
+               }
+
+               remove_fd_event(&state->fd_event);
                
                /* Remove from list and free */
                
                winbindd_remove_client(state);
-               SAFE_FREE(state);
+               talloc_free(state);
        }
 }
 
@@ -403,7 +656,8 @@ static BOOL remove_idle_client(void)
 
        for (state = winbindd_client_list(); state; state = state->next) {
                if (state->read_buf_len == 0 && state->write_buf_len == 0 &&
-                               !state->getpwent_state && !state->getgrent_state) {
+                   state->response.result != WINBINDD_PENDING &&
+                   !state->getpwent_state && !state->getgrent_state) {
                        nidle++;
                        if (!last_access || state->last_access < last_access) {
                                last_access = state->last_access;
@@ -432,7 +686,7 @@ void winbind_process_packet(struct winbindd_cli_state *state)
        state->request.null_term = '\0';
 
        state->pid = state->request.pid;
-       
+
        process_request(state);
 
        /* Update client state */
@@ -446,124 +700,6 @@ void winbind_process_packet(struct winbindd_cli_state *state)
        }
 }
 
-/* Read some data from a client connection */
-
-void winbind_client_read(struct winbindd_cli_state *state)
-{
-       int n;
-    
-       /* Read data */
-
-       n = sys_read(state->sock, state->read_buf_len + 
-                (char *)&state->request, 
-                sizeof(state->request) - state->read_buf_len);
-       
-       DEBUG(10,("client_read: read %d bytes. Need %ld more for a full request.\n", n, (unsigned long)(sizeof(state->request) - n - state->read_buf_len) ));
-
-       /* Read failed, kill client */
-       
-       if (n == -1 || n == 0) {
-               DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
-                        state->sock, (unsigned long)state->pid, 
-                        (n == -1) ? strerror(errno) : "EOF"));
-               
-               state->finished = True;
-               return;
-       }
-       
-       /* Update client state */
-       
-       state->read_buf_len += n;
-       state->last_access = time(NULL);
-}
-
-/* Write some data to a client connection */
-
-static void client_write(struct winbindd_cli_state *state)
-{
-       char *data;
-       int num_written;
-       
-       /* Write some data */
-       /*
-        * The fancy calculation of data below allows us to handle the 
-        * case where write (sys_write) does not write all the data we 
-        * gave it. In that case, we will come back through here again
-        * because of the loop above us, and we want to pick up where
-        * we left off.
-        */
-       
-       if (!state->write_extra_data) {
-
-               /* Write response structure */
-               
-               data = (char *)&state->response + sizeof(state->response) - 
-                       state->write_buf_len;
-
-       } else {
-
-               /* Write extra data */
-               
-               data = (char *)state->response.extra_data + 
-                       state->response.length - 
-                       sizeof(struct winbindd_response) - 
-                       state->write_buf_len;
-       }
-       
-       num_written = sys_write(state->sock, data, state->write_buf_len);
-       
-       DEBUG(10,("client_write: wrote %d bytes.\n", num_written ));
-
-       /* Write failed, kill cilent */
-       
-       if (num_written == -1 || num_written == 0) {
-               
-               DEBUG(3,("write failed on sock %d, pid %lu: %s\n",
-                        state->sock, (unsigned long)state->pid, 
-                        (num_written == -1) ? strerror(errno) : "EOF"));
-               
-               state->finished = True;
-
-               SAFE_FREE(state->response.extra_data);
-
-               return;
-       }
-       
-       /* Update client state */
-       
-       state->write_buf_len -= num_written;
-       state->last_access = time(NULL);
-
-       /* Have we written all data? */
-       
-       if (state->write_buf_len == 0) {
-               
-               /* Take care of extra data */
-               
-               if (state->write_extra_data) {
-
-                       SAFE_FREE(state->response.extra_data);
-
-                       state->write_extra_data = False;
-
-                       DEBUG(10,("client_write: client_write: complete response written.\n"));
-
-               } else if (state->response.length > 
-                          sizeof(struct winbindd_response)) {
-                       
-                       /* Start writing extra data */
-
-                       state->write_buf_len = 
-                               state->response.length -
-                               sizeof(struct winbindd_response);
-                       
-                       DEBUG(10,("client_write: need to write %d extra data bytes.\n", (int)state->write_buf_len));
-
-                       state->write_extra_data = True;
-               }
-       }
-}
-
 /* Process incoming clients on listen_sock.  We use a tricky non-blocking,
    non-forking, non-threaded model which allows us to handle many
    simultaneous connections while remaining impervious to many denial of
@@ -571,211 +707,182 @@ static void client_write(struct winbindd_cli_state *state)
 
 static void process_loop(void)
 {
-       /* We'll be doing this a lot */
+       struct winbindd_cli_state *state;
+       struct fd_event *ev;
+       fd_set r_fds, w_fds;
+       int maxfd, listen_sock, listen_priv_sock, selret;
+       struct timeval timeout;
 
-       while (1) {
-               struct winbindd_cli_state *state;
-               fd_set r_fds, w_fds;
-               int maxfd, listen_sock, listen_priv_sock, selret;
-               struct timeval timeout;
+       /* We'll be doing this a lot */
 
-       again:
-               /* Handle messages */
+       /* Handle messages */
 
-               message_dispatch();
+       message_dispatch();
 
-               /* refresh the trusted domain cache */
+       /* refresh the trusted domain cache */
                   
-               rescan_trusted_domains();
-
-               /* Free up temporary memory */
+       rescan_trusted_domains();
 
-               lp_talloc_free();
-               main_loop_talloc_free();
+       /* Free up temporary memory */
 
-               /* Initialise fd lists for select() */
+       lp_talloc_free();
+       main_loop_talloc_free();
 
-               listen_sock = open_winbindd_socket();
-               listen_priv_sock = open_winbindd_priv_socket();
-
-               if (listen_sock == -1 || listen_priv_sock == -1) {
-                       perror("open_winbind_socket");
-                       exit(1);
-               }
+       /* Initialise fd lists for select() */
 
-               maxfd = MAX(listen_sock, listen_priv_sock);
+       listen_sock = open_winbindd_socket();
+       listen_priv_sock = open_winbindd_priv_socket();
 
-               FD_ZERO(&r_fds);
-               FD_ZERO(&w_fds);
-               FD_SET(listen_sock, &r_fds);
-               FD_SET(listen_priv_sock, &r_fds);
-
-               timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
-               timeout.tv_usec = 0;
-
-               if (opt_dual_daemon) {
-                       maxfd = dual_select_setup(&w_fds, maxfd);
-               }
-
-               /* Set up client readers and writers */
+       if (listen_sock == -1 || listen_priv_sock == -1) {
+               perror("open_winbind_socket");
+               exit(1);
+       }
 
-               state = winbindd_client_list();
+       maxfd = MAX(listen_sock, listen_priv_sock);
 
-               while (state) {
+       FD_ZERO(&r_fds);
+       FD_ZERO(&w_fds);
+       FD_SET(listen_sock, &r_fds);
+       FD_SET(listen_priv_sock, &r_fds);
 
-                       /* Dispose of client connection if it is marked as 
-                          finished */ 
+       timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+       timeout.tv_usec = 0;
 
-                       if (state->finished) {
-                               struct winbindd_cli_state *next = state->next;
+       if (opt_dual_daemon) {
+               maxfd = dual_select_setup(&w_fds, maxfd);
+       }
 
-                               remove_client(state);
-                               state = next;
-                               continue;
-                       }
+       /* Set up client readers and writers */
 
-                       /* Select requires we know the highest fd used */
+       state = winbindd_client_list();
 
-                       if (state->sock > maxfd)
-                               maxfd = state->sock;
+       while (state) {
 
-                       /* Add fd for reading */
+               struct winbindd_cli_state *next = state->next;
 
-                       if (state->read_buf_len != sizeof(state->request))
-                               FD_SET(state->sock, &r_fds);
+               /* Dispose of client connection if it is marked as 
+                  finished */ 
 
-                       /* Add fd for writing */
+               if (state->finished)
+                       remove_client(state);
 
-                       if (state->write_buf_len)
-                               FD_SET(state->sock, &w_fds);
+               state = next;
+       }
 
-                       state = state->next;
+       for (ev = fd_events; ev; ev = ev->next) {
+               if (ev->flags & EVENT_FD_READ) {
+                       FD_SET(ev->fd, &r_fds);
+                       maxfd = MAX(ev->fd, maxfd);
+               }
+               if (ev->flags & EVENT_FD_WRITE) {
+                       FD_SET(ev->fd, &w_fds);
+                       maxfd = MAX(ev->fd, maxfd);
                }
+       }
 
-               /* Call select */
+       /* Call select */
         
-               selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+       selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
 
-               if (selret == 0)
-                       continue;
+       if (selret == 0)
+               goto no_fds_ready;
 
-               if ((selret == -1 && errno != EINTR) || selret == 0) {
+       if ((selret == -1 && errno != EINTR) || selret == 0) {
 
-                       /* Select error, something is badly wrong */
+               /* Select error, something is badly wrong */
 
-                       perror("select");
-                       exit(1);
-               }
+               perror("select");
+               exit(1);
+       }
 
-               /* Create a new connection if listen_sock readable */
+       /* Create a new connection if listen_sock readable */
 
-               if (selret > 0) {
+       if (opt_dual_daemon) {
+               dual_select(&w_fds);
+       }
 
-                       if (opt_dual_daemon) {
-                               dual_select(&w_fds);
-                       }
+       ev = fd_events;
+       while (ev != NULL) {
+               struct fd_event *next = ev->next;
+               int flags = 0;
+               if (FD_ISSET(ev->fd, &r_fds))
+                       flags |= EVENT_FD_READ;
+               if (FD_ISSET(ev->fd, &w_fds))
+                       flags |= EVENT_FD_WRITE;
+               if (flags)
+                       ev->handler(ev, flags);
+               ev = next;
+       }
 
-                       if (FD_ISSET(listen_sock, &r_fds)) {
-                               while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
-                                       DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
-                                               WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
-                                       if (!remove_idle_client()) {
-                                               DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
-                                                       WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
-                                               break;
-                                       }
-                               }
-                               /* new, non-privileged connection */
-                               new_connection(listen_sock, False);
+       if (FD_ISSET(listen_sock, &r_fds)) {
+               while (winbindd_num_clients() >
+                      WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+                       DEBUG(5,("winbindd: Exceeding %d client "
+                                "connections, removing idle "
+                                "connection.\n",
+                                WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                       if (!remove_idle_client()) {
+                               DEBUG(0,("winbindd: Exceeding %d "
+                                        "client connections, no idle "
+                                        "connection found\n",
+                                        WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                               break;
                        }
+               }
+               /* new, non-privileged connection */
+               new_connection(listen_sock, False);
+       }
             
-                       if (FD_ISSET(listen_priv_sock, &r_fds)) {
-                               while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
-                                       DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
-                                               WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
-                                       if (!remove_idle_client()) {
-                                               DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
-                                                       WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
-                                               break;
-                                       }
-                               }
-                               /* new, privileged connection */
-                               new_connection(listen_priv_sock, True);
-                       }
-            
-                       /* Process activity on client connections */
-            
-                       for (state = winbindd_client_list(); state; 
-                            state = state->next) {
-                
-                               /* Data available for writing */
-                
-                               if (FD_ISSET(state->sock, &w_fds))
-                                       client_write(state);
-                       }
-                
-                       for (state = winbindd_client_list(); state; 
-                            state = state->next) {
-                
-                               /* Data available for reading */
-                
-                               if (FD_ISSET(state->sock, &r_fds)) {
-                    
-                                       /* Read data */
-                    
-                                       winbind_client_read(state);
-
-                                       /* 
-                                        * If we have the start of a
-                                        * packet, then check the
-                                        * length field to make sure
-                                        * the client's not talking
-                                        * Mock Swedish.
-                                        */
-
-                                       if (state->read_buf_len >= sizeof(uint32)
-                                           && *(uint32 *) &state->request != sizeof(state->request)) {
-                                               DEBUG(0,("process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld\n",
-                                                               (unsigned long)state->request.pid, *(uint32 *) &state->request, (unsigned long)sizeof(state->request)));
-                                               DEBUGADD(0, ("This usually means that you are running old wbinfo, pam_winbind or libnss_winbind clients\n"));
-
-                                               remove_client(state);
-                                               break;
-                                       }
-
-                                       /* A request packet might be 
-                                          complete */
-                    
-                                       if (state->read_buf_len == 
-                                           sizeof(state->request)) {
-                                               winbind_process_packet(state);
-                                               winbindd_demote_client(state);
-                                               goto again;
-                                       }
-                               }
+       if (FD_ISSET(listen_priv_sock, &r_fds)) {
+               while (winbindd_num_clients() >
+                      WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+                       DEBUG(5,("winbindd: Exceeding %d client "
+                                "connections, removing idle "
+                                "connection.\n",
+                                WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                       if (!remove_idle_client()) {
+                               DEBUG(0,("winbindd: Exceeding %d "
+                                        "client connections, no idle "
+                                        "connection found\n",
+                                        WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                               break;
                        }
                }
+               /* new, privileged connection */
+               new_connection(listen_priv_sock, True);
+       }
+
+ no_fds_ready:
 
 #if 0
-               winbindd_check_cache_size(time(NULL));
+       winbindd_check_cache_size(time(NULL));
 #endif
 
-               /* Check signal handling things */
+       /* Check signal handling things */
 
-               if (do_sigterm)
-                       terminate();
+       if (do_sigterm)
+               terminate();
 
-               if (do_sighup) {
+       if (do_sighup) {
 
-                       DEBUG(3, ("got SIGHUP\n"));
+               DEBUG(3, ("got SIGHUP\n"));
 
-                       msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
-                       do_sighup = False;
-               }
+               msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
+               do_sighup = False;
+       }
+
+       if (do_sigusr2) {
+               print_winbindd_status();
+               do_sigusr2 = False;
+       }
 
-               if (do_sigusr2) {
-                       print_winbindd_status();
-                       do_sigusr2 = False;
+       if (do_sigchld) {
+               pid_t pid;
+
+               do_sigchld = False;
+
+               while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+                       winbind_child_died(pid);
                }
        }
 }
@@ -787,7 +894,6 @@ struct winbindd_state server_state;   /* Server state information */
 int main(int argc, char **argv)
 {
        pstring logfile;
-       static BOOL interactive = False;
        static BOOL Fork = True;
        static BOOL log_stdout = False;
        struct poptOption long_options[] = {
@@ -886,7 +992,7 @@ int main(int argc, char **argv)
        if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
             (!idmap_init(lp_idmap_backend())) ) {
                DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
-               idmap_proxyonly();
+               idmap_set_proxyonly();
        }
 
        /* Unblock all signals we are interested in as they may have been
@@ -948,9 +1054,12 @@ int main(int argc, char **argv)
        
        init_domain_list();
 
+       init_idmap_child();
+
        /* Loop waiting for requests */
 
-       process_loop();
+       while (1)
+               process_loop();
 
        trustdom_cache_shutdown();
 
index aed0c00c9d9eddc4b1eb6d3007fdc74158667962..c8d2ebf686ccf31d5490d2d98f4bb5d6ad0561b2 100644 (file)
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
-/* Client state structure */
+/* bits for fd_event.flags */
+#define EVENT_FD_READ 1
+#define EVENT_FD_WRITE 2
+
+struct fd_event {
+       struct fd_event *next, *prev;
+       int fd;
+       int flags; /* see EVENT_FD_* flags */
+       void (*handler)(struct fd_event *fde, int flags);
+       void *data;
+       size_t length, done;
+       void (*finished)(void *private, BOOL success);
+       void *private;
+};
 
 struct winbindd_cli_state {
        struct winbindd_cli_state *prev, *next;   /* Linked list pointers */
        int sock;                                 /* Open socket from client */
+       struct fd_event fd_event;
        pid_t pid;                                /* pid of client */
        int read_buf_len, write_buf_len;          /* Indexes in request/response */
        BOOL finished;                            /* Can delete from list */
@@ -44,10 +58,13 @@ struct winbindd_cli_state {
        time_t last_access;                       /* Time of last access (read or write) */
        BOOL privileged;                           /* Is the client 'privileged' */
 
+       TALLOC_CTX *mem_ctx;                      /* memory per request */
        struct winbindd_request request;          /* Request from client */
        struct winbindd_response response;        /* Respose to client */
-       BOOL getpwent_initialized;                /* Has getpwent_state been initialized? */
-       BOOL getgrent_initialized;                /* Has getgrent_state been initialized? */
+       BOOL getpwent_initialized;                /* Has getpwent_state been
+                                                  * initialized? */
+       BOOL getgrent_initialized;                /* Has getgrent_state been
+                                                  * initialized? */
        struct getent_state *getpwent_state;      /* State for getpwent() */
        struct getent_state *getgrent_state;      /* State for getgrent() */
 };
@@ -81,15 +98,56 @@ struct winbindd_state {
        gid_t gid_low, gid_high;               /* Range of gids to allocate */
 };
 
+struct winbindd_dispatch_table {
+       enum winbindd_cmd cmd;
+       enum winbindd_result (*fn)(struct winbindd_cli_state *state);
+       const char *winbindd_cmd_name;
+};
+
 extern struct winbindd_state server_state;  /* Server information */
 
 typedef struct {
        char *acct_name;
        char *full_name;
-       DOM_SID *user_sid;                    /* NT user and primary group SIDs */
-       DOM_SID *group_sid;
+       DOM_SID user_sid;                    /* NT user and primary group SIDs */
+       DOM_SID group_sid;
 } WINBIND_USERINFO;
 
+/* Our connection to the DC */
+
+struct winbindd_cm_conn {
+       struct cli_state *cli;
+
+       struct rpc_pipe_client *samr_pipe;
+       POLICY_HND sam_connect_handle, sam_domain_handle;
+
+       struct rpc_pipe_client *lsa_pipe;
+       POLICY_HND lsa_policy;
+
+       /* Auth2 pipe is the pipe used to setup the netlogon schannel key
+        * using rpccli_net_auth2. It needs to be kept open. */
+
+       struct rpc_pipe_client *netlogon_auth2_pipe;
+       unsigned char sess_key[16];        /* Current session key. */
+       DOM_CRED clnt_cred;                /* Client NETLOGON credential. */
+       struct rpc_pipe_client *netlogon_pipe;
+};
+
+struct winbindd_async_request;
+
+/* Async child */
+
+struct winbindd_child {
+       struct winbindd_child *next, *prev;
+
+       pid_t pid;
+       struct winbindd_domain *domain;
+       pstring logfilename;
+
+       struct fd_event event;
+       struct winbindd_async_request *requests;
+};
+
 /* Structures to hold per domain information */
 
 struct winbindd_domain {
@@ -123,6 +181,14 @@ struct winbindd_domain {
        uint32 sequence_number;
        NTSTATUS last_status;
 
+       /* The smb connection */
+
+       struct winbindd_cm_conn conn;
+
+       /* The child pid we're talking to */
+
+       struct winbindd_child child;
+
        /* Linked list info */
 
        struct winbindd_domain *prev, *next;
@@ -181,13 +247,14 @@ struct winbindd_methods {
        NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
                                      TALLOC_CTX *mem_ctx,
                                      const DOM_SID *user_sid,
-                                     uint32 *num_groups, DOM_SID ***user_gids);
+                                     uint32 *num_groups, DOM_SID **user_gids);
 
        /* Lookup all aliases that the sids delivered are member of. This is
         * to implement 'domain local groups' correctly */
        NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain,
                                       TALLOC_CTX *mem_ctx,
-                                      uint32 num_sids, DOM_SID **sids,
+                                      uint32 num_sids,
+                                      const DOM_SID *sids,
                                       uint32 *num_aliases,
                                       uint32 **alias_rids);
 
@@ -196,7 +263,7 @@ struct winbindd_methods {
                                    TALLOC_CTX *mem_ctx,
                                    const DOM_SID *group_sid,
                                    uint32 *num_names, 
-                                   DOM_SID ***sid_mem, char ***names, 
+                                   DOM_SID **sid_mem, char ***names, 
                                    uint32 **name_types);
 
        /* return the current global sequence number */
index 5f23e755d4c6148b81ddda59e5bdc83314007ce6..0f4dee4f4adb4731c758ca021a04137d25b9621f 100644 (file)
@@ -27,8 +27,6 @@
 
 #ifdef HAVE_ADS
 
-extern struct winbindd_methods msrpc_methods, cache_methods;
-
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
@@ -78,6 +76,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
 
        status = ads_connect(ads);
        if (!ADS_ERR_OK(status) || !ads->config.realm) {
+               extern struct winbindd_methods msrpc_methods, cache_methods;
                DEBUG(1,("ads_connect for domain %s failed: %s\n", 
                         domain->name, ads_errstr(status)));
                ads_destroy(&ads);
@@ -157,9 +156,6 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
 
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
                char *name, *gecos;
-               DOM_SID sid;
-               DOM_SID *sid2;
-               DOM_SID *group_sid;
                uint32 group;
                uint32 atype;
 
@@ -171,7 +167,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
 
                name = ads_pull_username(ads, mem_ctx, msg);
                gecos = ads_pull_string(ads, mem_ctx, msg, "name");
-               if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+               if (!ads_pull_sid(ads, msg, "objectSid",
+                                 &(*info)[i].user_sid)) {
                        DEBUG(1,("No sid for %s !?\n", name));
                        continue;
                }
@@ -180,20 +177,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                        continue;
                }
 
-               sid2 = TALLOC_P(mem_ctx, DOM_SID);
-               if (!sid2) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
-
-               sid_copy(sid2, &sid);
-
-               group_sid = rid_to_talloced_sid(domain, mem_ctx, group);
-
                (*info)[i].acct_name = name;
                (*info)[i].full_name = gecos;
-               (*info)[i].user_sid = sid2;
-               (*info)[i].group_sid = group_sid;
+               sid_compose(&(*info)[i].group_sid, &domain->sid, group);
                i++;
        }
 
@@ -386,8 +372,6 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        char *sidstr;
        uint32 group_rid;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       DOM_SID *sid2;
-       fstring sid_string;
 
        DEBUG(3,("ads: query_user\n"));
 
@@ -404,13 +388,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        free(ldap_exp);
        free(sidstr);
        if (!ADS_ERR_OK(rc) || !msg) {
-               DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc)));
+               DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
+                        sid_string_static(sid), ads_errstr(rc)));
                goto done;
        }
 
        count = ads_count_replies(ads, msg);
        if (count != 1) {
-               DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid)));
+               DEBUG(1,("query_user(sid=%s): Not found\n",
+                        sid_string_static(sid)));
                goto done;
        }
 
@@ -418,20 +404,13 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
 
        if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
-               DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid)));
-               goto done;
-       }
-       
-       sid2 = TALLOC_P(mem_ctx, DOM_SID);
-       if (!sid2) {
-               status = NT_STATUS_NO_MEMORY;
+               DEBUG(1,("No primary group for %s !?\n",
+                        sid_string_static(sid)));
                goto done;
        }
-       sid_copy(sid2, sid);
-       
-       info->user_sid = sid2;
 
-       info->group_sid = rid_to_talloced_sid(domain, mem_ctx, group_rid);
+       sid_copy(&info->user_sid, sid);
+       sid_compose(&info->group_sid, &domain->sid, group_rid);
 
        status = NT_STATUS_OK;
 
@@ -449,7 +428,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
                                      TALLOC_CTX *mem_ctx,
                                      const char *user_dn, 
                                      DOM_SID *primary_group,
-                                     uint32 *num_groups, DOM_SID ***user_gids)
+                                     uint32 *num_groups, DOM_SID **user_sids)
 {
        ADS_STATUS rc;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -502,34 +481,24 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
                goto done;
        }
        
-       (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
-       (*user_gids)[0] = primary_group;
-       
-       *num_groups = 1;
-       
-       for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+       *user_sids = NULL;
+       *num_groups = 0;
+
+       add_sid_to_array(mem_ctx, primary_group, user_sids, num_groups);
+
+       for (msg = ads_first_entry(ads, res); msg;
+            msg = ads_next_entry(ads, msg)) {
                DOM_SID group_sid;
                
                if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
                        DEBUG(1,("No sid for this group ?!?\n"));
                        continue;
                }
-               
-               if (sid_equal(&group_sid, primary_group)) continue;
-               
-               (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
-               if (!(*user_gids)[*num_groups]) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
 
-               sid_copy((*user_gids)[*num_groups], &group_sid);
-
-               (*num_groups)++;
-                       
+               add_sid_to_array(mem_ctx, &group_sid, user_sids, num_groups);
        }
 
-       status = NT_STATUS_OK;
+       status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 
        DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn));
 done:
@@ -543,7 +512,7 @@ done:
 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
                                  const DOM_SID *sid, 
-                                 uint32 *num_groups, DOM_SID ***user_gids)
+                                 uint32 *num_groups, DOM_SID **user_sids)
 {
        ADS_STRUCT *ads = NULL;
        const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
@@ -553,7 +522,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        char *user_dn;
        DOM_SID *sids;
        int i;
-       DOM_SID *primary_group;
+       DOM_SID primary_group;
        uint32 primary_group_rid;
        fstring sid_string;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -596,7 +565,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                goto done;
        }
 
-       primary_group = rid_to_talloced_sid(domain, mem_ctx, primary_group_rid);
+       sid_copy(&primary_group, &domain->sid);
+       sid_append_rid(&primary_group, primary_group_rid);
 
        count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
 
@@ -607,30 +577,23 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
           unless we are talking to a buggy Win2k server */
        if (count == 0) {
                return lookup_usergroups_alt(domain, mem_ctx, user_dn, 
-                                            primary_group,
-                                            num_groups, user_gids);
+                                            &primary_group,
+                                            num_groups, user_sids);
        }
 
-       (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
-       (*user_gids)[0] = primary_group;
-       
-       *num_groups = 1;
+       *user_sids = NULL;
+       *num_groups = 0;
+
+       add_sid_to_array(mem_ctx, &primary_group, user_sids, num_groups);
        
-       for (i=0;i<count;i++) {
-               if (sid_equal(&sids[i], primary_group)) continue;
-               
-               (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
-               if (!(*user_gids)[*num_groups]) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
+       for (i=0;i<count;i++)
+               add_sid_to_array_unique(mem_ctx, &sids[i],
+                                       user_sids, num_groups);
 
-               sid_copy((*user_gids)[*num_groups], &sids[i]);
-               (*num_groups)++;
-       }
+       status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 
-       status = NT_STATUS_OK;
-       DEBUG(3,("ads lookup_usergroups for sid=%s\n", sid_to_string(sid_string, sid)));
+       DEBUG(3,("ads lookup_usergroups for sid=%s\n",
+                sid_to_string(sid_string, sid)));
 done:
        return status;
 }
@@ -641,7 +604,7 @@ done:
 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                const DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID ***sid_mem, char ***names, 
+                               DOM_SID **sid_mem, char ***names, 
                                uint32 **name_types)
 {
        ADS_STATUS rc;
@@ -652,8 +615,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        char *sidstr;
        char **members;
-       int i;
-       size_t num_members;
+       int i, num_members;
        fstring sid_string;
        BOOL more_values;
        const char **attrs;
@@ -753,7 +715,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
           the problem is that the members are in the form of distinguised names
        */
 
-       (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, num_members);
+       (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
        (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
        (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
 
@@ -765,12 +727,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) {
                    (*names)[*num_names] = name;
                    (*name_types)[*num_names] = name_type;
-                   (*sid_mem)[*num_names] = TALLOC_P(mem_ctx, DOM_SID);
-                   if (!(*sid_mem)[*num_names]) {
-                           status = NT_STATUS_NO_MEMORY;
-                           goto done;
-                   }
-                   sid_copy((*sid_mem)[*num_names], &sid);
+                   sid_copy(&(*sid_mem)[*num_names], &sid);
                    (*num_names)++;
                }
        }       
@@ -827,9 +784,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        struct ds_domain_trust  *domains = NULL;
        int                     count = 0;
        int                     i;
-       struct cli_state        *cli = NULL;
                                /* i think we only need our forest and downlevel trusted domains */
        uint32                  flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
+       struct rpc_pipe_client *cli;
 
        DEBUG(3,("ads: trusted_domains\n"));
 
@@ -837,16 +794,27 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        *alt_names   = NULL;
        *names       = NULL;
        *dom_sids    = NULL;
-               
-       if ( !NT_STATUS_IS_OK(result = cm_fresh_connection(domain, PI_NETLOGON, &cli)) ) {
-               DEBUG(5, ("trusted_domains: Could not open a connection to %s for PIPE_NETLOGON (%s)\n", 
+
+       {
+               unsigned char *session_key;
+               DOM_CRED *creds;
+
+               result = cm_connect_netlogon(domain, mem_ctx, &cli,
+                                            &session_key, &creds);
+       }
+
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(5, ("trusted_domains: Could not open a connection to %s "
+                         "for PIPE_NETLOGON (%s)\n", 
                          domain->name, nt_errstr(result)));
                return NT_STATUS_UNSUCCESSFUL;
        }
        
        if ( NT_STATUS_IS_OK(result) )
-               result = cli_ds_enum_domain_trusts( cli, mem_ctx, cli->desthost, 
-                                                   flags, &domains, (unsigned int *)&count );
+               result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
+                                                     cli->cli->desthost, 
+                                                     flags, &domains,
+                                                     (unsigned int *)&count);
        
        if ( NT_STATUS_IS_OK(result) && count) {
        
@@ -854,20 +822,17 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
 
                if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
                        DEBUG(0, ("trusted_domains: out of memory\n"));
-                       result = NT_STATUS_NO_MEMORY;
-                       goto done;
+                       return NT_STATUS_NO_MEMORY;
                }
 
                if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
                        DEBUG(0, ("trusted_domains: out of memory\n"));
-                       result = NT_STATUS_NO_MEMORY;
-                       goto done;
+                       return NT_STATUS_NO_MEMORY;
                }
 
                if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
                        DEBUG(0, ("trusted_domains: out of memory\n"));
-                       result = NT_STATUS_NO_MEMORY;
-                       goto done;
+                       return NT_STATUS_NO_MEMORY;
                }
 
                /* Copy across names and sids */
@@ -882,13 +847,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                *num_domains = count;   
        }
 
-done:
-
-       /* remove connection;  This is a special case to the \NETLOGON pipe */
-       
-       if ( cli )
-               cli_shutdown( cli );
-
        return result;
 }
 
diff --git a/source/nsswitch/winbindd_async.c b/source/nsswitch/winbindd_async.c
new file mode 100644 (file)
index 0000000..9ac2aca
--- /dev/null
@@ -0,0 +1,1403 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Async helpers for blocking functions
+
+   Copyright (C) Volker Lendecke 2005
+   
+   The helpers always consist of three functions: 
+
+   * A request setup function that takes the necessary parameters together
+     with a continuation function that is to be called upon completion
+
+   * A private continuation function that is internal only. This is to be
+     called by the lower-level functions in do_async(). Its only task is to
+     properly call the continuation function named above.
+
+   * A worker function that is called inside the appropriate child process.
+
+   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 "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+struct do_async_state {
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       void (*cont)(TALLOC_CTX *mem_ctx,
+                    BOOL success,
+                    struct winbindd_response *response,
+                    void *c, void *private);
+       void *c, *private;
+};
+
+static void do_async_recv(void *private, BOOL success)
+{
+       struct do_async_state *state =
+               talloc_get_type_abort(private, struct do_async_state);
+
+       state->cont(state->mem_ctx, success, &state->response,
+                   state->c, state->private);
+}
+
+static void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+                    const struct winbindd_request *request,
+                    void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
+                                 struct winbindd_response *response,
+                                 void *c, void *private),
+                    void *c, void *private)
+{
+       struct do_async_state *state;
+
+       state = TALLOC_P(mem_ctx, struct do_async_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               cont(mem_ctx, False, NULL, c, private);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->request = *request;
+       state->request.length = sizeof(state->request);
+       state->cont = cont;
+       state->c = c;
+       state->private = private;
+
+       async_request(mem_ctx, child, &state->request,
+                     &state->response, do_async_recv, state);
+}
+
+static void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+                           const struct winbindd_request *request,
+                           void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
+                                        struct winbindd_response *response,
+                                        void *c, void *private),
+                           void *c, void *private)
+{
+       struct do_async_state *state;
+
+       state = TALLOC_P(mem_ctx, struct do_async_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               cont(mem_ctx, False, NULL, c, private);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->request = *request;
+       state->request.length = sizeof(state->request);
+       state->cont = cont;
+       state->c = c;
+       state->private = private;
+
+       async_domain_request(mem_ctx, domain, &state->request,
+                            &state->response, do_async_recv, state);
+}
+
+static void idmap_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                                  struct winbindd_response *response,
+                                  void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger idmap_set_mapping\n"));
+               cont(private, False);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("idmap_set_mapping returned an error\n"));
+               cont(private, False);
+               return;
+       }
+
+       cont(private, True);
+}
+
+void idmap_set_mapping_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+                            unid_t id, int id_type,
+                            void (*cont)(void *private, BOOL success),
+                            void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_IDMAPSET;
+       if (id_type == ID_USERID)
+               request.data.dual_idmapset.uid = id.uid;
+       else
+               request.data.dual_idmapset.gid = id.gid;
+       request.data.dual_idmapset.type = id_type;
+       sid_to_string(request.data.dual_idmapset.sid, sid);
+
+       do_async(mem_ctx, idmap_child(), &request, idmap_set_mapping_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_idmapset(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
+{
+       DOM_SID sid;
+       unid_t id;
+       NTSTATUS result;
+
+       DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
+
+       if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid))
+               return WINBINDD_ERROR;
+
+       if (state->request.data.dual_idmapset.type == ID_USERID)
+               id.uid = state->request.data.dual_idmapset.uid;
+       else
+               id.gid = state->request.data.dual_idmapset.gid;
+
+       result = idmap_set_mapping(&sid, id,
+                                  state->request.data.dual_idmapset.type);
+       return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                              struct winbindd_response *response,
+                              void *c, void *private);
+
+void idmap_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
+                        void (*cont)(void *private, BOOL success, uid_t uid),
+                        void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_SID2UID;
+       sid_to_string(request.data.dual_sid2id.sid, sid);
+       request.data.dual_sid2id.alloc = alloc;
+       do_async(mem_ctx, idmap_child(), &request, idmap_sid2uid_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
+                                          struct winbindd_cli_state *state)
+{
+       DOM_SID sid;
+       NTSTATUS result;
+
+       DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
+                 state->request.data.dual_sid2id.sid));
+
+       if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.dual_sid2id.sid));
+               return WINBINDD_ERROR;
+       }
+
+       /* Find uid for this sid and return it, possibly ask the slow remote
+        * idmap */
+
+       result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
+                                 state->request.data.dual_sid2id.alloc ?
+                                 0 : ID_QUERY_ONLY);
+
+       return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                              struct winbindd_response *response,
+                              void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, uid_t uid) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger sid2uid\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("sid2uid returned an error\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       cont(private, True, response->data.uid);
+}
+                        
+static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private);
+
+void winbindd_uid2name_async(TALLOC_CTX *mem_ctx, uid_t uid,
+                            void (*cont)(void *private, BOOL success,
+                                         const char *name),
+                            void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_UID2NAME;
+       request.data.uid = uid;
+       do_async(mem_ctx, idmap_child(), &request, uid2name_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_uid2name(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
+{
+       struct passwd *pw;
+
+       DEBUG(3, ("[%5lu]: uid2name %lu\n", (unsigned long)state->pid, 
+                 (unsigned long)state->request.data.uid));
+
+       pw = getpwuid(state->request.data.uid);
+       if (pw == NULL) {
+               DEBUG(5, ("User %lu not found\n",
+                         (unsigned long)state->request.data.uid));
+               return WINBINDD_ERROR;
+       }
+
+       fstrcpy(state->response.data.name.name, pw->pw_name);
+       return WINBINDD_OK;
+}
+
+static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, const char *name) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger uid2name\n"));
+               cont(private, False, NULL);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("uid2name returned an error\n"));
+               cont(private, False, NULL);
+               return;
+       }
+
+       cont(private, True, response->data.name.name);
+}
+
+static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private);
+
+static void winbindd_name2uid_async(TALLOC_CTX *mem_ctx, const char *name,
+                                   void (*cont)(void *private, BOOL success,
+                                                uid_t uid),
+                                   void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_NAME2UID;
+       fstrcpy(request.data.username, name);
+       do_async(mem_ctx, idmap_child(), &request, name2uid_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_name2uid(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
+{
+       struct passwd *pw;
+
+       /* Ensure null termination */
+       state->request.data.username
+               [sizeof(state->request.data.username)-1] = '\0';
+
+       DEBUG(3, ("[%5lu]: name2uid %s\n", (unsigned long)state->pid, 
+                 state->request.data.username));
+
+       pw = getpwnam(state->request.data.username);
+       if (pw == NULL) {
+               return WINBINDD_ERROR;
+       }
+
+       state->response.data.uid = pw->pw_uid;
+       return WINBINDD_OK;
+}
+
+static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, uid_t uid) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger name2uid\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("name2uid returned an error\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       cont(private, True, response->data.uid);
+}
+
+static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                              struct winbindd_response *response,
+                              void *c, void *private);
+
+void idmap_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
+                        void (*cont)(void *private, BOOL success, gid_t gid),
+                        void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_SID2GID;
+       sid_to_string(request.data.dual_sid2id.sid, sid);
+       request.data.dual_sid2id.alloc = alloc;
+       do_async(mem_ctx, idmap_child(), &request, idmap_sid2gid_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
+                                          struct winbindd_cli_state *state)
+{
+       DOM_SID sid;
+       NTSTATUS result;
+
+       DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
+                 state->request.data.dual_sid2id.sid));
+
+       if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.dual_sid2id.sid));
+               return WINBINDD_ERROR;
+       }
+
+       /* Find gid for this sid and return it, possibly ask the slow remote
+        * idmap */
+
+       result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
+                                 state->request.data.dual_sid2id.alloc ?
+                                 0 : ID_QUERY_ONLY);
+
+       return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                              struct winbindd_response *response,
+                              void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, gid_t gid) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger sid2gid\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("sid2gid returned an error\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       cont(private, True, response->data.gid);
+}
+                        
+static void gid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, const char *name) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger gid2name\n"));
+               cont(private, False, NULL);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("gid2name returned an error\n"));
+               cont(private, False, NULL);
+               return;
+       }
+
+       cont(private, True, response->data.name.name);
+}
+
+void winbindd_gid2name_async(TALLOC_CTX *mem_ctx, gid_t gid,
+                            void (*cont)(void *private, BOOL success,
+                                         const char *name),
+                            void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_GID2NAME;
+       request.data.gid = gid;
+       do_async(mem_ctx, idmap_child(), &request, gid2name_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_gid2name(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
+{
+       struct group *gr;
+
+       DEBUG(3, ("[%5lu]: gid2name %lu\n", (unsigned long)state->pid, 
+                 (unsigned long)state->request.data.gid));
+
+       gr = getgrgid(state->request.data.gid);
+       if (gr == NULL)
+               return WINBINDD_ERROR;
+
+       fstrcpy(state->response.data.name.name, gr->gr_name);
+       return WINBINDD_OK;
+}
+
+static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private);
+
+static void winbindd_name2gid_async(TALLOC_CTX *mem_ctx, const char *name,
+                                   void (*cont)(void *private, BOOL success,
+                                                gid_t gid),
+                                   void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_NAME2GID;
+       fstrcpy(request.data.groupname, name);
+       do_async(mem_ctx, idmap_child(), &request, name2gid_recv,
+                cont, private);
+}
+
+enum winbindd_result winbindd_dual_name2gid(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
+{
+       struct group *gr;
+
+       /* Ensure null termination */
+       state->request.data.groupname
+               [sizeof(state->request.data.groupname)-1] = '\0';
+
+       DEBUG(3, ("[%5lu]: name2gid %s\n", (unsigned long)state->pid, 
+                 state->request.data.groupname));
+
+       gr = getgrnam(state->request.data.groupname);
+       if (gr == NULL) {
+               return WINBINDD_ERROR;
+       }
+
+       state->response.data.gid = gr->gr_gid;
+       return WINBINDD_OK;
+}
+
+static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                         struct winbindd_response *response,
+                         void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, gid_t gid) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger name2gid\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("name2gid returned an error\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       cont(private, True, response->data.gid);
+}
+
+
+static void lookupsid_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                          struct winbindd_response *response,
+                          void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, const char *dom_name,
+                    const char *name, enum SID_NAME_USE type) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger lookupsid\n"));
+               cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("lookupsid returned an error\n"));
+               cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       cont(private, True, response->data.name.dom_name,
+            response->data.name.name, response->data.name.type);
+}
+
+void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+                             void (*cont)(void *private, BOOL success,
+                                          const char *dom_name,
+                                          const char *name,
+                                          enum SID_NAME_USE type),
+                             void *private)
+{
+       struct winbindd_domain *domain;
+       struct winbindd_request request;
+
+       domain = find_lookup_domain_from_sid(sid);
+       if (domain == NULL) {
+               DEBUG(5, ("Could not find domain for sid %s\n",
+                         sid_string_static(sid)));
+               cont(private, False, NULL, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_LOOKUPSID;
+       fstrcpy(request.data.sid, sid_string_static(sid));
+
+       do_async_domain(mem_ctx, domain, &request, lookupsid_recv,
+                       cont, private);
+}
+
+enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
+                                            struct winbindd_cli_state *state)
+{
+       enum SID_NAME_USE type;
+       DOM_SID sid;
+       fstring name;
+       fstring dom_name;
+
+       /* Ensure null termination */
+       state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+       DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, 
+                 state->request.data.sid));
+
+       /* Lookup sid from PDC using lsa_lookup_sids() */
+
+       if (!string_to_sid(&sid, state->request.data.sid)) {
+               DEBUG(5, ("%s not a SID\n", state->request.data.sid));
+               return WINBINDD_ERROR;
+       }
+
+       /* Lookup the sid */
+
+       if (!winbindd_lookup_name_by_sid(state->mem_ctx, &sid, dom_name, name,
+                                        &type)) {
+               return WINBINDD_ERROR;
+       }
+
+       fstrcpy(state->response.data.name.dom_name, dom_name);
+       fstrcpy(state->response.data.name.name, name);
+       state->response.data.name.type = type;
+
+       return WINBINDD_OK;
+}
+
+static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                           struct winbindd_response *response,
+                           void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, const DOM_SID *sid,
+                    enum SID_NAME_USE type) = c;
+       DOM_SID sid;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger lookup_name\n"));
+               cont(private, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("lookup_name returned an error\n"));
+               cont(private, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       if (!string_to_sid(&sid, response->data.sid.sid)) {
+               DEBUG(0, ("Could not convert string %s to sid\n",
+                         response->data.sid.sid));
+               cont(private, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       cont(private, True, &sid, response->data.sid.type);
+}
+
+void winbindd_lookupname_async(TALLOC_CTX *mem_ctx, const char *dom_name,
+                              const char *name,
+                              void (*cont)(void *private, BOOL success,
+                                           const DOM_SID *sid,
+                                           enum SID_NAME_USE type),
+                              void *private)
+{
+       struct winbindd_request request;
+       struct winbindd_domain *domain;
+
+       domain = find_lookup_domain_from_name(dom_name);
+
+       if (domain == NULL) {
+               DEBUG(5, ("Could not find domain for name %s\n", dom_name));
+               cont(private, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_LOOKUPNAME;
+       fstrcpy(request.data.name.dom_name, dom_name);
+       fstrcpy(request.data.name.name, name);
+
+       do_async_domain(mem_ctx, domain, &request, lookupname_recv,
+                       cont, private);
+}
+
+enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
+                                             struct winbindd_cli_state *state)
+{
+       enum SID_NAME_USE type;
+       char *name_domain, *name_user;
+       DOM_SID sid;
+       char *p;
+
+       /* Ensure null termination */
+       state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
+
+       /* Ensure null termination */
+       state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0';
+
+       /* cope with the name being a fully qualified name */
+       p = strstr(state->request.data.name.name, lp_winbind_separator());
+       if (p) {
+               *p = 0;
+               name_domain = state->request.data.name.name;
+               name_user = p+1;
+       } else {
+               name_domain = state->request.data.name.dom_name;
+               name_user = state->request.data.name.name;
+       }
+
+       DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
+                 name_domain, lp_winbind_separator(), name_user));
+
+       /* Lookup name from PDC using lsa_lookup_names() */
+       if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, name_domain,
+                                        name_user, &sid, &type)) {
+               return WINBINDD_ERROR;
+       }
+
+       sid_to_string(state->response.data.sid.sid, &sid);
+       state->response.data.sid.type = type;
+
+       return WINBINDD_OK;
+}
+
+static BOOL print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
+                         int num_sids, char **result)
+{
+       int i;
+       size_t buflen = 0;
+       ssize_t len = 0;
+
+       *result = NULL;
+       for (i=0; i<num_sids; i++) {
+               sprintf_append(mem_ctx, result, &len, &buflen,
+                              "%s\n", sid_string_static(&sids[i]));
+       }
+
+       if ((num_sids != 0) && (*result == NULL)) {
+               return False;
+       }
+
+       return True;
+}
+
+static BOOL parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
+                         DOM_SID **sids, int *num_sids)
+{
+       char *p, *q;
+
+       p = sidstr;
+       if (p == NULL)
+               return True;
+
+       while (p[0] != '\0') {
+               DOM_SID sid;
+               q = strchr(p, '\n');
+               if (q == NULL) {
+                       DEBUG(0, ("Got invalid sidstr: %s\n", p));
+                       return False;
+               }
+               *q = '\0';
+               q += 1;
+               if (!string_to_sid(&sid, p)) {
+                       DEBUG(0, ("Could not parse sid %s\n", p));
+                       return False;
+               }
+               add_sid_to_array(mem_ctx, &sid, sids, num_sids);
+               p = q;
+       }
+       return True;
+}
+
+static void getsidaliases_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                              struct winbindd_response *response,
+                              void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ,
+                    DOM_SID *aliases, int num_aliases) = c;
+       char *aliases_str;
+       DOM_SID *sids = NULL;
+       int num_sids = 0;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger getsidaliases\n"));
+               cont(private, success, NULL, 0);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               DEBUG(5, ("getsidaliases returned an error\n"));
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       aliases_str = response->extra_data;
+
+       if (aliases_str == NULL) {
+               DEBUG(10, ("getsidaliases return 0 SIDs\n"));
+               cont(private, True, NULL, 0);
+               return;
+       }
+
+       if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
+               DEBUG(0, ("Could not parse sids\n"));
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       SAFE_FREE(response->extra_data);
+
+       cont(private, True, sids, num_sids);
+}
+
+void winbindd_getsidaliases_async(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 const DOM_SID *sids, int num_sids,
+                                 void (*cont)(void *private,
+                                              BOOL success,
+                                              const DOM_SID *aliases,
+                                              int num_aliases),
+                                 void *private)
+{
+       struct winbindd_request request;
+       char *sidstr = NULL;
+       char *keystr;
+
+       if (num_sids == 0) {
+               cont(private, True, NULL, 0);
+               return;
+       }
+
+       if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr)) {
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       keystr = cache_store_request_data(mem_ctx, sidstr);
+       if (keystr == NULL) {
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_GETSIDALIASES;
+       fstrcpy(request.domain_name, domain->name);
+       fstrcpy(request.data.dual_sidaliases.cache_key, keystr);
+
+       do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
+                       cont, private);
+}
+
+enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
+                                                struct winbindd_cli_state *state)
+{
+       DOM_SID *sids = NULL;
+       int num_sids = 0;
+       char *key = state->request.data.dual_sidaliases.cache_key;
+       char *sidstr;
+       int i, num_aliases;
+       uint32 *alias_rids;
+       NTSTATUS result;
+
+       DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
+
+       /* Ensure null termination */
+        state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+        state->request.data.dual_sidaliases.cache_key
+               [sizeof(state->request.data.dual_sidaliases.cache_key)-1]='\0';
+
+       sidstr = cache_retrieve_request_data(state->mem_ctx, key);
+       if (sidstr == NULL)
+               sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
+
+       DEBUG(10, ("Sidlist: %s\n", sidstr));
+
+       if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
+               DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
+               return WINBINDD_ERROR;
+       }
+
+       num_aliases = 0;
+       alias_rids = NULL;
+
+       result = domain->methods->lookup_useraliases(domain,
+                                                    state->mem_ctx,
+                                                    num_sids, sids,
+                                                    &num_aliases,
+                                                    &alias_rids);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(3, ("Could not lookup_useraliases: %s\n",
+                         nt_errstr(result)));
+               return WINBINDD_ERROR;
+       }
+
+       num_sids = 0;
+       sids = NULL;
+
+       DEBUG(10, ("Got %d aliases\n", num_aliases));
+
+       for (i=0; i<num_aliases; i++) {
+               DOM_SID sid;
+               DEBUGADD(10, (" rid %d\n", alias_rids[i]));
+               sid_copy(&sid, &domain->sid);
+               sid_append_rid(&sid, alias_rids[i]);
+               add_sid_to_array(state->mem_ctx, &sid, &sids, &num_sids);
+       }
+
+       if (!print_sidlist(NULL, sids, num_sids,
+                          (char **)&state->response.extra_data)) {
+               DEBUG(0, ("Could not print_sidlist\n"));
+               return WINBINDD_ERROR;
+       }
+
+       if (state->response.extra_data != NULL) {
+               DEBUG(10, ("aliases_list: %s\n",
+                          (char *)state->response.extra_data));
+               state->response.length += strlen(state->response.extra_data)+1;
+       }
+       
+       return WINBINDD_OK;
+}
+
+struct gettoken_state {
+       TALLOC_CTX *mem_ctx;
+       DOM_SID user_sid;
+       struct winbindd_domain *alias_domain;
+       struct winbindd_domain *builtin_domain;
+       DOM_SID *sids;
+       int num_sids;
+       void (*cont)(void *private, BOOL success, DOM_SID *sids, int num_sids);
+       void *private;
+};
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
+                                  struct winbindd_response *response,
+                                  void *c, void *private);
+static void gettoken_recvaliases(void *private, BOOL success,
+                                const DOM_SID *aliases,
+                                int num_aliases);
+                                
+
+void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
+                            void (*cont)(void *private, BOOL success,
+                                         DOM_SID *sids, int num_sids),
+                            void *private)
+{
+       struct winbindd_domain *domain;
+       struct winbindd_request request;
+       struct gettoken_state *state;
+
+       state = TALLOC_P(mem_ctx, struct gettoken_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       sid_copy(&state->user_sid, user_sid);
+       state->alias_domain = find_our_domain();
+       state->builtin_domain = find_builtin_domain();
+       state->cont = cont;
+       state->private = private;
+
+       domain = find_domain_from_sid_noinit(user_sid);
+       if (domain == NULL) {
+               DEBUG(5, ("Could not find domain from SID %s\n",
+                         sid_string_static(user_sid)));
+               cont(private, False, NULL, 0);
+               return;
+       }
+
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_GETUSERDOMGROUPS;
+       fstrcpy(request.data.sid, sid_string_static(user_sid));
+
+       do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
+                       NULL, state);
+}
+
+static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
+                                  struct winbindd_response *response,
+                                  void *c, void *private)
+{
+       struct gettoken_state *state =
+               talloc_get_type_abort(private, struct gettoken_state);
+       char *sids_str;
+       
+       if (!success) {
+               DEBUG(10, ("Could not get domain groups\n"));
+               state->cont(state->private, False, NULL, 0);
+               return;
+       }
+
+       sids_str = response->extra_data;
+
+       if (sids_str == NULL) {
+               DEBUG(10, ("Received no domain groups\n"));
+               state->cont(state->private, True, NULL, 0);
+               return;
+       }
+
+       state->sids = NULL;
+       state->num_sids = 0;
+
+       add_sid_to_array(mem_ctx, &state->user_sid, &state->sids,
+                        &state->num_sids);
+
+       if (!parse_sidlist(mem_ctx, sids_str, &state->sids,
+                          &state->num_sids)) {
+               DEBUG(0, ("Could not parse sids\n"));
+               state->cont(state->private, False, NULL, 0);
+               return;
+       }
+
+       SAFE_FREE(response->extra_data);
+
+       if (state->alias_domain == NULL) {
+               DEBUG(10, ("Don't expand domain local groups\n"));
+               state->cont(state->private, True, state->sids,
+                           state->num_sids);
+               return;
+       }
+
+       winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
+                                    state->sids, state->num_sids,
+                                    gettoken_recvaliases, state);
+}
+
+static void gettoken_recvaliases(void *private, BOOL success,
+                                const DOM_SID *aliases,
+                                int num_aliases)
+{
+       struct gettoken_state *state = private;
+       int i;
+
+       if (!success) {
+               DEBUG(10, ("Could not receive domain local groups\n"));
+               state->cont(state->private, False, NULL, 0);
+               return;
+       }
+
+       for (i=0; i<num_aliases; i++)
+               add_sid_to_array(state->mem_ctx, &aliases[i],
+                                &state->sids, &state->num_sids);
+
+       if (state->builtin_domain != NULL) {
+               struct winbindd_domain *builtin_domain = state->builtin_domain;
+               DEBUG(10, ("Expanding our own local groups\n"));
+               state->builtin_domain = NULL;
+               winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
+                                            state->sids, state->num_sids,
+                                            gettoken_recvaliases, state);
+               return;
+       }
+
+       state->cont(state->private, True, state->sids, state->num_sids);
+}
+
+struct sid2uid_state {
+       TALLOC_CTX *mem_ctx;
+       DOM_SID sid;
+       char *username;
+       uid_t uid;
+       void (*cont)(void *private, BOOL success, uid_t uid);
+       void *private;
+};
+
+static void sid2uid_lookup_sid_recv(void *private, BOOL success,
+                                   const char *dom_name, const char *name,
+                                   enum SID_NAME_USE type);
+static void sid2uid_noalloc_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_alloc_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_name2uid_recv(void *private, BOOL success, uid_t uid);
+static void sid2uid_set_mapping_recv(void *private, BOOL success);
+
+void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+                           void (*cont)(void *private, BOOL success,
+                                        uid_t uid),
+                           void *private)
+{
+       struct sid2uid_state *state;
+       NTSTATUS result;
+       uid_t uid;
+
+       if (idmap_proxyonly()) {
+               DEBUG(10, ("idmap proxy only\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       /* Query only the local tdb, everything else might possibly block */
+
+       result = idmap_sid_to_uid(sid, &uid, ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+       if (NT_STATUS_IS_OK(result)) {
+               cont(private, True, uid);
+               return;
+       }
+
+       state = TALLOC_P(mem_ctx, struct sid2uid_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->sid = *sid;
+       state->cont = cont;
+       state->private = private;
+
+       /* Let's see if it's really a user before allocating a uid */
+
+       winbindd_lookupsid_async(mem_ctx, sid, sid2uid_lookup_sid_recv, state);
+}
+
+static void sid2uid_lookup_sid_recv(void *private, BOOL success,
+                                   const char *dom_name, const char *name,
+                                   enum SID_NAME_USE type)
+{
+       struct sid2uid_state *state =
+               talloc_get_type_abort(private, struct sid2uid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger lookup_sid\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+               DEBUG(5, ("SID is not a user\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->username = talloc_strdup(state->mem_ctx, name);
+
+       /* Ask the possibly blocking remote IDMAP */
+
+       idmap_sid2uid_async(state->mem_ctx, &state->sid, False,
+                           sid2uid_noalloc_recv, state);
+}
+
+static void sid2uid_noalloc_recv(void *private, BOOL success, uid_t uid)
+{
+       struct sid2uid_state *state =
+               talloc_get_type_abort(private, struct sid2uid_state);
+
+       if (success) {
+               DEBUG(10, ("found uid for sid %s in remote backend\n",
+                          sid_string_static(&state->sid)));
+               state->cont(state->private, True, uid);
+               return;
+       }
+
+       if (lp_winbind_trusted_domains_only() && 
+           (sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
+               DEBUG(10, ("Trying to go via nss\n"));
+               winbindd_name2uid_async(state->mem_ctx, state->username,
+                                       sid2uid_name2uid_recv, state);
+               return;
+       }
+
+       /* To be done: Here we're going to try the unixinfo pipe */
+
+       /* Now allocate a uid */
+
+       idmap_sid2uid_async(state->mem_ctx, &state->sid, True,
+                           sid2uid_alloc_recv, state);
+}
+
+static void sid2uid_alloc_recv(void *private, BOOL success, uid_t uid)
+{
+       struct sid2uid_state *state =
+               talloc_get_type_abort(private, struct sid2uid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not allocate uid\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->cont(state->private, True, uid);
+}
+
+static void sid2uid_name2uid_recv(void *private, BOOL success, uid_t uid)
+{
+       struct sid2uid_state *state =
+               talloc_get_type_abort(private, struct sid2uid_state);
+       unid_t id;
+
+       if (!success) {
+               DEBUG(5, ("Could not find uid for name %s\n",
+                         state->username));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->uid = uid;
+
+       id.uid = uid;
+       idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_USERID,
+                               sid2uid_set_mapping_recv, state);
+}
+
+static void sid2uid_set_mapping_recv(void *private, BOOL success)
+{
+       struct sid2uid_state *state =
+               talloc_get_type_abort(private, struct sid2uid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not set ID mapping for sid %s\n",
+                         sid_string_static(&state->sid)));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->cont(state->private, True, state->uid);
+}
+
+struct sid2gid_state {
+       TALLOC_CTX *mem_ctx;
+       DOM_SID sid;
+       char *groupname;
+       gid_t gid;
+       void (*cont)(void *private, BOOL success, gid_t gid);
+       void *private;
+};
+
+static void sid2gid_lookup_sid_recv(void *private, BOOL success,
+                                   const char *dom_name, const char *name,
+                                   enum SID_NAME_USE type);
+static void sid2gid_noalloc_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_alloc_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_name2gid_recv(void *private, BOOL success, gid_t gid);
+static void sid2gid_set_mapping_recv(void *private, BOOL success);
+
+void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+                           void (*cont)(void *private, BOOL success,
+                                        gid_t gid),
+                           void *private)
+{
+       struct sid2gid_state *state;
+       NTSTATUS result;
+       gid_t gid;
+
+       if (idmap_proxyonly()) {
+               DEBUG(10, ("idmap proxy only\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       /* Query only the local tdb, everything else might possibly block */
+
+       result = idmap_sid_to_gid(sid, &gid, ID_QUERY_ONLY|ID_CACHE_ONLY);
+
+       if (NT_STATUS_IS_OK(result)) {
+               cont(private, True, gid);
+               return;
+       }
+
+       state = TALLOC_P(mem_ctx, struct sid2gid_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               cont(private, False, 0);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->sid = *sid;
+       state->cont = cont;
+       state->private = private;
+
+       /* Let's see if it's really a user before allocating a gid */
+
+       winbindd_lookupsid_async(mem_ctx, sid, sid2gid_lookup_sid_recv, state);
+}
+
+static void sid2gid_lookup_sid_recv(void *private, BOOL success,
+                                   const char *dom_name, const char *name,
+                                   enum SID_NAME_USE type)
+{
+       struct sid2gid_state *state =
+               talloc_get_type_abort(private, struct sid2gid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger lookup_sid\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       if (((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
+            (type != SID_NAME_WKN_GRP))) {
+               DEBUG(5, ("SID is not a group\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->groupname = talloc_strdup(state->mem_ctx, name);
+
+       /* Ask the possibly blocking remote IDMAP and allocate  */
+
+       idmap_sid2gid_async(state->mem_ctx, &state->sid, False,
+                           sid2gid_noalloc_recv, state);
+}
+
+static void sid2gid_noalloc_recv(void *private, BOOL success, gid_t gid)
+{
+       struct sid2gid_state *state =
+               talloc_get_type_abort(private, struct sid2gid_state);
+
+       if (success) {
+               DEBUG(10, ("found gid for sid %s in remote backend\n",
+                          sid_string_static(&state->sid)));
+               state->cont(state->private, True, gid);
+               return;
+       }
+
+       if (lp_winbind_trusted_domains_only() && 
+           (sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
+               DEBUG(10, ("Trying to go via nss\n"));
+               winbindd_name2gid_async(state->mem_ctx, state->groupname,
+                                       sid2gid_name2gid_recv, state);
+               return;
+       }
+
+       /* To be done: Here we're going to try the unixinfo pipe */
+
+       /* Now allocate a gid */
+
+       idmap_sid2gid_async(state->mem_ctx, &state->sid, True,
+                           sid2gid_alloc_recv, state);
+}
+
+static void sid2gid_alloc_recv(void *private, BOOL success, gid_t gid)
+{
+       struct sid2gid_state *state =
+               talloc_get_type_abort(private, struct sid2gid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not allocate gid\n"));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->cont(state->private, True, gid);
+}
+
+static void sid2gid_name2gid_recv(void *private, BOOL success, gid_t gid)
+{
+       struct sid2gid_state *state =
+               talloc_get_type_abort(private, struct sid2gid_state);
+       unid_t id;
+
+       if (!success) {
+               DEBUG(5, ("Could not find gid for name %s\n",
+                         state->groupname));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->gid = gid;
+
+       id.gid = gid;
+       idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_GROUPID,
+                               sid2gid_set_mapping_recv, state);
+}
+
+static void sid2gid_set_mapping_recv(void *private, BOOL success)
+{
+       struct sid2gid_state *state =
+               talloc_get_type_abort(private, struct sid2gid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not set ID mapping for sid %s\n",
+                         sid_string_static(&state->sid)));
+               state->cont(state->private, False, 0);
+               return;
+       }
+
+       state->cont(state->private, True, state->gid);
+}
+
+static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                           struct winbindd_response *response,
+                           void *c, void *private)
+{
+       void (*cont)(void *priv, BOOL succ, const char *acct_name,
+                    const char *full_name, uint32 group_rid) = c;
+
+       if (!success) {
+               DEBUG(5, ("Could not trigger query_user\n"));
+               cont(private, False, NULL, NULL, -1);
+               return;
+       }
+
+       cont(private, True, response->data.user_info.acct_name,
+            response->data.user_info.full_name,
+            response->data.user_info.group_rid);
+}
+
+void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
+                     const DOM_SID *sid,
+                     void (*cont)(void *private, BOOL success,
+                                  const char *acct_name,
+                                  const char *full_name,
+                                  uint32 group_rid),
+                     void *private)
+{
+       struct winbindd_request request;
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_DUAL_USERINFO;
+       sid_to_string(request.data.sid, sid);
+       do_async_domain(mem_ctx, domain, &request, query_user_recv,
+                       cont, private);
+}
+
index e036de72a70c0d1392aedb6a3222fea13733d894..90ccb43a6ec1cea78b43396dc553b8ca95234273 100644 (file)
 #include "includes.h"
 #include "winbindd.h"
 
-extern BOOL opt_nocache;
-extern struct winbindd_methods msrpc_methods;
-extern struct winbindd_methods ads_methods;
-extern BOOL opt_dual_daemon;
-extern BOOL background_process;
-
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
@@ -53,6 +47,8 @@ static struct winbind_cache *wcache;
 /* flush the cache */
 void wcache_flush_cache(void)
 {
+       extern BOOL opt_nocache;
+
        if (!wcache)
                return;
        if (wcache->tdb) {
@@ -106,9 +102,11 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
        struct winbind_cache *ret = wcache;
 
        if (!domain->backend) {
+               extern struct winbindd_methods reconnect_methods;
                switch (lp_security()) {
 #ifdef HAVE_ADS
                case SEC_ADS: {
+                       extern struct winbindd_methods ads_methods;
                        /* always obey the lp_security parameter for our domain */
                        if (domain->primary) {
                                domain->backend = &ads_methods;
@@ -132,7 +130,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
                default:
                        DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
                                domain->name));
-                       domain->backend = &msrpc_methods;
+                       domain->backend = &reconnect_methods;
                }
        }
 
@@ -212,7 +210,10 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
                smb_panic("centry_string");
        }
 
-       ret = TALLOC(mem_ctx, len+1);
+       if (mem_ctx != NULL)
+               ret = TALLOC(mem_ctx, len+1);
+       else
+               ret = SMB_MALLOC(len+1);
        if (!ret) {
                smb_panic("centry_string out of memory\n");
        }
@@ -225,20 +226,15 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
 /* pull a string from a cache entry, using the supplied
    talloc context 
 */
-static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
+static BOOL centry_sid(struct cache_entry *centry, DOM_SID *sid)
 {
-       DOM_SID *sid;
        char *sid_string;
-
-       sid = TALLOC_P(mem_ctx, DOM_SID);
-       if (!sid)
-               return NULL;
-       
-       sid_string = centry_string(centry, mem_ctx);
+       sid_string = centry_string(centry, NULL);
        if (!string_to_sid(sid, sid_string)) {
-               return NULL;
+               return False;
        }
-       return sid;
+       SAFE_FREE(sid_string);
+       return True;
 }
 
 /* the server is considered down if it can't give us a sequence number */
@@ -471,11 +467,13 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
        centry->sequence_number = centry_uint32(centry);
 
        if (centry_expired(domain, kstr, centry)) {
+               extern BOOL opt_dual_daemon;
 
                DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
                         kstr, domain->name ));
 
                if (opt_dual_daemon) {
+                       extern BOOL background_process;
                        background_process = True;
                        DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
                                 kstr, domain->name ));
@@ -654,9 +652,9 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI
                return;
        centry_put_string(centry, info->acct_name);
        centry_put_string(centry, info->full_name);
-       centry_put_sid(centry, info->user_sid);
-       centry_put_sid(centry, info->group_sid);
-       centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid));
+       centry_put_sid(centry, &info->user_sid);
+       centry_put_sid(centry, &info->group_sid);
+       centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
        DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
        centry_free(centry);
 }
@@ -691,8 +689,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
        for (i=0; i<(*num_entries); i++) {
                (*info)[i].acct_name = centry_string(centry, mem_ctx);
                (*info)[i].full_name = centry_string(centry, mem_ctx);
-               (*info)[i].user_sid = centry_sid(centry, mem_ctx);
-               (*info)[i].group_sid = centry_sid(centry, mem_ctx);
+               centry_sid(centry, &(*info)[i].user_sid);
+               centry_sid(centry, &(*info)[i].group_sid);
        }
 
 do_cached:     
@@ -729,10 +727,12 @@ do_query:
 
                status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
                if (!NT_STATUS_IS_OK(status))
-                       DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status)));
-                       if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) {
-                               DEBUG(3, ("query_user_list: flushing connection cache\n"));
-                               winbindd_cm_flush();
+                       DEBUG(3, ("query_user_list: returned 0x%08x, "
+                                 "retrying\n", NT_STATUS_V(status)));
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
+                               DEBUG(3, ("query_user_list: flushing "
+                                         "connection cache\n"));
+                               invalidate_cm_connection(&domain->conn);
                        }
 
        } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 
@@ -747,17 +747,17 @@ do_query:
        for (i=0; i<(*num_entries); i++) {
                centry_put_string(centry, (*info)[i].acct_name);
                centry_put_string(centry, (*info)[i].full_name);
-               centry_put_sid(centry, (*info)[i].user_sid);
-               centry_put_sid(centry, (*info)[i].group_sid);
+               centry_put_sid(centry, &(*info)[i].user_sid);
+               centry_put_sid(centry, &(*info)[i].group_sid);
                if (domain->backend->consistent) {
                        /* when the backend is consistent we can pre-prime some mappings */
                        wcache_save_name_to_sid(domain, NT_STATUS_OK, 
                                                domain->name,
                                                (*info)[i].acct_name, 
-                                               (*info)[i].user_sid,
+                                               &(*info)[i].user_sid,
                                                SID_NAME_USER);
                        wcache_save_sid_to_name(domain, NT_STATUS_OK, 
-                                               (*info)[i].user_sid,
+                                               &(*info)[i].user_sid,
                                                domain->name,
                                                (*info)[i].acct_name, 
                                                SID_NAME_USER);
@@ -939,7 +939,6 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
        struct cache_entry *centry = NULL;
        NTSTATUS status;
        fstring uname;
-       DOM_SID *sid2;
 
        if (!cache->tdb)
                goto do_query;
@@ -950,13 +949,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
        if (!centry)
                goto do_query;
        *type = (enum SID_NAME_USE)centry_uint32(centry);
-       sid2 = centry_sid(centry, mem_ctx);
-       if (!sid2) {
-               ZERO_STRUCTP(sid);
-       } else {
-               sid_copy(sid, sid2);
-       }
-
+       centry_sid(centry, sid);
        status = centry->status;
 
        DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
@@ -1089,8 +1082,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 
        info->acct_name = centry_string(centry, mem_ctx);
        info->full_name = centry_string(centry, mem_ctx);
-       info->user_sid = centry_sid(centry, mem_ctx);
-       info->group_sid = centry_sid(centry, mem_ctx);
+       centry_sid(centry, &info->user_sid);
+       centry_sid(centry, &info->group_sid);
        status = centry->status;
 
        DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
@@ -1124,7 +1117,7 @@ do_query:
 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
                                  const DOM_SID *user_sid, 
-                                 uint32 *num_groups, DOM_SID ***user_gids)
+                                 uint32 *num_groups, DOM_SID **user_gids)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -1157,11 +1150,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        if (*num_groups == 0)
                goto do_cached;
 
-       (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
+       (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
        if (! (*user_gids))
                smb_panic("lookup_usergroups out of memory");
        for (i=0; i<(*num_groups); i++) {
-               (*user_gids)[i] = centry_sid(centry, mem_ctx);
+               centry_sid(centry, &(*user_gids)[i]);
        }
 
 do_cached:     
@@ -1194,7 +1187,7 @@ do_query:
                goto skip_save;
        centry_put_uint32(centry, *num_groups);
        for (i=0; i<(*num_groups); i++) {
-               centry_put_sid(centry, (*user_gids)[i]);
+               centry_put_sid(centry, &(*user_gids)[i]);
        }       
        centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
        centry_free(centry);
@@ -1205,7 +1198,7 @@ skip_save:
 
 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
                                   TALLOC_CTX *mem_ctx,
-                                  uint32 num_sids, DOM_SID **sids,
+                                  uint32 num_sids, const DOM_SID *sids,
                                   uint32 *num_aliases, uint32 **alias_rids)
 {
        struct winbind_cache *cache = get_cache(domain);
@@ -1228,7 +1221,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
 
        for (i=0; i<num_sids; i++) {
                sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
-                                         sid_string_static(sids[i]));
+                                         sid_string_static(&sids[i]));
                if (sidlist == NULL)
                        return NT_STATUS_NO_MEMORY;
        }
@@ -1265,7 +1258,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
        if (!NT_STATUS_IS_OK(domain->last_status))
                return domain->last_status;
 
-       DEBUG(10,("lookup_useraliases: [Cached] - doing backend query for info "
+       DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
                  "for domain %s\n", domain->name ));
 
        status = domain->backend->lookup_useraliases(domain, mem_ctx,
@@ -1291,7 +1284,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                const DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID ***sid_mem, char ***names, 
+                               DOM_SID **sid_mem, char ***names, 
                                uint32 **name_types)
 {
        struct winbind_cache *cache = get_cache(domain);
@@ -1312,7 +1305,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        if (*num_names == 0)
                goto do_cached;
 
-       (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_names);
+       (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
        (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
        (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
 
@@ -1321,7 +1314,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        }
 
        for (i=0; i<(*num_names); i++) {
-               (*sid_mem)[i] = centry_sid(centry, mem_ctx);
+               centry_sid(centry, &(*sid_mem)[i]);
                (*names)[i] = centry_string(centry, mem_ctx);
                (*name_types)[i] = centry_uint32(centry);
        }
@@ -1359,7 +1352,7 @@ do_query:
                goto skip_save;
        centry_put_uint32(centry, *num_names);
        for (i=0; i<(*num_names); i++) {
-               centry_put_sid(centry, (*sid_mem)[i]);
+               centry_put_sid(centry, &(*sid_mem)[i]);
                centry_put_string(centry, (*names)[i]);
                centry_put_uint32(centry, (*name_types)[i]);
        }       
@@ -1466,3 +1459,166 @@ struct winbindd_methods cache_methods = {
        trusted_domains,
        alternate_name
 };
+
+static BOOL init_wcache(void)
+{
+       if (wcache == NULL) {
+               wcache = SMB_XMALLOC_P(struct winbind_cache);
+               ZERO_STRUCTP(wcache);
+       }
+
+       if (wcache->tdb != NULL)
+               return True;
+
+       wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000, 
+                                  TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
+
+       if (wcache->tdb == NULL) {
+               DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
+               return False;
+       }
+
+       return True;
+}
+
+void cache_store_response(pid_t pid, struct winbindd_response *response)
+{
+       fstring key_str;
+
+       if (!init_wcache())
+               return;
+
+       DEBUG(10, ("Storing response for pid %d, len %d\n",
+                  pid, response->length));
+
+       fstr_sprintf(key_str, "DR/%d", pid);
+       if (tdb_store(wcache->tdb, string_tdb_data(key_str), 
+                     make_tdb_data((void *)response, sizeof(*response)),
+                     TDB_REPLACE) == -1)
+               return;
+
+       if (response->length == sizeof(*response))
+               return;
+
+       /* There's extra data */
+
+       DEBUG(10, ("Storing extra data: len=%d\n",
+                  response->length - sizeof(*response)));
+
+       fstr_sprintf(key_str, "DE/%d", pid);
+       if (tdb_store(wcache->tdb, string_tdb_data(key_str),
+                     make_tdb_data(response->extra_data,
+                                   response->length - sizeof(*response)),
+                     TDB_REPLACE) == 0)
+               return;
+
+       /* We could not store the extra data, make sure the tdb does not
+        * contain a main record with wrong dangling extra data */
+
+       fstr_sprintf(key_str, "DR/%d", pid);
+       tdb_delete(wcache->tdb, string_tdb_data(key_str));
+
+       return;
+}
+
+BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
+{
+       TDB_DATA data;
+       fstring key_str;
+
+       if (!init_wcache())
+               return False;
+
+       DEBUG(10, ("Retrieving response for pid %d\n", pid));
+
+       fstr_sprintf(key_str, "DR/%d", pid);
+       data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+       if (data.dptr == NULL)
+               return False;
+
+       if (data.dsize != sizeof(*response))
+               return False;
+
+       memcpy(response, data.dptr, data.dsize);
+       SAFE_FREE(data.dptr);
+
+       if (response->length == sizeof(*response)) {
+               response->extra_data = NULL;
+               return True;
+       }
+
+       /* There's extra data */
+
+       DEBUG(10, ("Retrieving extra data length=%d\n",
+                  response->length - sizeof(*response)));
+
+       fstr_sprintf(key_str, "DE/%d", pid);
+       data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
+
+       if (data.dptr == NULL) {
+               DEBUG(0, ("Did not find extra data\n"));
+               return False;
+       }
+
+       if (data.dsize != (response->length - sizeof(*response))) {
+               DEBUG(0, ("Invalid extra data length: %d\n", data.dsize));
+               SAFE_FREE(data.dptr);
+               return False;
+       }
+
+       response->extra_data = data.dptr;
+       return True;
+}
+
+char *cache_store_request_data(TALLOC_CTX *mem_ctx, char *request_string)
+{
+       int i;
+
+       if (!init_wcache())
+               return NULL;
+
+       for (i=0; i<2; i++) {
+               char *key = talloc_strdup(mem_ctx, generate_random_str(16));
+               if (key == NULL)
+                       return NULL;
+               DEBUG(10, ("Storing request key %s\n", key));
+               if (tdb_store_bystring(wcache->tdb, key,
+                                      string_tdb_data(request_string),
+                                      TDB_INSERT) == 0)
+                       return key;
+       }
+       return NULL;
+}
+
+char *cache_retrieve_request_data(TALLOC_CTX *mem_ctx, char *key)
+{
+       TDB_DATA data;
+       char *result = NULL;
+
+       if (!init_wcache())
+               return NULL;
+
+       DEBUG(10, ("Retrieving key %s\n", key));
+
+       data = tdb_fetch_bystring(wcache->tdb, key);
+       if (data.dptr == NULL)
+               return NULL;
+
+       if (strnlen(data.dptr, data.dsize) != (data.dsize)) {
+               DEBUG(0, ("Received invalid request string\n"));
+               goto done;
+       }
+       result = TALLOC_ARRAY(mem_ctx, char, data.dsize+1);
+       if (result != NULL) {
+               memcpy(result, data.dptr, data.dsize);
+               result[data.dsize] = '\0';
+       }
+       if (tdb_delete_bystring(wcache->tdb, key) != 0) {
+               DEBUG(0, ("Could not delete key %s\n", key));
+               result = NULL;
+       }
+  done:
+       SAFE_FREE(data.dptr);
+       return result;
+}
index c5cf1d5f4646554caec3bbb643ad49531e7033c2..a6f09f4bf291c4aa044b3bb07dbdf0cec533e448 100644 (file)
@@ -3,8 +3,10 @@
 
    Winbind daemon connection manager
 
-   Copyright (C) Tim Potter 2001
-   Copyright (C) Andrew Bartlett 2002
+   Copyright (C) Tim Potter                2001
+   Copyright (C) Andrew Bartlett           2002
+   Copyright (C) Gerald (Jerry) Carter     2003-2005.
+   Copyright (C) Volker Lendecke           2004-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
 /* Global list of connections. Initially a DLIST but can become a hash
    table or whatever later. */
 
-struct winbindd_cm_conn {
-       struct winbindd_cm_conn *prev, *next;
-       fstring domain;
-       fstring controller;
-       fstring pipe_name;
-       struct cli_state *cli;
-       POLICY_HND pol;
-};
-
-static struct winbindd_cm_conn *cm_conns = NULL;
-
-static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
-                                         const char *pipe_name,
-                                         struct winbindd_cm_conn **conn_out);
-
 /* Choose between anonymous or authenticated connections.  We need to use
    an authenticated connection if DCs have the RestrictAnonymous registry
    entry set > 0, or the "Additional restrictions for anonymous
@@ -113,75 +100,45 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
        }
 }
 
-/*
-  setup for schannel on any pipes opened on this connection
-*/
-static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
-{
-       NTSTATUS ret;
-       uchar trust_password[16];
-       uint32 sec_channel_type;
-       DOM_SID sid;
-       time_t lct;
-
-       /* use the domain trust password if we're on a DC 
-          and this is not our domain */
-       
-       if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
-               char *pass = NULL;
-               
-               if ( !secrets_fetch_trusted_domain_password( domain, 
-                       &pass, &sid, &lct) )
-               {
-                       return NT_STATUS_UNSUCCESSFUL;
-               }       
-
-               sec_channel_type = SEC_CHAN_DOMAIN;
-               E_md4hash(pass, trust_password);
-               SAFE_FREE( pass );
-               
-       } else {
-               if (!secrets_fetch_trust_account_password(lp_workgroup(),
-                       trust_password, NULL, &sec_channel_type)) 
-               {
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       }
-
-       ret = cli_nt_setup_netsec(cli, sec_channel_type, 
-               AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
-
-       return ret;
-}
-
 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
                                     fstring dcname, struct in_addr *dc_ip)
 {
        struct winbindd_domain *our_domain;
        NTSTATUS result;
-       struct winbindd_cm_conn *conn;
+       struct rpc_pipe_client *cli;
        TALLOC_CTX *mem_ctx;
 
        fstring tmp;
        char *p;
 
+       /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
+        * moment.... */
+
        if (IS_DC)
                return False;
 
        if (domain->primary)
                return False;
 
-       if ((our_domain = find_our_domain()) == NULL)
-               return False;
+       our_domain = find_our_domain();
 
-       result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
-       if (!NT_STATUS_IS_OK(result))
+       if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
                return False;
 
-       if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
+       {
+               /* These var's can be ignored -- we're not requesting
+                  anything in the credential chain here */
+               unsigned char *session_key;
+               DOM_CRED *creds;
+               result = cm_connect_netlogon(our_domain, mem_ctx, &cli,
+                                            &session_key, &creds);
+       }
+
+       if (!NT_STATUS_IS_OK(result))
                return False;
 
-       result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
+       result = rpccli_netlogon_getdcname(cli, mem_ctx, domain->dcname,
+                                          domain->name, tmp);
 
        talloc_destroy(mem_ctx);
 
@@ -208,7 +165,6 @@ static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
 
 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
                                      const int sockfd,
-                                     const int pipe_index,
                                      const char *controller,
                                      struct cli_state **cli,
                                      BOOL *retry)
@@ -376,33 +332,11 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
        got_mutex = False;
        *retry = False;
 
-       /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel.
-          Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call.
-          So just drop it on the lsarpc pipe */
-
-       if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) {
-               NTSTATUS status = setup_schannel( *cli, domain->name );
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(3,("schannel refused - continuing without "
-                                "schannel (%s)\n", nt_errstr(status)));
-               }
-       }
-
        /* set the domain if empty; needed for schannel connections */
        if ( !*(*cli)->domain )
                fstrcpy( (*cli)->domain, domain->name );
 
-       if ( !cli_nt_session_open (*cli, pipe_index) ) {
-
-               result = NT_STATUS_PIPE_NOT_AVAILABLE;
-
-               /* This might be a NT4 DC */
-               if ( is_win2k_pipe(pipe_index) )
-                       add_failed_connection = False;
-
-               cli_shutdown(*cli);
-               goto done;
-       }
+       (*cli)->pipe_auth_flags = 0;
 
        result = NT_STATUS_OK;
        add_failed_connection = False;
@@ -463,18 +397,158 @@ static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
        return True;
 }
 
+static void mailslot_name(struct in_addr dc_ip, fstring name)
+{
+       fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
+}
+
+static BOOL send_getdc_request(struct in_addr dc_ip,
+                              const char *domain_name,
+                              const DOM_SID *sid)
+{
+       pstring outbuf;
+       char *p;
+       fstring my_acct_name;
+       fstring my_mailslot;
+
+       mailslot_name(dc_ip, my_mailslot);
+
+       memset(outbuf, '\0', sizeof(outbuf));
+
+       p = outbuf;
+
+       SCVAL(p, 0, SAMLOGON);
+       p++;
+
+       SCVAL(p, 0, 0); /* Count pointer ... */
+       p++;
+
+       SIVAL(p, 0, 0); /* The sender's token ... */
+       p += 2;
+
+       p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
+       fstr_sprintf(my_acct_name, "%s$", global_myname());
+       p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
+
+       memcpy(p, my_mailslot, strlen(my_mailslot)+1);
+       p += strlen(my_mailslot)+1;
+
+       SIVAL(p, 0, 0x80);
+       p+=4;
+
+       SIVAL(p, 0, sid_size(sid));
+       p+=4;
+
+       p = ALIGN4(p, outbuf);
+
+       sid_linearize(p, sid_size(sid), sid);
+       p += sid_size(sid);
+
+       SIVAL(p, 0, 1);
+       SSVAL(p, 4, 0xffff);
+       SSVAL(p, 6, 0xffff);
+       p+=8;
+
+       return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
+                                outbuf, PTR_DIFF(p, outbuf),
+                                global_myname(), 0, domain_name, 0x1c,
+                                dc_ip);
+}
+
+static BOOL receive_getdc_response(struct in_addr dc_ip,
+                                  const char *domain_name,
+                                  fstring dc_name)
+{
+       struct packet_struct *packet;
+       fstring my_mailslot;
+       char *buf, *p;
+       fstring dcname, user, domain;
+       int len;
+
+       mailslot_name(dc_ip, my_mailslot);
+
+       packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
+
+       if (packet == NULL) {
+               DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
+               return False;
+       }
+
+       DEBUG(5, ("Received packet for %s\n", my_mailslot));
+
+       buf = packet->packet.dgram.data;
+       len = packet->packet.dgram.datasize;
+
+       if (len < 70) {
+               /* 70 is a completely arbitrary value to make sure
+                  the SVAL below does not read uninitialized memory */
+               DEBUG(3, ("GetDC got short response\n"));
+               return False;
+       }
+
+       /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
+       p = buf+SVAL(buf, smb_vwv10);
+
+       if (CVAL(p,0) != SAMLOGON_R) {
+               DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
+               return False;
+       }
+
+       p+=2;
+       pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+                 STR_TERMINATE|STR_NOALIGN);
+       p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+       pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+                 STR_TERMINATE|STR_NOALIGN);
+       p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+       pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
+                 STR_TERMINATE|STR_NOALIGN);
+       p = skip_unibuf(p, PTR_DIFF(buf+len, p));
+
+       if (!strequal(domain, domain_name)) {
+               DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
+                         domain_name, domain));
+               return False;
+       }
+
+       p = dcname;
+       if (*p == '\\') p += 1;
+       if (*p == '\\') p += 1;
+
+       fstrcpy(dc_name, p);
+
+       DEBUG(10, ("GetDC gave name %s for domain %s\n",
+                  dc_name, domain));
+
+       return True;
+}
+
 /*******************************************************************
  convert an ip to a name
 *******************************************************************/
 
-static void dcip_to_name( const char *domainname, const char *realm, struct in_addr ip, fstring name )
+static void dcip_to_name( const char *domainname, const char *realm, 
+                          const DOM_SID *sid, struct in_addr ip, fstring name )
 {
-       /* try node status request first */
+       int i;
+
+       /* try GETDC requests first */
+       
+       send_getdc_request(ip, domainname, sid);
+       smb_msleep(100);
+
+       for (i=0; i<5; i++) {
+               if (receive_getdc_response(ip, domainname, name))
+                       return;
+               smb_msleep(500);
+       }
+
+       /* try node status request */
 
        if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
                return;
 
-       /* backup in case the ads stuff fails */
+       /* backup in case the netbios stuff fails */
 
        fstrcpy( name, inet_ntoa(ip) );
 
@@ -510,7 +584,6 @@ static void dcip_to_name( const char *domainname, const char *realm, struct in_a
        return;
 }
 
-
 /*******************************************************************
  Retreive a list of IP address for domain controllers.  Fill in 
  the dcs[]  with results.
@@ -553,6 +626,8 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
        if ( iplist_size==0 && lp_security() == SEC_ADS ) 
                get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
 
+       /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
+
        /* now add to the dc array.  We'll wait until the last minute 
           to look up the name of the DC.  But we fill in the char* for 
           the ip now in to make the failed connection cache work */
@@ -616,7 +691,7 @@ static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
           the name, now try to get the name */
 
        if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
-               dcip_to_name( domain->name, domain->alt_name, addr->sin_addr, dcname );
+               dcip_to_name( domain->name, domain->alt_name, &domain->sid, addr->sin_addr, dcname );
        else
                fstrcpy(dcname, dcnames[fd_index]);
 
@@ -624,7 +699,6 @@ static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
-                                  const int pipe_index,
                                   struct winbindd_cm_conn *new_conn)
 {
        TALLOC_CTX *mem_ctx;
@@ -659,17 +733,8 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 
                new_conn->cli = NULL;
 
-               result = cm_prepare_connection(domain, fd, pipe_index,
-                                              domain->dcname,
-                                              &new_conn->cli, &retry);
-
-               if (NT_STATUS_IS_OK(result)) {
-                       fstrcpy(new_conn->domain, domain->name);
-                       /* Initialise SMB connection */
-                       fstrcpy(new_conn->pipe_name,
-                               get_pipe_name_from_index(pipe_index));
-                       break;
-               }
+               result = cm_prepare_connection(domain, fd, domain->dcname,
+                       &new_conn->cli, &retry);
 
                if (!retry)
                        break;
@@ -679,121 +744,86 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
        return result;
 }
 
-/************************************************************************
- Wrapper around statuc cm_open_connection to retreive a freshly
- setup cli_state struct
-************************************************************************/
-
-NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
-                              struct cli_state **cli)
-{
-       NTSTATUS result;
-       struct winbindd_cm_conn conn;
-       
-       result = cm_open_connection( domain, pipe_index, &conn );
-       
-       if ( NT_STATUS_IS_OK(result) ) 
-               *cli = conn.cli;
-
-       return result;
-}
-
 /* Return true if a connection is still alive */
 
-static BOOL connection_ok(struct winbindd_cm_conn *conn)
+void invalidate_cm_connection(struct winbindd_cm_conn *conn)
 {
-       if (!conn) {
-               smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
-               return False;
+       if (conn->samr_pipe != NULL) {
+               cli_rpc_close(conn->samr_pipe);
+               conn->samr_pipe = NULL;
        }
 
-       if (!conn->cli) {
-               DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
-                         conn->controller, conn->domain, conn->pipe_name));
-               return False;
+       if (conn->lsa_pipe != NULL) {
+               cli_rpc_close(conn->lsa_pipe);
+               conn->lsa_pipe = NULL;
        }
 
-       if (!conn->cli->initialised) {
-               DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
-                         conn->controller, conn->domain, conn->pipe_name));
-               return False;
+       if (conn->netlogon_auth2_pipe != NULL) {
+               cli_rpc_close(conn->netlogon_auth2_pipe);
+               conn->netlogon_auth2_pipe = NULL;
        }
 
-       if (conn->cli->fd == -1) {
-               DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
-                         conn->controller, conn->domain, conn->pipe_name));
-               return False;
+       if (conn->netlogon_pipe != NULL) {
+               cli_rpc_close(conn->netlogon_pipe);
+               conn->netlogon_pipe = NULL;
        }
-       
-       return True;
-}
 
-/* Search the cache for a connection. If there is a broken one,
-   shut it down properly and return NULL. */
+       if (conn->cli)
+               cli_shutdown(conn->cli);
+
+       conn->cli = NULL;
+}
 
-static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
-                              struct winbindd_cm_conn **conn_out) 
+void close_conns_after_fork(void)
 {
-       struct winbindd_cm_conn *conn;
+       struct winbindd_domain *domain;
 
-       for (conn = cm_conns; conn; ) {
-               if (strequal(conn->domain, domain->name) && 
-                   strequal(conn->pipe_name, pipe_name)) {
-                       if (!connection_ok(conn)) {
-                               /* Dead connection - remove it. */
-                               struct winbindd_cm_conn *conn_temp = conn->next;
-                               if (conn->cli)
-                                       cli_shutdown(conn->cli);
-                               DLIST_REMOVE(cm_conns, conn);
-                               SAFE_FREE(conn);
-                               conn = conn_temp;  /* Keep the loop moving */
-                               continue;
-                       } else {
-                               break;
-                       }
-               }
-               conn = conn->next;
-       }
+       for (domain = domain_list(); domain; domain = domain->next) {
+               if (domain->conn.cli == NULL)
+                       continue;
 
-       *conn_out = conn;
-}
+               if (domain->conn.cli->fd == -1)
+                       continue;
 
-/* Initialize a new connection up to the RPC BIND. */
+               close(domain->conn.cli->fd);
+               domain->conn.cli->fd = -1;
+       }
+}
 
-static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
-                                 struct winbindd_cm_conn **conn_out)
+static BOOL connection_ok(struct winbindd_domain *domain)
 {
-       struct winbindd_cm_conn *conn;
-       NTSTATUS result;
+       if (domain->conn.cli == NULL) {
+               DEBUG(8, ("Connection to %s for domain %s has NULL "
+                         "cli!\n", domain->dcname, domain->name));
+               return False;
+       }
 
-       if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
-               return NT_STATUS_NO_MEMORY;
-               
-       ZERO_STRUCTP(conn);
-               
-       if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
-               DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
-                         domain->name, pipe_name, nt_errstr(result)));
-               SAFE_FREE(conn);
-               return result;
+       if (!domain->conn.cli->initialised) {
+               DEBUG(3, ("Connection to %s for domain %s was never "
+                         "initialised!\n", domain->dcname, domain->name));
+               return False;
        }
-       DLIST_ADD(cm_conns, conn);
 
-       *conn_out = conn;
-       return NT_STATUS_OK;
-}
+       if (domain->conn.cli->fd == -1) {
+               DEBUG(3, ("Connection to %s for domain %s has died or was "
+                         "never started (fd == -1)\n", 
+                         domain->dcname, domain->name));
+               return False;
+       }
 
-/* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
+       return True;
+}
+       
+/* Initialize a new connection up to the RPC BIND. */
 
-static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
-                                         struct winbindd_cm_conn **conn_out)
+static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
 {
-       find_cm_connection(domain, pipe_name, conn_out);
-
-       if (*conn_out != NULL)
+       if (connection_ok(domain))
                return NT_STATUS_OK;
 
-       return new_cm_connection(domain, pipe_name, conn_out);
+       invalidate_cm_connection(&domain->conn);
+
+       return cm_open_connection(domain, &domain->conn);
 }
 
 /**********************************************************************************
@@ -806,11 +836,15 @@ static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const
 void set_dc_type_and_flags( struct winbindd_domain *domain )
 {
        NTSTATUS                result;
-       struct winbindd_cm_conn conn;
        DS_DOMINFO_CTR          ctr;
        TALLOC_CTX              *mem_ctx = NULL;
+       struct rpc_pipe_client  *cli;
+       POLICY_HND pol;
        
-       ZERO_STRUCT( conn );
+       char *domain_name = NULL;
+       char *dns_name = NULL;
+       DOM_SID *dom_sid = NULL;
+
        ZERO_STRUCT( ctr );
        
        domain->native_mode = False;
@@ -820,100 +854,100 @@ void set_dc_type_and_flags( struct winbindd_domain *domain )
                domain->initialized = True;
                return;
        }
-       
-       if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
-               DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
+
+       result = init_dc_connection(domain);
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
+                         "to %s: (%s)\n", domain->name, nt_errstr(result)));
+               domain->initialized = True;
+               return;
+       }
+
+       cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC_DS);
+
+       if (cli == NULL) {
+               DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
+                         "PI_LSARPC_DS on domain %s: (%s)\n",
                          domain->name, nt_errstr(result)));
                domain->initialized = True;
                return;
        }
-       
-       if ( conn.cli ) {
-               if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
-                               conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
-                       goto done;
-               }
+
+       result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
+                                            DsRolePrimaryDomainInfoBasic,
+                                            &ctr);
+       cli_rpc_close(cli);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               domain->initialized = True;
+               return;
        }
-                               
-       if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
-                       && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
+       
+       if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
+           !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
                domain->native_mode = True;
 
-       /* Cheat - shut down the DS pipe, and open LSA */
+       cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC);
 
-       cli_nt_session_close(conn.cli);
-
-       if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
-               char *domain_name = NULL;
-               char *dns_name = NULL;
-               DOM_SID *dom_sid = NULL;
+       if (cli == NULL) {
+               domain->initialized = True;
+               return;
+       }
 
-               mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
-               if (!mem_ctx) {
-                       DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
-                       return;
-               }
+       mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
+                             domain->name);
+       if (!mem_ctx) {
+               DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
+               return;
+       }
 
-               result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
-                                             SEC_RIGHTS_MAXIMUM_ALLOWED,
-                                             &conn.pol);
+       result = rpccli_lsa_open_policy2(cli, mem_ctx, True, 
+                                        SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
                
-               if (NT_STATUS_IS_OK(result)) {
-                       /* This particular query is exactly what Win2k clients use 
-                          to determine that the DC is active directory */
-                       result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
-                                                           &conn.pol,
-                                                           12, &domain_name,
-                                                           &dns_name, NULL,
-                                                           NULL, &dom_sid);
-               }
+       if (NT_STATUS_IS_OK(result)) {
+               /* This particular query is exactly what Win2k clients use 
+                  to determine that the DC is active directory */
+               result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
+                                                      12, &domain_name,
+                                                      &dns_name, NULL,
+                                                      NULL, &dom_sid);
+       }
+
+       if (NT_STATUS_IS_OK(result)) {
+               if (domain_name)
+                       fstrcpy(domain->name, domain_name);
+
+               if (dns_name)
+                       fstrcpy(domain->alt_name, dns_name);
+
+               if (dom_sid) 
+                       sid_copy(&domain->sid, dom_sid);
 
+               domain->active_directory = True;
+       } else {
+               
+               result = rpccli_lsa_open_policy(cli, mem_ctx, True, 
+                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                               &pol);
+                       
+               if (!NT_STATUS_IS_OK(result))
+                       goto done;
+                       
+               result = rpccli_lsa_query_info_policy(cli, mem_ctx, 
+                                                     &pol, 5, &domain_name, 
+                                                     &dom_sid);
+                       
                if (NT_STATUS_IS_OK(result)) {
                        if (domain_name)
                                fstrcpy(domain->name, domain_name);
-                       
-                       if (dns_name)
-                               fstrcpy(domain->alt_name, dns_name);
 
                        if (dom_sid) 
                                sid_copy(&domain->sid, dom_sid);
-
-                       domain->active_directory = True;
-               } else {
-                       
-                       result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
-                                                    SEC_RIGHTS_MAXIMUM_ALLOWED,
-                                                    &conn.pol);
-                       
-                       if (!NT_STATUS_IS_OK(result))
-                               goto done;
-                       
-                       result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
-                                                          &conn.pol, 5, &domain_name, 
-                                                          &dom_sid);
-                       
-                       if (NT_STATUS_IS_OK(result)) {
-                               if (domain_name)
-                                       fstrcpy(domain->name, domain_name);
-                               
-                               if (dom_sid) 
-                                       sid_copy(&domain->sid, dom_sid);
-                       }
                }
        }
-       
 done:
-       
-       DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
-               domain->active_directory ? "ADS" : "NT4",
-               domain->native_mode ? "native mode" :
-               ((domain->active_directory && !domain->native_mode) ? "mixed mode" : "")));
 
-       /* close the connection;  no other calls use this pipe and it is called only
-          on reestablishing the domain list   --jerry */
-       
-       if ( conn.cli )
-               cli_shutdown( conn.cli );
+       cli_rpc_close(cli);
        
        talloc_destroy(mem_ctx);
 
@@ -922,264 +956,278 @@ done:
        return;
 }
 
+static BOOL cm_get_schannel_key(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               unsigned char **session_key)
+{
+       struct rpc_pipe_client *cli;
+       DOM_CRED *credentials;
 
+       if (lp_client_schannel() == False)
+               return False;
 
-/* Return a LSA policy handle on a domain */
+       return NT_STATUS_IS_OK(cm_connect_netlogon(domain, mem_ctx,
+                                                  &cli, session_key,
+                                                  &credentials));
+}
 
-NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
+NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+                       struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
 {
        struct winbindd_cm_conn *conn;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
        NTSTATUS result;
-       static CLI_POLICY_HND hnd;
 
-       /* Look for existing connections */
-
-       if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
+       result = init_dc_connection(domain);
+       if (!NT_STATUS_IS_OK(result))
                return result;
 
-       /* This *shitty* code needs scrapping ! JRA */
-       
-       if (policy_handle_is_valid(&conn->pol)) {
-               hnd.pol = conn->pol;
-               hnd.cli = conn->cli;
-               *return_hnd = &hnd;
+       conn = &domain->conn;
 
-               return NT_STATUS_OK;
-       }
-       
-       result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
-                                    des_access, &conn->pol);
+       if (conn->samr_pipe == NULL) {
+               unsigned char *session_key;
 
-       if (!NT_STATUS_IS_OK(result)) {
-               /* Hit the cache code again.  This cleans out the old connection and gets a new one */
-               if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
-                       if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
-                               return result;
+               if (cm_get_schannel_key(domain, mem_ctx, &session_key))
+                       conn->samr_pipe = cli_rpc_open_schannel(conn->cli,
+                                                               PI_SAMR,
+                                                               session_key,
+                                                               domain->name);
+               else
+                       conn->samr_pipe = cli_rpc_open_noauth(conn->cli,
+                                                             PI_SAMR);
 
-                       result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
-                                                    des_access, &conn->pol);
+               if (conn->samr_pipe == NULL) {
+                       result = NT_STATUS_PIPE_NOT_AVAILABLE;
+                       goto done;
                }
 
-               if (!NT_STATUS_IS_OK(result)) {
-                       cli_shutdown(conn->cli);
-                       DLIST_REMOVE(cm_conns, conn);
-                       SAFE_FREE(conn);
-                       return result;
-               }
-       }       
+               result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
+                                            SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                            &conn->sam_connect_handle);
+               if (!NT_STATUS_IS_OK(result))
+                       goto done;
 
-       hnd.pol = conn->pol;
-       hnd.cli = conn->cli;
+               result = rpccli_samr_open_domain(conn->samr_pipe,
+                                                mem_ctx,
+                                                &conn->sam_connect_handle,
+                                                SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                                &domain->sid,
+                                                &conn->sam_domain_handle);
+       }
 
-       *return_hnd = &hnd;
+ done:
+       if (!NT_STATUS_IS_OK(result)) {
+               invalidate_cm_connection(conn);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
-       return NT_STATUS_OK;
+       *cli = conn->samr_pipe;
+       *sam_handle = conn->sam_domain_handle;
+       return result;
 }
 
-/* Return a SAM policy handle on a domain */
-
-NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
-{ 
+NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+                       struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
+{
        struct winbindd_cm_conn *conn;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
        NTSTATUS result;
-       static CLI_POLICY_HND hnd;
 
-       /* Look for existing connections */
-
-       if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
+       result = init_dc_connection(domain);
+       if (!NT_STATUS_IS_OK(result))
                return result;
-       
-       /* This *shitty* code needs scrapping ! JRA */
-       
-       if (policy_handle_is_valid(&conn->pol)) {
-               hnd.pol = conn->pol;
-               hnd.cli = conn->cli;
-               
-               *return_hnd = &hnd;
 
-               return NT_STATUS_OK;
-       }
-       
-       result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
-                                 des_access, &conn->pol);
+       conn = &domain->conn;
 
-       if (!NT_STATUS_IS_OK(result)) {
-               /* Hit the cache code again.  This cleans out the old connection and gets a new one */
-               if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
-               
-                       if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
-                               return result;
+       if (conn->lsa_pipe == NULL) {
+               unsigned char *session_key;
 
-                       result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
-                                                 des_access, &conn->pol);
-               }
+               if (cm_get_schannel_key(domain, mem_ctx, &session_key))
+                       conn->lsa_pipe = cli_rpc_open_schannel(conn->cli,
+                                                              PI_LSARPC,
+                                                              session_key,
+                                                              domain->name);
+               else
+                       conn->lsa_pipe = cli_rpc_open_noauth(conn->cli,
+                                                            PI_LSARPC);
 
-               if (!NT_STATUS_IS_OK(result)) {
-               
-                       cli_shutdown(conn->cli);
-                       DLIST_REMOVE(cm_conns, conn);
-                       SAFE_FREE(conn);
-
-                       /* log a message for possible Windows 2003 SP1 DC's */
-                       if ( NT_STATUS_EQUAL(result,NT_STATUS_ACCESS_DENIED) && (lp_security() == SEC_DOMAIN) ) {
-                               DEBUG(0,("samr_connect() received NT_STATUS_ACCESS_DENIED.  If you are connecting \n"));
-                               DEBUGADD(0,("to a Windows 2003 SP1 DC, this is a known issue.  There are two current \n"));
-                               DEBUGADD(0,("workarounds:\n"));
-                               DEBUGADD(0,("(a) Move your configuration to security = ads, or\n"));
-                               DEBUGADD(0,("(b) set 'client schannel = no' in smb.conf and use 'wbinfo --set-auth-user'\n"));
-                               DEBUGADD(0,("    to define the credentials when connecting to the DC\n"));
-                       }
-                       
-                       return result;
+               if (conn->lsa_pipe == NULL) {
+                       result = NT_STATUS_PIPE_NOT_AVAILABLE;
+                       goto done;
                }
-       }       
 
-       hnd.pol = conn->pol;
-       hnd.cli = conn->cli;
+               result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
+                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                               &conn->lsa_policy);
+       }
 
-       *return_hnd = &hnd;
+ done:
+       if (!NT_STATUS_IS_OK(result)) {
+               invalidate_cm_connection(conn);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
-       return NT_STATUS_OK;
+       *cli = conn->lsa_pipe;
+       *lsa_policy = conn->lsa_policy;
+       return result;
 }
 
-/* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
-   netlogon pipe as no handle is returned. */
+/*******************************************************************
+ wrapper around retrieving the trust account password
+*******************************************************************/
 
-NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
-                            const unsigned char *trust_passwd, 
-                            uint32 sec_channel_type,
-                            BOOL fresh,
-                            struct cli_state **cli)
+static BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
+                        uint32 *channel)
 {
-       NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-       struct winbindd_cm_conn *conn;
-       fstring lock_name;
-       BOOL got_mutex;
-
-       if (!cli)
-               return NT_STATUS_INVALID_PARAMETER;
+       DOM_SID sid;
+       char *pwd;
+       time_t last_set_time;
 
-       /* Open an initial conection - keep the mutex. */
+       /* if we are a DC and this is not our domain, then lookup an account
+          for the domain trust */
 
-       find_cm_connection(domain, PIPE_NETLOGON, &conn);
+       if ( IS_DC && !strequal(domain, lp_workgroup()) &&
+            lp_allow_trusted_domains() ) {
 
-       if ( fresh && (conn != NULL) ) {
-               cli_shutdown(conn->cli);
-               conn->cli = NULL;
+               if (!secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
+                                                          &last_set_time)) {
+                       DEBUG(0, ("get_trust_pw: could not fetch trust "
+                                 "account password for trusted domain %s\n",
+                                 domain));
+                       return False;
+               }
 
-               conn = NULL;
+               *channel = SEC_CHAN_DOMAIN;
+               E_md4hash(pwd, ret_pwd);
+               SAFE_FREE(pwd);
 
-               /* purge connection from cache */
-               find_cm_connection(domain, PIPE_NETLOGON, &conn);
-               if (conn != NULL) {
-                       DEBUG(0,("Could not purge connection\n"));
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
+               return True;
        }
 
-       if (conn != NULL) {
-               *cli = conn->cli;
-               return NT_STATUS_OK;
-       }
+       /* Just get the account for the requested domain. In the future this
+        * might also cover to be member of more than one domain. */
 
-       result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
+       if (secrets_fetch_trust_account_password(domain, ret_pwd,
+                                                &last_set_time, channel))
+               return True;
 
-       if (!NT_STATUS_IS_OK(result))
-               return result;
-       
-       fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
+       DEBUG(5, ("get_trust_pw: could not fetch trust account "
+                 "password for domain %s\n", domain));
+       return False;
+}
 
-       if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
-               DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
-       }
-       
-       if ( sec_channel_type == SEC_CHAN_DOMAIN )
-               fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
-                       
-       /* This must be the remote domain (not ours) for schannel */
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+                            TALLOC_CTX *mem_ctx,
+                            struct rpc_pipe_client **cli,
+                            unsigned char **session_key,
+                            DOM_CRED **credentials)
+{
+       struct winbindd_cm_conn *conn;
+       NTSTATUS result;
 
-       fstrcpy( conn->cli->domain, domain->name);
-       
-       result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
-       
-       if (got_mutex)
-               secrets_named_mutex_release(lock_name);
-                               
-       if (!NT_STATUS_IS_OK(result)) {
-               cli_shutdown(conn->cli);
-               DLIST_REMOVE(cm_conns, conn);
-               SAFE_FREE(conn);
+       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
+       uint8  mach_pwd[16];
+       uint32  sec_chan_type;
+       DOM_CHAL clnt_chal, srv_chal, rcv_chal;
+       const char *server_name;
+       const char *account_name;
+       UTIME zerotime;
+
+       result = init_dc_connection(domain);
+       if (!NT_STATUS_IS_OK(result))
                return result;
-       }
 
-       *cli = conn->cli;
+       conn = &domain->conn;
 
-       return result;
-}
+       if (conn->netlogon_pipe != NULL) {
+               *cli = conn->netlogon_pipe;
+               *session_key = (unsigned char *)&conn->sess_key;
+               *credentials = &conn->clnt_cred;
+               return NT_STATUS_OK;
+       }
 
-/* Dump the current connection status */
+       if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type))
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 
-static void dump_conn_list(void)
-{
-       struct winbindd_cm_conn *con;
+       conn->netlogon_auth2_pipe = cli_rpc_open_noauth(conn->cli,
+                                                       PI_NETLOGON);
+       if (conn->netlogon_auth2_pipe == NULL)
+               return NT_STATUS_UNSUCCESSFUL;
 
-       DEBUG(0, ("\tDomain          Controller      Pipe\n"));
+       if (lp_client_schannel() != False)
+               neg_flags |= NETLOGON_NEG_SCHANNEL;
 
-       for(con = cm_conns; con; con = con->next) {
-               char *msg;
+       generate_random_buffer(clnt_chal.data, 8);
 
-               /* Display pipe info */
-               
-               if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
-                       DEBUG(0, ("Error: not enough memory!\n"));
-               } else {
-                       DEBUG(0, ("%s\n", msg));
-                       SAFE_FREE(msg);
-               }
-       }
-}
+       server_name = talloc_asprintf(mem_ctx, "\\\\%s", domain->dcname);
+       account_name = talloc_asprintf(mem_ctx, "%s$",
+                                      domain->primary ?
+                                      global_myname() : domain->name);
 
-void winbindd_cm_status(void)
-{
-       /* List open connections */
+       if ((server_name == NULL) || (account_name == NULL))
+               return NT_STATUS_NO_MEMORY;
 
-       DEBUG(0, ("winbindd connection manager status:\n"));
+       result = rpccli_net_req_chal(conn->netlogon_auth2_pipe, server_name,
+                                    global_myname(), &clnt_chal, &srv_chal);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-       if (cm_conns)
-               dump_conn_list();
-       else
-               DEBUG(0, ("\tNo active connections\n"));
-}
+       /**************** Long-term Session key **************/
 
-/* Close all cached connections */
+       /* calculate the session key */
+       cred_session_key(&clnt_chal, &srv_chal, mach_pwd, conn->sess_key);
+       memset((char *)conn->sess_key+8, '\0', 8);
 
-void winbindd_cm_flush(void)
-{
-       struct winbindd_cm_conn *conn, tmp;
+       /* calculate auth2 credentials */
+       zerotime.time = 0;
+       cred_create(conn->sess_key, &clnt_chal, zerotime,
+                   &conn->clnt_cred.challenge);
 
-       /* Flush connection cache */
+       result = rpccli_net_auth2(conn->netlogon_auth2_pipe, server_name,
+                                 account_name, sec_chan_type, global_myname(),
+                                 &conn->clnt_cred.challenge, &neg_flags,
+                                 &rcv_chal);
 
-       for (conn = cm_conns; conn; conn = conn->next) {
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-               if (!connection_ok(conn))
-                       continue;
+       zerotime.time = 0;
+       if (!cred_assert(&rcv_chal, conn->sess_key, &srv_chal, zerotime)) {
+               DEBUG(0, ("Server replied with bad credential\n"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
-               DEBUG(10, ("Closing connection to %s on %s\n",
-                       conn->pipe_name, conn->controller));
+       if ((lp_client_schannel() == True) &&
+           ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+               DEBUG(3, ("Server did not offer schannel\n"));
+               cli_rpc_close(conn->netlogon_auth2_pipe);
+               conn->netlogon_auth2_pipe = NULL;
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
-               if (conn->cli)
-                       cli_shutdown(conn->cli);
+       if ((lp_client_schannel() == False) ||
+           ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+               /* keep the existing connection to NETLOGON open */
+               conn->netlogon_pipe = conn->netlogon_auth2_pipe;
+               conn->netlogon_auth2_pipe = NULL;
+               *cli = conn->netlogon_pipe;
+               *session_key = (unsigned char *)&conn->sess_key;
+               *credentials = &conn->clnt_cred;
+               return NT_STATUS_OK;
+       }
 
-               tmp.next = conn->next;
+       conn->netlogon_pipe = cli_rpc_open_schannel(conn->cli, PI_NETLOGON,
+                                                   conn->sess_key,
+                                                   domain->name);
 
-               DLIST_REMOVE(cm_conns, conn);
-               SAFE_FREE(conn);
-               conn = &tmp;
+       if (conn->netlogon_pipe == NULL) {
+               DEBUG(3, ("Could not open schannel'ed NETLOGON pipe\n"));
+               cli_rpc_close(conn->netlogon_auth2_pipe);
+               conn->netlogon_auth2_pipe = NULL;
+               return NT_STATUS_ACCESS_DENIED;
        }
 
-       /* Flush failed connection cache */
-
-       flush_negative_conn_cache();
+       *cli = conn->netlogon_pipe;
+       *session_key = (unsigned char *)&conn->sess_key;
+       *credentials = &conn->clnt_cred;
+               
+       return NT_STATUS_OK;
 }
index 587507ee29046c65960e87e07fc16e8b8538a957..f8b802dafac0f8e2f00bc6e7e711b2e8d46d5b05 100644 (file)
@@ -4,6 +4,7 @@
    Winbind background daemon
 
    Copyright (C) Andrew Tridgell 2002
+   Copyright (C) Volker Lendecke 2004,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
@@ -51,6 +52,39 @@ struct dual_list {
 static struct dual_list *dual_list;
 static struct dual_list *dual_list_end;
 
+/* Read some data from a client connection */
+
+static void dual_client_read(struct winbindd_cli_state *state)
+{
+       int n;
+    
+       /* Read data */
+
+       n = sys_read(state->sock, state->read_buf_len + 
+                (char *)&state->request, 
+                sizeof(state->request) - state->read_buf_len);
+       
+       DEBUG(10,("client_read: read %d bytes. Need %ld more for a full "
+                 "request.\n", n, (unsigned long)(sizeof(state->request) - n -
+                                                  state->read_buf_len) ));
+
+       /* Read failed, kill client */
+       
+       if (n == -1 || n == 0) {
+               DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
+                        state->sock, (unsigned long)state->pid, 
+                        (n == -1) ? strerror(errno) : "EOF"));
+               
+               state->finished = True;
+               return;
+       }
+       
+       /* Update client state */
+       
+       state->read_buf_len += n;
+       state->last_access = time(NULL);
+}
+
 /*
   setup a select() including the dual daemon pipe
  */
@@ -176,7 +210,7 @@ void do_dual_daemon(void)
                main_loop_talloc_free();
 
                /* fetch a request from the main daemon */
-               winbind_client_read(&state);
+               dual_client_read(&state);
 
                if (state.finished) {
                        /* we lost contact with our parent */
@@ -212,3 +246,412 @@ void do_dual_daemon(void)
        }
 }
 
+/*
+ * Machinery for async requests sent to children. You set up a
+ * winbindd_request, select a child to query, and issue a async_request
+ * call. When the request is completed, the callback function you specified is
+ * called back with the private pointer you gave to async_request.
+ */
+
+struct winbindd_async_request {
+       struct winbindd_async_request *next, *prev;
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_child *child;
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+       void (*continuation)(void *private, BOOL success);
+       void *private;
+};
+
+static void async_request_sent(void *private, BOOL success);
+static void async_reply_recv(void *private, BOOL success);
+static void schedule_async_request(struct winbindd_child *child);
+
+void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+                  struct winbindd_request *request,
+                  struct winbindd_response *response,
+                  void (*continuation)(void *private, BOOL success),
+                  void *private)
+{
+       struct winbindd_async_request *state, *tmp;
+
+       SMB_ASSERT(continuation != NULL);
+
+       state = TALLOC_P(mem_ctx, struct winbindd_async_request);
+
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               continuation(private, False);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->child = child;
+       state->request = request;
+       state->response = response;
+       state->continuation = continuation;
+       state->private = private;
+
+       DLIST_ADD_END(child->requests, state, tmp);
+
+       schedule_async_request(child);
+
+       return;
+}
+
+static void async_request_sent(void *private, BOOL success)
+{
+       struct winbindd_async_request *state =
+               talloc_get_type_abort(private, struct winbindd_async_request);
+
+       if (!success) {
+               DEBUG(5, ("Could not send async request\n"));
+
+               state->response->length = sizeof(struct winbindd_response);
+               state->response->result = WINBINDD_ERROR;
+               state->continuation(state->private, False);
+               return;
+       }
+
+       /* Request successfully sent to the child, setup the wait for reply */
+
+       setup_async_read(&state->child->event,
+                        &state->response->result,
+                        sizeof(state->response->result),
+                        async_reply_recv, state);
+}
+
+static void async_reply_recv(void *private, BOOL success)
+{
+       struct winbindd_async_request *state =
+               talloc_get_type_abort(private, struct winbindd_async_request);
+       struct winbindd_child *child = state->child;
+
+       state->response->length = sizeof(struct winbindd_response);
+
+       if (!success) {
+               DEBUG(5, ("Could not receive async reply\n"));
+               state->response->result = WINBINDD_ERROR;
+       }
+
+       if (state->response->result == WINBINDD_OK)
+               SMB_ASSERT(cache_retrieve_response(child->pid,
+                                                  state->response));
+
+       DLIST_REMOVE(child->requests, state);
+
+       schedule_async_request(child);
+
+       state->continuation(state->private, True);
+}
+
+static BOOL fork_domain_child(struct winbindd_child *child);
+
+static void schedule_async_request(struct winbindd_child *child)
+{
+       struct winbindd_async_request *request = child->requests;
+
+       if (request == NULL) {
+               return;
+       }
+
+       if (child->event.flags != 0) {
+               return;         /* Busy */
+       }
+
+       if ((child->pid == 0) && (!fork_domain_child(child))) {
+               /* Cancel all outstanding requests */
+
+               while (request != NULL) {
+                       /* request might be free'd in the continuation */
+                       struct winbindd_async_request *next = request->next;
+                       request->continuation(request->private, False);
+                       request = next;
+               }
+               return;
+       }
+
+       setup_async_write(&child->event, request->request,
+                         sizeof(*request->request),
+                         async_request_sent, request);
+       return;
+}
+
+struct domain_request_state {
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_domain *domain;
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+       void (*continuation)(void *private, BOOL success);
+       void *private;
+};
+
+static void domain_init_recv(void *private, BOOL success);
+
+void async_domain_request(TALLOC_CTX *mem_ctx,
+                         struct winbindd_domain *domain,
+                         struct winbindd_request *request,
+                         struct winbindd_response *response,
+                         void (*continuation)(void *private, BOOL success),
+                         void *private)
+{
+       struct domain_request_state *state;
+
+       if (domain->initialized) {
+               async_request(mem_ctx, &domain->child, request, response,
+                             continuation, private);
+               return;
+       }
+
+       state = TALLOC_P(mem_ctx, struct domain_request_state);
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               continuation(private, False);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->domain = domain;
+       state->request = request;
+       state->response = response;
+       state->continuation = continuation;
+       state->private = private;
+
+       init_child_connection(domain, domain_init_recv, state);
+}
+
+static void domain_init_recv(void *private, BOOL success)
+{
+       struct domain_request_state *state =
+               talloc_get_type_abort(private, struct domain_request_state);
+
+       if (!success) {
+               DEBUG(5, ("Domain init returned an error\n"));
+               state->continuation(state->private, False);
+               return;
+       }
+
+       async_request(state->mem_ctx, &state->domain->child,
+                     state->request, state->response,
+                     state->continuation, state->private);
+}
+
+struct winbindd_child_dispatch_table {
+       enum winbindd_cmd cmd;
+       enum winbindd_result (*fn)(struct winbindd_domain *domain,
+                                  struct winbindd_cli_state *state);
+       const char *winbindd_cmd_name;
+};
+
+static struct winbindd_child_dispatch_table child_dispatch_table[] = {
+       
+       { WINBINDD_LOOKUPSID, winbindd_dual_lookupsid, "LOOKUPSID" },
+       { WINBINDD_LOOKUPNAME, winbindd_dual_lookupname, "LOOKUPNAME" },
+       { WINBINDD_LIST_TRUSTDOM, winbindd_dual_list_trusted_domains,
+         "LIST_TRUSTDOM" },
+       { WINBINDD_INIT_CONNECTION, winbindd_dual_init_connection,
+         "INIT_CONNECTION" },
+       { WINBINDD_GETDCNAME, winbindd_dual_getdcname, "GETDCNAME" },
+       { WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence,
+         "SHOW_SEQUENCE" },
+       { WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" },
+       { WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" },
+       { WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct,
+         "CHECK_MACHACC" },
+       { WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" },
+       { WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" },
+       { WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" },
+       { WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" },
+       { WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" },
+       { WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" },
+       { WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" },
+       { WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
+       { WINBINDD_ALLOCATE_RID, winbindd_dual_allocate_rid, "ALLOCATE_RID" },
+       { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_dual_allocate_rid_and_gid,
+         "ALLOCATE_RID_AND_GID" },
+       { WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups,
+         "GETUSERDOMGROUPS" },
+       { WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases,
+         "GETSIDALIASES" },
+       /* End of list */
+
+       { WINBINDD_NUM_CMDS, NULL, "NONE" }
+};
+
+static void child_process_request(struct winbindd_domain *domain,
+                                 struct winbindd_cli_state *state)
+{
+       struct winbindd_child_dispatch_table *table;
+
+       /* Free response data - we may be interrupted and receive another
+          command before being able to send this data off. */
+
+       state->response.result = WINBINDD_ERROR;
+       state->response.length = sizeof(struct winbindd_response);
+
+       state->mem_ctx = talloc_init("winbind request");
+       if (state->mem_ctx == NULL)
+               return;
+
+       /* Process command */
+
+       for (table = child_dispatch_table; table->fn; table++) {
+               if (state->request.cmd == table->cmd) {
+                       DEBUG(10,("process_request: request fn %s\n",
+                                 table->winbindd_cmd_name ));
+                       state->response.result = table->fn(domain, state);
+                       break;
+               }
+       }
+
+       if (!table->fn) {
+               DEBUG(10,("process_request: unknown request fn number %d\n",
+                         (int)state->request.cmd ));
+               state->response.result = WINBINDD_ERROR;
+       }
+
+       talloc_destroy(state->mem_ctx);
+}
+
+void setup_domain_child(struct winbindd_domain *domain,
+                       struct winbindd_child *child,
+                       const char *explicit_logfile)
+{
+       if (explicit_logfile != NULL) {
+               pstr_sprintf(child->logfilename, "%s/log.winbindd-%s",
+                            dyn_LOGFILEBASE, explicit_logfile);
+       } else if (domain != NULL) {
+               pstr_sprintf(child->logfilename, "%s/log.wb-%s",
+                            dyn_LOGFILEBASE, domain->name);
+       } else {
+               smb_panic("Internal error: domain == NULL && "
+                         "explicit_logfile == NULL");
+       }
+
+       child->domain = domain;
+}
+
+struct winbindd_child *children = NULL;
+
+void winbind_child_died(pid_t pid)
+{
+       struct winbindd_child *child;
+
+       for (child = children; child != NULL; child = child->next) {
+               if (child->pid == pid) {
+                       break;
+               }
+       }
+
+       if (child == NULL) {
+               DEBUG(0, ("Unknown child %d died!\n", pid));
+               return;
+       }
+
+       remove_fd_event(&child->event);
+       close(child->event.fd);
+       child->event.fd = 0;
+       child->event.flags = 0;
+       child->pid = 0;
+
+       schedule_async_request(child);
+}
+
+static BOOL fork_domain_child(struct winbindd_child *child)
+{
+       int fdpair[2];
+       struct winbindd_cli_state state;
+       extern BOOL override_logfile;
+
+       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fdpair) != 0) {
+               DEBUG(0, ("Could not open child pipe: %s\n",
+                         strerror(errno)));
+               return False;
+       }
+
+       ZERO_STRUCT(state);
+       state.pid = getpid();
+
+       child->pid = sys_fork();
+
+       if (child->pid == -1) {
+               DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
+               return False;
+       }
+
+       if (child->pid != 0) {
+               /* Parent */
+               close(fdpair[0]);
+               child->next = child->prev = NULL;
+               DLIST_ADD(children, child);
+               child->event.fd = fdpair[1];
+               child->event.flags = 0;
+               child->requests = NULL;
+               add_fd_event(&child->event);
+               return True;
+       }
+
+       /* Child */
+
+       state.sock = fdpair[0];
+       close(fdpair[1]);
+
+       /* tdb needs special fork handling */
+       if (tdb_reopen_all() == -1) {
+               DEBUG(0,("tdb_reopen_all failed.\n"));
+               _exit(0);
+       }
+
+       close_conns_after_fork();
+
+       if (!override_logfile) {
+               lp_set_logfile(child->logfilename);
+               reopen_logs();
+       }
+       
+       dual_daemon_pipe = -1;
+       opt_dual_daemon = False;
+
+       while (1) {
+               /* free up any talloc memory */
+               lp_talloc_free();
+               main_loop_talloc_free();
+
+               /* fetch a request from the main daemon */
+               dual_client_read(&state);
+
+               if (state.finished) {
+                       /* we lost contact with our parent */
+                       exit(0);
+               }
+
+               /* process full rquests */
+               if (state.read_buf_len == sizeof(state.request)) {
+                       DEBUG(4,("child daemon request %d\n",
+                                (int)state.request.cmd));
+
+                       state.request.null_term = '\0';
+                       child_process_request(child->domain, &state);
+
+                       if (state.response.result == WINBINDD_OK)
+                               cache_store_response(sys_getpid(),
+                                                    &state.response);
+
+                       SAFE_FREE(state.response.extra_data);
+
+                       /* We just send the result code back, the result
+                        * structure needs to be fetched via the
+                        * winbindd_cache. Hmm. That needs fixing... */
+
+                       if (write_data(state.sock,
+                                      (void *)&state.response.result,
+                                      sizeof(state.response.result)) !=
+                           sizeof(state.response.result)) {
+                               DEBUG(0, ("Could not write result\n"));
+                               exit(1);
+                       }
+
+                       state.read_buf_len = 0;
+               }
+       }
+}
index c431e32cc130c759e232a9e6d4624b84ce2e9406..1138762cc4045da8dcd60ac72428a55def94a3ed 100644 (file)
@@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
                           enum SID_NAME_USE group_name_type, 
                           int *num_gr_mem, char **gr_mem, int *gr_mem_len)
 {
-       DOM_SID **sid_mem = NULL;
+       DOM_SID *sid_mem = NULL;
        uint32 num_names = 0;
        uint32 *name_types = NULL;
        unsigned int buf_len, buf_ndx, i;
@@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
 
        if (DEBUGLEVEL >= 10) {
                for (i = 0; i < num_names; i++)
-                       DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
+                       DEBUG(10, ("\t%20s %s %d\n", names[i],
+                                  sid_string_static(&sid_mem[i]),
                                   name_types[i]));
        }
 
@@ -222,7 +223,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
        
        parse_domain_user(tmp, name_domain, name_group);
 
-       /* if no domain or our local domain, default to our local domain for aliases */
+       /* if no domain or our local domain and no local tdb group, default to
+        * our local domain for aliases */
 
        if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
                fstrcpy(name_domain, get_global_sam_name());
@@ -245,8 +247,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
 
        /* Get rid and name type from name */
         
-       if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid, 
-                                        &name_type)) {
+       if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
+                                        name_group, &group_sid, &name_type)) {
                DEBUG(1, ("group %s in domain %s does not exist\n", 
                          name_group, name_domain));
                return WINBINDD_ERROR;
@@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
 
        /* Get rid from gid */
-       if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
+       if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) {
                DEBUG(1, ("could not convert gid %lu to rid\n", 
                          (unsigned long)state->request.data.gid));
                return WINBINDD_ERROR;
@@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
 
        /* Get name from sid */
 
-       if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
+       if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
+                                        group_name, &name_type)) {
                DEBUG(1, ("could not lookup sid\n"));
                return WINBINDD_ERROR;
        }
 
        /* Fill in group structure */
 
-       domain = find_domain_from_sid(&group_sid);
+       domain = find_domain_from_sid_noinit(&group_sid);
 
        if (!domain) {
                DEBUG(1,("Can't find domain from sid\n"));
@@ -793,10 +796,6 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
                   
                if ( *which_domain && !strequal(which_domain, domain->name) )
                        continue;
-
-               if ( !domain->initialized )
-                       set_dc_type_and_flags( domain );
-
                        
                ZERO_STRUCT(groups);
 
@@ -856,323 +855,155 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
        return WINBINDD_OK;
 }
 
-static BOOL enum_alias_memberships(const DOM_SID *member_sid,
-                                  DOM_SID **aliases, int *num_aliases)
-{
-       TALLOC_CTX *mem_ctx = talloc_init("enum_alias_memberships");
-
-       uint32 *rids = NULL;
-       int i, num_rids = 0;
-
-       BOOL result = False;
-
-       if (mem_ctx == NULL)
-               return False;
-       
-       *aliases = NULL;
-       *num_aliases = 0;
-
-       if (!pdb_enum_alias_memberships(mem_ctx, get_global_sam_sid(),
-                                       member_sid, 1, &rids, &num_rids))
-               goto done;
-
-       for (i=0; i<num_rids; i++) {
-               DOM_SID alias_sid;
-               sid_copy(&alias_sid, get_global_sam_sid());
-               sid_append_rid(&alias_sid, rids[i]);
-               add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
-       }
-
-       if (!pdb_enum_alias_memberships(mem_ctx, &global_sid_Builtin,
-                                       member_sid, 1, &rids, &num_rids))
-               goto done;
-
-       for (i=0; i<num_rids; i++) {
-               DOM_SID alias_sid;
-               sid_copy(&alias_sid, &global_sid_Builtin);
-               sid_append_rid(&alias_sid, rids[i]);
-               add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
-       }
-
-       result = True;
- done:
-       if (mem_ctx != NULL)
-               talloc_destroy(mem_ctx);
-
-       return result;
-}
-
-static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
-       gid_t gid;
-       DOM_SID *aliases;
-       int j, num_aliases;
-
-       DEBUG(10, ("Adding local gids from SID: %s\n",
-                  sid_string_static(sid)));
-
-       /* Don't expand aliases if not explicitly activated -- for now
-          -- jerry */
-
-       if (!lp_winbind_nested_groups())
-               return;
-
-       /* Add nested group memberships */
-
-       if (!enum_alias_memberships(sid, &aliases, &num_aliases))
-               return;
-
-       for (j=0; j<num_aliases; j++) {
-               enum SID_NAME_USE type;
-
-               if (!local_sid_to_gid(&gid, &aliases[j], &type)) {
-                       DEBUG(1, ("Got an alias membership with no alias\n"));
-                       continue;
-               }
-
-               if ((type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) {
-                       DEBUG(1, ("Got an alias membership in a non-alias\n"));
-                       continue;
-               }
-
-               add_gid_to_array_unique(NULL, gid, gids, num);
-       }
-       SAFE_FREE(aliases);
-}
-
-static void add_gids_from_user_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
-       DEBUG(10, ("Adding gids from user SID: %s\n",
-                  sid_string_static(sid)));
-
-       add_local_gids_from_sid(sid, gids, num);
-}
-
-static void add_gids_from_group_sid(DOM_SID *sid, gid_t **gids, int *num)
-{
-       gid_t gid;
-
-       DEBUG(10, ("Adding gids from group SID: %s\n",
-                  sid_string_static(sid)));
-
-       if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
-               add_gid_to_array_unique(NULL, gid, gids, num);
-
-       add_local_gids_from_sid(sid, gids, num);
-}
-
 /* Get user supplementary groups.  This is much quicker than trying to
    invert the groups database.  We merge the groups from the gids and
    other_sids info3 fields as trusted domain, universal group
    memberships, and nested groups (win2k native mode only) are not
    returned by the getgroups RPC call but are present in the info3. */
 
+struct getgroups_state {
+       struct winbindd_cli_state *state;
+       struct winbindd_domain *domain;
+       char *domname;
+       char *username;
+       DOM_SID user_sid;
+
+       const DOM_SID *token_sids;
+       int i, num_token_sids;
+
+       gid_t *token_gids;
+       int num_token_gids;
+};
+
+static void getgroups_usersid_recv(void *private, BOOL success,
+                                  const DOM_SID *sid, enum SID_NAME_USE type);
+static void getgroups_tokensids_recv(void *private, BOOL success,
+                                    DOM_SID *token_sids, int num_token_sids);
+static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid);
+
 enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
 {
-       fstring name_domain, name_user;
-       DOM_SID user_sid, group_sid;
-       enum SID_NAME_USE name_type;
-       uint32 num_groups = 0;
-       uint32 num_gids = 0;
-       NTSTATUS status;
-       DOM_SID **user_grpsids;
-       struct winbindd_domain *domain;
-       enum winbindd_result result = WINBINDD_ERROR;
-       gid_t *gid_list = NULL;
-       unsigned int i;
-       TALLOC_CTX *mem_ctx;
-       NET_USER_INFO_3 *info3 = NULL;
-       
+       struct getgroups_state *s;
+
        /* Ensure null termination */
-       state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+       state->request.data.username
+               [sizeof(state->request.data.username)-1]='\0';
 
        DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
                  state->request.data.username));
 
-       if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
-                                         state->request.data.username)))
-               return WINBINDD_ERROR;
-
        /* Parse domain and username */
 
-       parse_domain_user(state->request.data.username, 
-                         name_domain, name_user);
-       
-       /* Get info for the domain */
-       
-       if ((domain = find_domain_from_name(name_domain)) == NULL) {
-               DEBUG(7, ("could not find domain entry for domain %s\n", 
-                         name_domain));
-               goto done;
+       s = TALLOC_P(state->mem_ctx, struct getgroups_state);
+       if (s == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               return WINBINDD_ERROR;
        }
 
-       if ( domain->primary && lp_winbind_trusted_domains_only()) {
-               DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
-                        "getgroups() for %s\\%s.\n", name_domain, name_user));
+       s->state = state;
+
+       if (!parse_domain_user_talloc(state->mem_ctx,
+                                     state->request.data.username,
+                                     &s->domname, &s->username)) {
+               DEBUG(0, ("Could not parse domain user: %s\n",
+                         state->request.data.username));
                return WINBINDD_ERROR;
-       }       
+       }
        
-       /* Get rid and name type from name.  The following costs 1 packet */
+       /* Get info for the domain */
 
-       if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, 
-                                        &name_type)) {
-               DEBUG(4, ("user '%s' does not exist\n", name_user));
-               goto done;
-       }
+       s->domain = find_domain_from_name_noinit(s->domname);
 
-       if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
-               DEBUG(1, ("name '%s' is not a user name: %d\n", 
-                         name_user, name_type));
-               goto done;
+       if (s->domain == NULL) {
+               DEBUG(7, ("could not find domain entry for domain %s\n", 
+                         s->domname));
+               return WINBINDD_ERROR;
        }
 
-       add_gids_from_user_sid(&user_sid, &gid_list, &num_gids);
-
-       /* Treat the info3 cache as authoritative as the
-          lookup_usergroups() function may return cached data. */
-
-       if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) {
-
-               struct winbindd_domain *our_domain = find_our_domain();
-
-               if (our_domain == NULL) {
-                       DEBUG(0, ("Could not find our domain\n"));
-                       goto done;
-               }
-
-               DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n",
-                          info3->num_groups2, info3->num_other_sids));
-
-               num_groups = info3->num_other_sids + info3->num_groups2;
-
-               /* Go through each other sid and convert it to a gid */
-
-               for (i = 0; i < info3->num_other_sids; i++) {
-                       DOM_SID *sid = &info3->other_sids[i].sid;
-                       fstring name;
-                       fstring dom_name;
-                       enum SID_NAME_USE sid_type;
-
-                       /* Is this sid known to us?  It can either be
-                           a trusted domain sid or a foreign sid. */
-
-                       if (!winbindd_lookup_name_by_sid( sid, dom_name,
-                                                         name, &sid_type)) {
-                               DEBUG(10, ("winbindd_getgroups: could not "
-                                          "lookup name for %s\n", 
-                                          sid_string_static(sid)));
-                               continue;
-                       }
-
-                       /* Check it is a domain group or an alias (domain
-                          local group) in a win2k native mode domain. */
-                       
-                       if (!((sid_type==SID_NAME_DOM_GRP) ||
-                             ((sid_type==SID_NAME_ALIAS) &&
-                              (our_domain->active_directory) &&
-                              (our_domain->native_mode) &&
-                              (sid_compare_domain(sid, &our_domain->sid)
-                               == 0)))) {
-                               DEBUG(10, ("winbindd_getgroups: sid type %d "
-                                          "for %s is not a domain group\n",
-                                          sid_type, sid_string_static(sid)));
-                               continue;
-                       }
-
-                       add_gids_from_group_sid(sid, &gid_list, &num_gids);
-               }
-
-               for (i = 0; i < info3->num_groups2; i++) {
-               
-                       /* create the group SID */
-                       
-                       sid_copy( &group_sid, &domain->sid );
-                       sid_append_rid( &group_sid, info3->gids[i].g_rid );
-
-                       add_gids_from_group_sid(&group_sid, &gid_list,
-                                               &num_gids);
-               }
+       if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
+               DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+                        "getgroups() for %s\\%s.\n", s->domname,
+                        s->username));
+               return WINBINDD_ERROR;
+       }       
 
-               SAFE_FREE(info3);
+       /* Get rid and name type from name.  The following costs 1 packet */
 
-       } else {
-               status = domain->methods->lookup_usergroups(domain, mem_ctx, 
-                                                   &user_sid, &num_groups, 
-                                                   &user_grpsids);
-               if (!NT_STATUS_IS_OK(status)) 
-                       goto done;
+       winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
+                                 getgroups_usersid_recv, s);
+       return WINBINDD_PENDING;
+}
 
-               if (state->response.extra_data)
-                       goto done;
+static void getgroups_usersid_recv(void *private, BOOL success,
+                                  const DOM_SID *sid, enum SID_NAME_USE type)
+{
+       struct getgroups_state *s = private;
 
-               for (i = 0; i < num_groups; i++) {
-                       add_gids_from_group_sid(user_grpsids[i],
-                                               &gid_list, &num_gids);
-               }
+       if ((!success) ||
+           ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
+               s->state->response.result = WINBINDD_ERROR;
+               request_finished(s->state);
+               return;
        }
 
-       /* We want at least one group... */
-       if (gid_list == NULL)
-               goto done;
-
-       remove_duplicate_gids( &num_gids, gid_list );
-
-       /* Send data back to client */
+       sid_copy(&s->user_sid, sid);
 
-       state->response.data.num_entries = num_gids;
-       state->response.extra_data = gid_list;
-       state->response.length += num_gids * sizeof(gid_t);
-
-       result = WINBINDD_OK;
-
- done:
-
-       talloc_destroy(mem_ctx);
-
-       return result;
+       winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
+                               getgroups_tokensids_recv, s);
 }
 
-static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
-                                   DOM_SID ***sids, int *num_sids)
+static void getgroups_tokensids_recv(void *private, BOOL success,
+                                    DOM_SID *token_sids, int num_token_sids)
 {
-       int i;
+       struct getgroups_state *s = private;
 
-       for (i=0; i<(*num_sids); i++) {
-               if (sid_compare(sid, (*sids)[i]) == 0)
-                       return;
+       /* We need at least the user sid and the primary group in the token,
+        * otherwise it's an error */
+
+       if ((!success) || (num_token_sids < 2)) {
+               s->state->response.result = WINBINDD_ERROR;
+               request_finished(s->state);
+               return;
        }
 
-       *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1);
+       s->token_sids = token_sids;
+       s->num_token_sids = num_token_sids;
+       s->i = 0;
 
-       if (*sids == NULL)
-               return;
+       s->token_gids = NULL;
+       s->num_token_gids = 0;
 
-       (*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID);
-       sid_copy((*sids)[*num_sids], sid);
-       *num_sids += 1;
-       return;
+       getgroups_sid2gid_recv(s, False, 0);
 }
 
-static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
-                                   DOM_SID ***user_grpsids,
-                                   int *num_groups)
+static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid)
 {
-       DOM_SID *aliases = NULL;
-       int i, num_aliases = 0;
+       struct getgroups_state *s = private;
 
-       if (!enum_alias_memberships(sid, &aliases, &num_aliases))
-               return;
+       if (success)
+               add_gid_to_array_unique(NULL, gid,
+                                       &s->token_gids,
+                                       &s->num_token_gids);
 
-       if (num_aliases == 0)
-               return;
+       if (s->i < s->num_token_sids) {
+               const DOM_SID *sid = &s->token_sids[s->i];
+               s->i += 1;
 
-       for (i=0; i<num_aliases; i++)
-               add_sid_to_parray_unique(mem_ctx, &aliases[i], user_grpsids,
-                                        num_groups);
+               if (sid_equal(sid, &s->user_sid)) {
+                       getgroups_sid2gid_recv(s, False, 0);
+                       return;
+               }
 
-       SAFE_FREE(aliases);
+               winbindd_sid2gid_async(s->state->mem_ctx, sid,
+                                      getgroups_sid2gid_recv, s);
+               return;
+       }
 
-       return;
+       s->state->response.data.num_entries = s->num_token_gids;
+       s->state->response.extra_data = s->token_gids;
+       s->state->response.length += s->num_token_gids * sizeof(gid_t);
+       s->state->response.result = WINBINDD_OK;
+       request_finished(s->state);
 }
 
 /* Get user supplementary sids. This is equivalent to the
@@ -1186,106 +1017,50 @@ static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
    you pass in another type of SID then you may get unpredictable
    results.
 */
+
+static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
+                            int num_sids);
+
 enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
 {
-       DOM_SID user_sid;
-       NTSTATUS status;
-       DOM_SID **user_grpsids;
-       struct winbindd_domain *domain;
-       enum winbindd_result result = WINBINDD_ERROR;
-       unsigned int i;
-       TALLOC_CTX *mem_ctx;
-       char *ret = NULL;
-       uint32 num_groups;
-       unsigned ofs, ret_size = 0;
+       DOM_SID *user_sid;
 
        /* Ensure null termination */
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
-       if (!string_to_sid(&user_sid, state->request.data.sid)) {
-               DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
+       user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
+       if (user_sid == NULL) {
+               DEBUG(1, ("talloc failed\n"));
                return WINBINDD_ERROR;
        }
 
-       if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
-                                   state->request.data.username))) {
+       if (!string_to_sid(user_sid, state->request.data.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.sid));
                return WINBINDD_ERROR;
        }
 
-       /* Get info for the domain */   
-       if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
-               DEBUG(0,("could not find domain entry for sid %s\n", 
-                         sid_string_static(&user_sid)));
-               goto done;
-       }
-       
-       status = domain->methods->lookup_usergroups(domain, mem_ctx, 
-                                                   &user_sid, &num_groups, 
-                                                   &user_grpsids);
-       if (!NT_STATUS_IS_OK(status)) 
-               goto done;
+       winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
+                               state);
+       return WINBINDD_PENDING;
+}
 
-       if (num_groups == 0) {
-               goto no_groups;
-       }
+static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
+                            int num_sids)
+{
+       struct winbindd_cli_state *state = private;
+       char *ret = NULL;
+       unsigned ofs, ret_size = 0;
+       int i;
 
-       domain = find_our_domain();
+       state->response.result = WINBINDD_ERROR;
 
-       if (domain == NULL) {
-               DEBUG(0, ("Could not find our domain\n"));
+       if (!success)
                goto done;
-       }
-
-       /* Note that I do not check for AD or its mode. XP in a real NT4
-        * domain also asks for this info. -- vl */
-
-       if (!IS_DC) {
-               uint32 *alias_rids = NULL;
-               int num_aliases;
-
-               /* We need to include the user SID to expand */
-               user_grpsids = TALLOC_REALLOC_ARRAY(mem_ctx, user_grpsids,
-                                                   DOM_SID *, num_groups+1);
-               user_grpsids[num_groups] = &user_sid;
-
-               status = domain->methods->lookup_useraliases(domain, mem_ctx,
-                                                            num_groups+1,
-                                                            user_grpsids,
-                                                            &num_aliases,
-                                                            &alias_rids);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(3, ("Could not expand alias sids: %s\n",
-                                 nt_errstr(status)));
-                       goto done;
-               }
-
-               for (i=0; i<num_aliases; i++) {
-                       DOM_SID sid;
-                       sid_copy(&sid, &domain->sid);
-                       sid_append_rid(&sid, alias_rids[i]);
-                       add_sid_to_parray_unique(mem_ctx, &sid, &user_grpsids,
-                                                &num_groups);
-               }
-       }
-
-       if (lp_winbind_nested_groups()) {
-               int k;
-               /* num_groups is changed during the loop, that's why we have
-                  to count down here.*/
-
-               for (k=num_groups-1; k>=0; k--) {
-                       add_local_sids_from_sid(mem_ctx, user_grpsids[k],
-                                               &user_grpsids, &num_groups);
-               }
-
-               add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids,
-                                       &num_groups);
-       }
 
        /* work out the response size */
-       for (i = 0; i < num_groups; i++) {
-               const char *s = sid_string_static(user_grpsids[i]);
+       for (i = 0; i < num_sids; i++) {
+               const char *s = sid_string_static(&sids[i]);
                ret_size += strlen(s) + 1;
        }
 
@@ -1293,22 +1068,94 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
        ret = SMB_MALLOC(ret_size);
        if (!ret) goto done;
        ofs = 0;
-       for (i = 0; i < num_groups; i++) {
-               const char *s = sid_string_static(user_grpsids[i]);
+       for (i = 0; i < num_sids; i++) {
+               const char *s = sid_string_static(&sids[i]);
                safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
                ofs += strlen(ret+ofs) + 1;
        }
 
-no_groups:
        /* Send data back to client */
-       state->response.data.num_entries = num_groups;
+       state->response.data.num_entries = num_sids;
        state->response.extra_data = ret;
        state->response.length += ret_size;
-       result = WINBINDD_OK;
+       state->response.result = WINBINDD_OK;
 
  done:
-       talloc_destroy(mem_ctx);
+       request_finished(state);
+}
 
-       return result;
+enum winbindd_result winbindd_getuserdomgroups(struct winbindd_cli_state *state)
+{
+       DOM_SID user_sid;
+       struct winbindd_domain *domain;
+
+       /* Ensure null termination */
+       state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+       if (!string_to_sid(&user_sid, state->request.data.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.sid));
+               return WINBINDD_ERROR;
+       }
+
+       /* Get info for the domain */   
+       if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) {
+               DEBUG(0,("could not find domain entry for sid %s\n", 
+                        sid_string_static(&user_sid)));
+               return WINBINDD_ERROR;
+       }
+
+       async_domain_request(state->mem_ctx, domain, &state->request,
+                            &state->response, request_finished_cont, state);
+       return WINBINDD_PENDING;
 }
 
+enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain,
+                                                   struct winbindd_cli_state *state)
+{
+       DOM_SID user_sid;
+       NTSTATUS status;
+
+       int i, num_groups, len, bufsize;
+       DOM_SID *groups;
+
+       /* Ensure null termination */
+       state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
+
+       if (!string_to_sid(&user_sid, state->request.data.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.sid));
+               return WINBINDD_ERROR;
+       }
+
+       status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
+                                                   &user_sid, &num_groups,
+                                                   &groups);
+       if (!NT_STATUS_IS_OK(status))
+               return WINBINDD_ERROR;
+
+       if (num_groups == 0) {
+               state->response.data.num_entries = 0;
+               state->response.extra_data = NULL;
+               return WINBINDD_OK;
+       }
+
+       len=bufsize=0;
+       state->response.extra_data = NULL;
+
+       for (i=0; i<num_groups; i++) {
+               sprintf_append(NULL, (char **)&state->response.extra_data,
+                              &len, &bufsize,
+                              "%s\n", sid_string_static(&groups[i]));
+       }
+
+       if (state->response.extra_data == NULL) {
+               /* Hmmm. Allocation failed somewhere */
+               return WINBINDD_ERROR;
+       }
+
+       state->response.data.num_entries = num_groups;
+       state->response.length += len+1;
+
+       return WINBINDD_OK;
+}
diff --git a/source/nsswitch/winbindd_ldap.c b/source/nsswitch/winbindd_ldap.c
new file mode 100644 (file)
index 0000000..4eedf0c
--- /dev/null
@@ -0,0 +1,646 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   winbind ldap proxy code
+
+   Copyright (C) Volker Lendecke
+   
+   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 "winbindd.h"
+
+/* This rw-buf api is made to avoid memcpy. For now do that like mad...  The
+   idea is to write into a circular list of buffers where the ideal case is
+   that a read(2) holds a complete request that is then thrown away
+   completely. */
+
+struct ldap_message_queue {
+       struct ldap_message_queue *prev, *next;
+       struct ldap_message *msg;
+};
+
+struct rw_buffer {
+       uint8_t *data;
+       size_t ofs, length;
+};
+
+struct winbind_ldap_client {
+       struct winbind_ldap_client *next, *prev;
+       int sock;
+       BOOL finished;
+       struct rw_buffer in_buffer, out_buffer;
+};
+
+static struct winbind_ldap_client *ldap_clients;
+
+struct winbind_ldap_server {
+       struct winbind_ldap_server *next, *prev;
+       int sock;
+       BOOL ready;             /* Bind successful? */
+       BOOL finished;
+       struct rw_buffer in_buffer, out_buffer;
+       int messageid;
+};
+       
+static struct winbind_ldap_server *ldap_servers;
+
+struct pending_ldap_message {
+       struct pending_ldap_message *next, *prev;
+       struct ldap_message *msg; /* The message the client sent us */
+       int our_msgid;          /* The messageid we used */
+       struct winbind_ldap_client *client;
+};
+
+struct pending_ldap_message *pending_messages;
+
+static BOOL append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
+{
+       buf->data = SMB_REALLOC(buf->data, buf->length+length);
+
+       if (buf->data == NULL)
+               return False;
+
+       memcpy(buf->data+buf->length, data, length);
+
+       buf->length += length;
+       return True;
+}
+
+static BOOL read_into_buf(int fd, struct rw_buffer *buf)
+{
+       char tmp_buf[1024];
+       int len;
+
+       len = read(fd, tmp_buf, sizeof(tmp_buf));
+       if (len == 0)
+               return False;
+
+       return append_to_buf(buf, tmp_buf, len);
+}
+
+static void peek_into_buf(struct rw_buffer *buf, uint8_t **out,
+                         size_t *out_length)
+{
+       *out = buf->data;
+       *out_length = buf->length;
+}
+
+static void consumed_from_buf(struct rw_buffer *buf, size_t length)
+{
+       uint8_t *new = memdup(buf->data+length, buf->length-length);
+       free(buf->data);
+       buf->data = new;
+       buf->length -= length;
+}
+
+static BOOL write_out_of_buf(int fd, struct rw_buffer *buf)
+{
+       uint8_t *tmp;
+       size_t tmp_length, written;
+
+       peek_into_buf(buf, &tmp, &tmp_length);
+       if (tmp_length == 0)
+               return True;
+
+       written = write(fd, tmp, tmp_length);
+       if (written < 0)
+               return False;
+
+       consumed_from_buf(buf, written);
+       return True;
+}
+
+static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
+{
+       DATA_BLOB blob;
+       BOOL res;
+
+       if (!ldap_encode(msg, &blob))
+               return False;
+
+       res = append_to_buf(buf, blob.data, blob.length);
+
+       data_blob_free(&blob);
+       return res;
+}
+
+static void new_ldap_client(int listen_sock)
+{
+       struct sockaddr_un sunaddr;
+       struct winbind_ldap_client *client;
+       socklen_t len;
+       int sock;
+       
+       /* Accept connection */
+       
+       len = sizeof(sunaddr);
+
+       do {
+               sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
+       } while (sock == -1 && errno == EINTR);
+
+       if (sock == -1)
+               return;
+       
+       DEBUG(6,("accepted socket %d\n", sock));
+       
+       /* Create new connection structure */
+
+       client = SMB_MALLOC_P(struct winbind_ldap_client);
+
+       if (client == NULL)
+               return;
+
+       ZERO_STRUCTP(client);
+       
+       client->sock = sock;
+       client->finished = False;
+       
+       DLIST_ADD(ldap_clients, client);
+}
+
+static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,
+                                            BOOL *error)
+{
+       uint8_t *buf;
+       int buf_length, msg_length;
+       DATA_BLOB blob;
+       ASN1_DATA data;
+       struct ldap_message *msg;
+
+       DEBUG(10,("ldapsrv_recv\n"));
+
+       *error = False;
+
+       peek_into_buf(buffer, &buf, &buf_length);
+
+       if (buf_length < 8) {
+               /* Arbitrary heuristics: ldap messages are longer than eight
+                * bytes, and their tag length fits into the eight bytes */
+               return NULL;
+       }
+
+       /* LDAP Messages are always SEQUENCES */
+
+       if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
+                               &msg_length))
+               goto disconnect;
+
+       if (buf_length < msg_length) {
+               /* Not enough yet */
+               return NULL;
+       }
+
+       /* We've got a complete LDAP request in the in-buffer */
+
+       blob.data = buf;
+       blob.length = msg_length;
+
+       if (!asn1_load(&data, blob))
+               goto disconnect;
+
+       msg = new_ldap_message();
+
+       if ((msg == NULL) || !ldap_decode(&data, msg)) {
+               asn1_free(&data);
+               goto disconnect;
+       }
+
+       asn1_free(&data);
+
+       consumed_from_buf(buffer, msg_length);
+
+       return msg;
+
+ disconnect:
+
+       *error = True;
+       return NULL;
+}
+
+static int send_msg_to_server(struct ldap_message *msg,
+                             struct winbind_ldap_server *server)
+{
+       int cli_messageid;
+
+       cli_messageid = msg->messageid;
+       msg->messageid = ldap_servers->messageid;
+
+       if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))
+               return -1;
+
+       msg->messageid = cli_messageid;
+       return ldap_servers->messageid++;
+}
+
+static int send_msg(struct ldap_message *msg)
+{
+       /* This is the scheduling routine that should decide where to send
+        * stuff. The first attempt is easy: We only have one server. This
+        * will change once we handle referrals etc. */
+
+       SMB_ASSERT(ldap_servers != NULL);
+
+       if (!ldap_servers->ready)
+               return -1;
+
+       return send_msg_to_server(msg, ldap_servers);
+}
+
+static void fake_bind_response(struct winbind_ldap_client *client,
+                              int messageid)
+{
+       struct ldap_message *msg = new_ldap_message();
+
+       if (msg == NULL) {
+               client->finished = True;
+               return;
+       }
+
+       msg->messageid = messageid;
+       msg->type = LDAP_TAG_BindResponse;
+       msg->r.BindResponse.response.resultcode = 0;
+       msg->r.BindResponse.response.dn = "";
+       msg->r.BindResponse.response.dn = "";
+       msg->r.BindResponse.response.errormessage = "";
+       msg->r.BindResponse.response.referral = "";
+       ldap_append_to_buf(msg, &client->out_buffer);
+       destroy_ldap_message(msg);
+}
+
+static int open_ldap_socket(void)
+{
+       static int fd = -1;
+
+       if (fd >= 0)
+               return fd;
+
+       fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
+       return fd;
+}
+
+static BOOL do_sigterm = False;
+
+static void ldap_termination_handler(int signum)
+{
+       do_sigterm = True;
+       sys_select_signal();
+}
+
+static BOOL handled_locally(struct ldap_message *msg,
+                           struct winbind_ldap_server *server)
+{
+       struct ldap_Result *r = &msg->r.BindResponse.response;
+
+       if (msg->type != LDAP_TAG_BindResponse)
+               return False;
+
+       if (r->resultcode != 0) {
+               destroy_ldap_message(msg);
+               server->finished = True;
+       }
+       destroy_ldap_message(msg);
+       server->ready = True;
+       return True;
+}
+
+static void client_has_data(struct winbind_ldap_client *client)
+{
+                       
+       struct ldap_message *msg;
+
+       if (!read_into_buf(client->sock, &client->in_buffer)) {
+               client->finished = True;
+               return;
+       }
+
+       while ((msg = get_msg_from_buf(&client->in_buffer,
+                                      &client->finished))) {
+               struct pending_ldap_message *pending;
+
+               if (msg->type == LDAP_TAG_BindRequest) {
+                       fake_bind_response(client, msg->messageid);
+                       destroy_ldap_message(msg);
+                       continue;
+               }
+
+               if (msg->type == LDAP_TAG_UnbindRequest) {
+                       destroy_ldap_message(msg);
+                       client->finished = True;
+                       break;
+               }
+
+               pending = SMB_MALLOC_P(struct pending_ldap_message);
+               if (pending == NULL)
+                       continue;
+
+               pending->msg = msg;
+               pending->client = client;
+               pending->our_msgid = send_msg(msg);
+
+               if (pending->our_msgid < 0) {
+                       /* could not send */
+                       client->finished = True;
+                       free(pending);
+               }
+               DLIST_ADD(pending_messages, pending);
+       }
+}
+
+static struct ldap_Result *ldap_msg2result(struct ldap_message *msg)
+{
+       switch(msg->type) {
+       case LDAP_TAG_BindResponse:
+               return &msg->r.BindResponse.response;
+       case LDAP_TAG_SearchResultDone:
+               return &msg->r.SearchResultDone;
+       case LDAP_TAG_ModifyResponse:
+               return &msg->r.ModifyResponse;
+       case LDAP_TAG_AddResponse:
+               return &msg->r.AddResponse;
+       case LDAP_TAG_DelResponse:
+               return &msg->r.DelResponse;
+       case LDAP_TAG_ModifyDNResponse:
+               return &msg->r.ModifyDNResponse;
+       case LDAP_TAG_CompareResponse:
+               return &msg->r.CompareResponse;
+       case LDAP_TAG_ExtendedResponse:
+               return &msg->r.ExtendedResponse.response;
+       }
+       return NULL;
+}
+
+static void server_has_data(struct winbind_ldap_server *server)
+{
+       struct ldap_message *msg;
+
+       if (!read_into_buf(server->sock, &server->in_buffer)) {
+               server->finished = True;
+               return;
+       }
+
+       while ((msg = get_msg_from_buf(&server->in_buffer,
+                                      &server->finished))) {
+               struct pending_ldap_message *pending;
+               struct rw_buffer *buf;
+               struct ldap_Result *res;
+
+               if (handled_locally(msg, server))
+                       continue;
+
+               res = ldap_msg2result(msg);
+
+               if ( (res != NULL) && (res->resultcode == 10) )
+                       DEBUG(5, ("Got Referral %s\n", res->referral));
+
+               for (pending = pending_messages;
+                    pending != NULL;
+                    pending = pending->next) {
+                       if (pending->our_msgid == msg->messageid)
+                               break;
+               }
+
+               if (pending == NULL) {
+                       talloc_destroy(msg->mem_ctx);
+                       continue;
+               }
+
+               msg->messageid = pending->msg->messageid;
+
+               buf = &pending->client->out_buffer;
+               ldap_append_to_buf(msg, buf);
+
+               if ( (msg->type != LDAP_TAG_SearchResultEntry) &&
+                    (msg->type != LDAP_TAG_SearchResultReference) ) {
+                       destroy_ldap_message(pending->msg);
+                       DLIST_REMOVE(pending_messages,
+                                    pending);
+                       SAFE_FREE(pending);
+               }
+               destroy_ldap_message(msg);
+       }
+}
+
+static void process_ldap_loop(void)
+{
+       struct winbind_ldap_client *client;
+       struct winbind_ldap_server *server;
+       fd_set r_fds, w_fds;
+       int maxfd, listen_sock, selret;
+       struct timeval timeout;
+
+       /* Free up temporary memory */
+
+       lp_talloc_free();
+       main_loop_talloc_free();
+
+       if (do_sigterm) {
+#if 0
+               TALLOC_CTX *mem_ctx = talloc_init("describe");
+               DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx)));
+               talloc_destroy(mem_ctx);
+#endif
+               exit(0);
+       }
+
+       /* Initialise fd lists for select() */
+
+       listen_sock = open_ldap_socket();
+
+       if (listen_sock == -1) {
+               perror("open_ldap_socket");
+               exit(1);
+       }
+
+       maxfd = listen_sock;
+
+       FD_ZERO(&r_fds);
+       FD_ZERO(&w_fds);
+       FD_SET(listen_sock, &r_fds);
+
+       timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+       timeout.tv_usec = 0;
+
+       /* Set up client readers and writers */
+       
+       client = ldap_clients;
+
+       while (client != NULL) {
+
+               if (client->finished) {
+                       struct winbind_ldap_client *next = client->next;
+                       DLIST_REMOVE(ldap_clients, client);
+                       close(client->sock);
+                       SAFE_FREE(client->in_buffer.data);
+                       SAFE_FREE(client->out_buffer.data);
+                       SAFE_FREE(client);
+                       client = next;
+                       continue;
+               }
+
+               if (client->sock > maxfd)
+                       maxfd = client->sock;
+
+               FD_SET(client->sock, &r_fds);
+
+               if (client->out_buffer.length > 0)
+                       FD_SET(client->sock, &w_fds);
+
+               client = client->next;
+       }
+
+       /* And now the servers */
+
+       server = ldap_servers;
+
+       while (server != NULL) {
+
+               if (server->finished) {
+                       struct winbind_ldap_server *next = server->next;
+                       DLIST_REMOVE(ldap_servers, server);
+                       close(server->sock);
+                       SAFE_FREE(server);
+                       server = next;
+                       continue;
+               }
+
+               if (server->sock > maxfd)
+                       maxfd = server->sock;
+
+               FD_SET(server->sock, &r_fds);
+
+               if (server->out_buffer.length > 0)
+                       FD_SET(server->sock, &w_fds);
+
+               server = server->next;
+       }
+
+       selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+
+       if (selret == 0)
+               return;
+
+       if (selret == -1 && errno != EINTR) {
+               perror("select");
+               exit(1);
+       }
+
+       if (FD_ISSET(listen_sock, &r_fds))
+               new_ldap_client(listen_sock);
+
+       for (client = ldap_clients; client != NULL; client = client->next) {
+
+               if (FD_ISSET(client->sock, &r_fds))
+                       client_has_data(client);
+
+               if ((!client->finished) && FD_ISSET(client->sock, &w_fds))
+                       write_out_of_buf(client->sock, &client->out_buffer);
+       }
+
+       for (server = ldap_servers; server != NULL; server = server->next) {
+
+               if (FD_ISSET(server->sock, &r_fds))
+                       server_has_data(server);
+
+               if (!server->finished && FD_ISSET(server->sock, &w_fds))
+                       write_out_of_buf(server->sock, &server->out_buffer);
+       }
+}
+
+static BOOL setup_ldap_serverconn(void)
+{
+       char *host;
+       uint16 port;
+       BOOL ldaps;
+       struct hostent *hp;
+       struct in_addr ip;
+       TALLOC_CTX *mem_ctx = talloc_init("server");
+       struct ldap_message *msg;
+       char *dn, *pw;
+
+       ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);
+
+       if ((ldap_servers == NULL) || (mem_ctx == NULL))
+               return False;
+
+       if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",
+                                 &host, &port, &ldaps))
+               return False;
+       
+       hp = sys_gethostbyname(host);
+
+       if ((hp == NULL) || (hp->h_addr == NULL))
+               return False;
+
+       putip((char *)&ip, (char *)hp->h_addr);
+
+       ZERO_STRUCTP(ldap_servers);
+       ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);
+       ldap_servers->messageid = 1;
+
+       if (!fetch_ldap_pw(&dn, &pw))
+               return False;
+
+       msg = new_ldap_simple_bind_msg(dn, pw);
+
+       SAFE_FREE(dn);
+       SAFE_FREE(pw);
+
+       if (msg == NULL)
+               return False;
+
+       msg->messageid = ldap_servers->messageid++;
+
+       ldap_append_to_buf(msg, &ldap_servers->out_buffer);
+
+       destroy_ldap_message(msg);
+
+       return (ldap_servers->sock >= 0);
+}
+
+void do_ldap_proxy(void)
+{
+       int ldap_child;
+
+       ldap_child = sys_fork();
+
+       if (ldap_child != 0)
+               return;
+
+       /* tdb needs special fork handling */
+       if (tdb_reopen_all() == -1) {
+               DEBUG(0,("tdb_reopen_all failed.\n"));
+               _exit(0);
+       }
+
+       if (!message_init()) {
+               DEBUG(0, ("message_init failed\n"));
+               _exit(0);
+       }
+
+       CatchSignal(SIGINT, ldap_termination_handler);
+       CatchSignal(SIGQUIT, ldap_termination_handler);
+       CatchSignal(SIGTERM, ldap_termination_handler);
+
+       if (!setup_ldap_serverconn())
+               return;
+
+       while (1)
+               process_ldap_loop();
+
+       return;
+}
index bb30a7029e16247b0d79f38698dad47ead6ca0be..9cfa4c6fcc4eeb9c53401a63255609e4fa745fdf 100644 (file)
 /* Check the machine account password is valid */
 
 enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
+{
+       DEBUG(3, ("[%5lu]: check machine account\n",
+                 (unsigned long)state->pid));
+
+       async_domain_request(state->mem_ctx, find_our_domain(),
+                            &state->request, &state->response,
+                            request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
+                                                     struct winbindd_cli_state *state)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uchar trust_passwd[16];
         int num_retries = 0;
-        struct cli_state *cli;
-       uint32 sec_channel_type;
        struct winbindd_domain *contact_domain;
 
        DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
@@ -43,26 +52,22 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
        /* Get trust account password */
 
  again:
-       if (!secrets_fetch_trust_account_password(
-                   lp_workgroup(), trust_passwd, NULL, &sec_channel_type)) {
-               result = NT_STATUS_INTERNAL_ERROR;
-               goto done;
-       }
-
 
        contact_domain = find_our_domain();
-        if (!contact_domain) {
-               result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-                DEBUG(1, ("Cannot find our own domain!\n"));
-                goto done;
-        }
        
         /* This call does a cli_nt_setup_creds() which implicitly checks
            the trust account password. */
-       /* Don't shut this down - it belongs to the connection cache code */
-       
-        result = cm_get_netlogon_cli(contact_domain,
-               trust_passwd, sec_channel_type, True, &cli);
+
+       invalidate_cm_connection(&contact_domain->conn);
+
+       {
+               struct rpc_pipe_client *cli;
+               unsigned char *session_key;
+               DOM_CRED *creds;
+
+               result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+                                            &cli, &session_key, &creds);
+       }
 
         if (!NT_STATUS_IS_OK(result)) {
                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
@@ -100,108 +105,256 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
 
-enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
-                                                  *state)
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state)
 {
-       struct winbindd_domain *domain;
-       int total_entries = 0, extra_data_len = 0;
-       char *ted, *extra_data = NULL;
+       DEBUG(3, ("[%5lu]: list trusted domains\n",
+                 (unsigned long)state->pid));
+
+       async_domain_request(state->mem_ctx, find_our_domain(),
+                            &state->request, &state->response,
+                            request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
 
-       DEBUG(3, ("[%5lu]: list trusted domains\n", (unsigned long)state->pid));
+enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
+                                                       struct winbindd_cli_state *state)
+{
+       uint32 i, num_domains;
+       char **names, **alt_names;
+       DOM_SID *sids;
+       int extra_data_len = 0;
+       char *extra_data;
+       NTSTATUS result;
 
-       /* We need to refresh the trusted domain list as the domains may
-          have changed since we last looked.  There may be a sequence
-          number or something we should use but I haven't found it yet. */
+       DEBUG(3, ("[%5lu]: list trusted domains\n",
+                 (unsigned long)state->pid));
 
-       if (!init_domain_list()) {
-               DEBUG(1, ("winbindd_list_trusted_domains: could not "
-                         "refresh trusted domain list\n"));
-               return WINBINDD_ERROR;
+       result = domain->methods->trusted_domains(domain, state->mem_ctx,
+                                                 &num_domains, &names,
+                                                 &alt_names, &sids);
+
+       extra_data = talloc_strdup(state->mem_ctx, "");
+
+       if (num_domains > 0)
+               extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
+                                            names[0], alt_names[0],
+                                            sid_string_static(&sids[0]));
+
+       for (i=1; i<num_domains; i++)
+               extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
+                                            extra_data,
+                                            names[i], alt_names[i],
+                                            sid_string_static(&sids[i]));
+
+       /* This is a bit excessive, but the extra data sooner or later will be
+          talloc'ed */
+
+       extra_data_len = strlen(extra_data);
+
+       if (extra_data_len > 0) {
+               state->response.extra_data = SMB_STRDUP(extra_data);
+               state->response.length += extra_data_len+1;
        }
 
-       for(domain = domain_list(); domain; domain = domain->next) {
+       return WINBINDD_OK;
+}
 
-               /* Skip own domain */
+enum winbindd_result winbindd_getdcname(struct winbindd_cli_state *state)
+{
+       state->request.domain_name
+               [sizeof(state->request.domain_name)-1] = '\0';
 
-               if (domain->primary) continue;
+       DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+                 state->request.domain_name));
 
-               /* Add domain to list */
+       async_domain_request(state->mem_ctx, find_our_domain(),
+                            &state->request, &state->response,
+                            request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
 
-               total_entries++;
-               ted = SMB_REALLOC(extra_data, sizeof(fstring) * 
-                              total_entries);
+enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
+                                            struct winbindd_cli_state *state)
+{
+       fstring dcname_slash;
+       char *p;
+       struct rpc_pipe_client *cli;
+       NTSTATUS result;
 
-               if (!ted) {
-                       DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
-                       SAFE_FREE(extra_data);
-                       return WINBINDD_ERROR;
-               } else 
-                        extra_data = ted;
+       state->request.domain_name
+               [sizeof(state->request.domain_name)-1] = '\0';
 
-               memcpy(&extra_data[extra_data_len], domain->name,
-                      strlen(domain->name));
+       DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
+                 state->request.domain_name));
+
+       {
+               /* These var's can be ignored -- we're not requesting
+                  anything in the credential chain here */
+               unsigned char *session_key;
+               DOM_CRED *creds;
+               result = cm_connect_netlogon(domain, state->mem_ctx, &cli,
+                                            &session_key, &creds);
+       }
 
-               extra_data_len  += strlen(domain->name);
-               extra_data[extra_data_len++] = ',';
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(1, ("Can't contact our the NETLOGON pipe\n"));
+               return WINBINDD_ERROR;
        }
 
-       if (extra_data) {
-               if (extra_data_len > 1) 
-                        extra_data[extra_data_len - 1] = '\0';
-               state->response.extra_data = extra_data;
-               state->response.length += extra_data_len;
+       result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
+                                          state->request.domain_name,
+                                          dcname_slash);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
+               return WINBINDD_ERROR;
        }
 
+       p = dcname_slash;
+       if (*p == '\\') p+=1;
+       if (*p == '\\') p+=1;
+
+       fstrcpy(state->response.data.dc_name, p);
+
        return WINBINDD_OK;
 }
 
+struct sequence_state {
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_cli_state *cli_state;
+       struct winbindd_domain *domain;
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+       char *extra_data;
+};
+
+static void sequence_recv(void *private, BOOL success);
 
 enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
 {
-       struct winbindd_domain *domain;
-       char *extra_data = NULL;
-       const char *which_domain;
+       struct sequence_state *seq;
+
+       /* Ensure null termination */
+       state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
+
+       if (strlen(state->request.domain_name) > 0) {
+               struct winbindd_domain *domain;
+               domain = find_domain_from_name_noinit(
+                       state->request.domain_name);
+               if (domain == NULL)
+                       return WINBINDD_ERROR;
+               async_domain_request(state->mem_ctx, domain,
+                                    &state->request, &state->response,
+                                    request_finished_cont, state);
+               return WINBINDD_PENDING;
+       }
+
+       /* Ask all domains in sequence, collect the results in sequence_recv */
 
+       seq = TALLOC_P(state->mem_ctx, struct sequence_state);
+       if (seq == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               return WINBINDD_ERROR;
+       }
+
+       seq->mem_ctx = state->mem_ctx;
+       seq->cli_state = state;
+       seq->domain = domain_list();
+       if (seq->domain == NULL) {
+               DEBUG(0, ("domain list empty\n"));
+               return WINBINDD_ERROR;
+       }
+       seq->request = TALLOC_ZERO_P(state->mem_ctx,
+                                    struct winbindd_request);
+       seq->response = TALLOC_ZERO_P(state->mem_ctx,
+                                     struct winbindd_response);
+       seq->extra_data = talloc_strdup(state->mem_ctx, "");
+
+       if ((seq->request == NULL) || (seq->response == NULL) ||
+           (seq->extra_data == NULL)) {
+               DEBUG(0, ("talloc failed\n"));
+               return WINBINDD_ERROR;
+       }
+
+       seq->request->length = sizeof(*seq->request);
+       seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
+       fstrcpy(seq->request->domain_name, seq->domain->name);
+
+       async_domain_request(state->mem_ctx, seq->domain,
+                            seq->request, seq->response,
+                            sequence_recv, seq);
+       return WINBINDD_PENDING;
+}
+
+static void sequence_recv(void *private, BOOL success)
+{
+       struct sequence_state *state = private;
+       uint32 seq = DOM_SEQUENCE_NONE;
+
+       if ((success) && (state->response->result == WINBINDD_OK))
+               seq = state->response->data.domain_info.sequence_number;
+
+       if (seq == DOM_SEQUENCE_NONE) {
+               state->extra_data = talloc_asprintf(state->mem_ctx,
+                                                   "%s%s : DISCONNECTED\n",
+                                                   state->extra_data,
+                                                   state->domain->name);
+       } else {
+               state->extra_data = talloc_asprintf(state->mem_ctx,
+                                                   "%s%s : %d\n",
+                                                   state->extra_data,
+                                                   state->domain->name, seq);
+       }
+
+       state->domain->sequence_number = seq;
+
+       state->domain = state->domain->next;
+
+       if (state->domain == NULL) {
+               struct winbindd_cli_state *cli_state = state->cli_state;
+               cli_state->response.result = WINBINDD_OK;
+               cli_state->response.length =
+                       sizeof(cli_state->response) +
+                       strlen(state->extra_data) + 1;
+               cli_state->response.extra_data =
+                       SMB_STRDUP(state->extra_data);
+               request_finished(cli_state);
+               return;
+       }
+
+       /* Ask the next domain */
+       fstrcpy(state->request->domain_name, state->domain->name);
+       async_domain_request(state->mem_ctx, state->domain,
+                            state->request, state->response,
+                            sequence_recv, state);
+}
+
+/* This is the child-only version of --sequence. It only allows for a single
+ * domain (ie "our" one) to be displayed. */
+
+enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
+                                                struct winbindd_cli_state *state)
+{
        DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
 
        /* Ensure null termination */
-       state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';  
-       which_domain = state->request.domain_name;
-
-       extra_data = SMB_STRDUP("");
-
-       /* this makes for a very simple data format, and is easily parsable as well
-          if that is ever needed */
-       for (domain = domain_list(); domain; domain = domain->next) {
-               char *s;
-
-               /* if we have a domain name restricting the request and this
-                  one in the list doesn't match, then just bypass the remainder
-                  of the loop */
-
-               if ( *which_domain && !strequal(which_domain, domain->name) )
-                       continue;
-
-               domain->methods->sequence_number(domain, &domain->sequence_number);
-               
-               if (DOM_SEQUENCE_NONE == (unsigned)domain->sequence_number) {
-                       asprintf(&s,"%s%s : DISCONNECTED\n", extra_data, 
-                                domain->name);
-               } else {
-                       asprintf(&s,"%s%s : %u\n", extra_data, 
-                                domain->name, (unsigned)domain->sequence_number);
-               }
-               free(extra_data);
-               extra_data = s;
-       }
+       state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
 
-       state->response.extra_data = extra_data;
-       /* must add one to length to copy the 0 for string termination */
-       state->response.length += strlen(extra_data) + 1;
+       domain->methods->sequence_number(domain, &domain->sequence_number);
+
+       state->response.data.domain_info.sequence_number =
+               domain->sequence_number;
 
        return WINBINDD_OK;
 }
 
+struct domain_info_state {
+       struct winbindd_domain *domain;
+       struct winbindd_cli_state *cli_state;
+};
+
+static void domain_info_init_recv(void *private, BOOL success);
+
 enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
@@ -209,7 +362,7 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
                  state->request.domain_name));
 
-       domain = find_domain_from_name(state->request.domain_name);
+       domain = find_domain_from_name_noinit(state->request.domain_name);
 
        if (domain == NULL) {
                DEBUG(3, ("Did not find domain [%s]\n",
@@ -217,21 +370,78 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
        }
 
-       fstrcpy(state->response.data.domain_info.name, domain->name);
-       fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
+       if (!domain->initialized) {
+               struct domain_info_state *istate;
+
+               istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
+               if (istate == NULL) {
+                       DEBUG(0, ("talloc failed\n"));
+                       return WINBINDD_ERROR;
+               }
+
+               istate->cli_state = state;
+               istate->domain = domain;
+
+               init_child_connection(domain, domain_info_init_recv, istate);
+                                     
+               return WINBINDD_PENDING;
+       }
+
+       fstrcpy(state->response.data.domain_info.name,
+               domain->name);
+       fstrcpy(state->response.data.domain_info.alt_name,
+               domain->alt_name);
        fstrcpy(state->response.data.domain_info.sid,
                sid_string_static(&domain->sid));
        
-       state->response.data.domain_info.native_mode = domain->native_mode;
-       state->response.data.domain_info.active_directory = domain->active_directory;
-       state->response.data.domain_info.primary = domain->primary;
-
+       state->response.data.domain_info.native_mode =
+               domain->native_mode;
+       state->response.data.domain_info.active_directory =
+               domain->active_directory;
+       state->response.data.domain_info.primary =
+               domain->primary;
        state->response.data.domain_info.sequence_number =
                domain->sequence_number;
 
        return WINBINDD_OK;
 }
 
+static void domain_info_init_recv(void *private, BOOL success)
+{
+       struct domain_info_state *istate = private;
+       struct winbindd_cli_state *state = istate->cli_state;
+       struct winbindd_domain *domain = istate->domain;
+
+       DEBUG(10, ("Got back from child init: %d\n", success));
+
+       if ((!success) || (!domain->initialized)) {
+               DEBUG(5, ("Could not init child for domain %s\n",
+                         domain->name));
+               state->response.result = WINBINDD_ERROR;
+               request_finished_cont(state, False);
+               return;
+       }
+
+       fstrcpy(state->response.data.domain_info.name,
+               domain->name);
+       fstrcpy(state->response.data.domain_info.alt_name,
+               domain->alt_name);
+       fstrcpy(state->response.data.domain_info.sid,
+               sid_string_static(&domain->sid));
+       
+       state->response.data.domain_info.native_mode =
+               domain->native_mode;
+       state->response.data.domain_info.active_directory =
+               domain->active_directory;
+       state->response.data.domain_info.primary =
+               domain->primary;
+       state->response.data.domain_info.sequence_number =
+               domain->sequence_number;
+
+       state->response.result = WINBINDD_OK;
+       request_finished_cont(state, True);
+}
+
 enum winbindd_result winbindd_ping(struct winbindd_cli_state
                                                   *state)
 {
index 88645e093b434b921ac6a5e62d36cf10c212813d..b249b62d69eed3dd14252ed12fe7b2e350ea1acc 100644 (file)
@@ -34,7 +34,7 @@
 
 /* Update this when you change the interface.  */
 
-#define WINBIND_INTERFACE_VERSION 10
+#define WINBIND_INTERFACE_VERSION 11
 
 /* Socket commands */
 
@@ -83,6 +83,7 @@ enum winbindd_cmd {
        WINBINDD_UID_TO_SID,
        WINBINDD_GID_TO_SID,
        WINBINDD_ALLOCATE_RID,
+       WINBINDD_ALLOCATE_RID_AND_GID,
 
        /* Miscellaneous other stuff */
 
@@ -93,6 +94,7 @@ enum winbindd_cmd {
 
        WINBINDD_DOMAIN_INFO,   /* Most of what we know from
                                   struct winbindd_domain */
+       WINBINDD_GETDCNAME,     /* Issue a GetDCName Request */
 
        WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
 
@@ -110,9 +112,29 @@ enum winbindd_cmd {
        WINBINDD_PRIV_PIPE_DIR,
 
        /* return a list of group sids for a user sid */
-       WINBINDD_GETUSERSIDS,   
+       WINBINDD_GETUSERSIDS,
+
+       /* Return the domain groups a user is in */
+       WINBINDD_GETUSERDOMGROUPS,
+
+       /* Initialize connection in a child */
+       WINBINDD_INIT_CONNECTION,
+
+       /* Blocking calls that are not allowed on the main winbind pipe, only
+        * between parent and children */
+       WINBINDD_DUAL_SID2UID,
+       WINBINDD_DUAL_SID2GID,
+       WINBINDD_DUAL_IDMAPSET,
+
+       /* Wrapper around possibly blocking unix nss calls */
+       WINBINDD_DUAL_UID2NAME,
+       WINBINDD_DUAL_NAME2UID,
+       WINBINDD_DUAL_GID2NAME,
+       WINBINDD_DUAL_NAME2GID,
+
+       WINBINDD_DUAL_USERINFO,
+       WINBINDD_DUAL_GETSIDALIASES,
 
-       /* Placeholder for end of cmd list */
        WINBINDD_NUM_CMDS
 };
 
@@ -148,6 +170,9 @@ typedef struct winbindd_gr {
 #define WBFLAG_PAM_AFS_TOKEN            0x0100
 #define WBFLAG_PAM_NT_STATUS_SQUASH     0x0200
 
+/* This is a flag that can only be sent from parent to child */
+#define WBFLAG_IS_PRIVILEGED            0x0400
+
 /* Winbind request structure */
 
 struct winbindd_request {
@@ -156,6 +181,7 @@ struct winbindd_request {
        pid_t pid;               /* pid of calling process */
        uint32 flags;            /* flags relavant to a given request */
        fstring domain_name;    /* name of domain for which the request applies */
+       int msgid;
 
        union {
                fstring winsreq;     /* WINS request */
@@ -197,6 +223,24 @@ struct winbindd_request {
                        fstring username;
                        fstring groupname;
                } acct_mgt;
+               struct {
+                       BOOL is_primary;
+                       fstring dcname;
+               } init_conn;
+               struct {
+                       fstring sid;
+                       fstring name;
+                       BOOL alloc;
+               } dual_sid2id;
+               struct {
+                       int type;
+                       uid_t uid;
+                       gid_t gid;
+                       fstring sid;
+               } dual_idmapset;
+               struct {
+                       fstring cache_key;
+               } dual_sidaliases;
        } data;
        char null_term;
 };
@@ -205,6 +249,7 @@ struct winbindd_request {
 
 enum winbindd_result {
        WINBINDD_ERROR,
+       WINBINDD_PENDING,
        WINBINDD_OK
 };
 
@@ -250,6 +295,7 @@ struct winbindd_response {
                } info;
                fstring domain_name;
                fstring netbios_name;
+               fstring dc_name;
 
                struct auth_reply {
                        uint32 nt_status;
@@ -260,6 +306,10 @@ struct winbindd_response {
                        char first_8_lm_hash[8];
                } auth;
                uint32 rid;     /* create user or group or allocate rid */
+               struct {
+                       uint32 rid;
+                       gid_t gid;
+               } rid_and_gid;
                struct {
                        fstring name;
                        fstring alt_name;
@@ -269,6 +319,11 @@ struct winbindd_response {
                        BOOL primary;
                        uint32 sequence_number;
                } domain_info;
+               struct {
+                       fstring acct_name;
+                       fstring full_name;
+                       uint32 group_rid;
+               } user_info;
        } data;
 
        /* Variable length return data */
index 90613911182734712440b65f3fd9153f8d46e888..97dc35c0e7e2ded1981898b3c597f35d7f549af0 100644 (file)
@@ -145,24 +145,99 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
        return NT_STATUS_LOGON_FAILURE;
 }
 
+static struct winbindd_domain *find_auth_domain(const char *domain_name)
+{
+       struct winbindd_domain *domain;
+
+       if (IS_DC) {
+               domain = find_domain_from_name_noinit(domain_name);
+               if (domain == NULL) {
+                       DEBUG(3, ("Authentication for domain [%s] "
+                                 "as it is not a trusted domain\n", 
+                                 domain_name));
+               }
+               return domain;
+       }
+
+       if (is_myname(domain_name)) {
+               DEBUG(3, ("Authentication for domain %s (local domain "
+                         "to this server) not supported at this "
+                         "stage\n", domain_name));
+               return NULL;
+       }
+
+       return find_our_domain();
+}
+
+static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
+{
+       resp->data.auth.nt_status = NT_STATUS_V(result);
+       fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
+
+       /* we might have given a more useful error above */
+       if (*resp->data.auth.error_string == '\0') 
+               fstrcpy(resp->data.auth.error_string,
+                       get_friendly_nt_error_msg(result));
+       resp->data.auth.pam_error = nt_status_to_pam(result);
+}
+
 /**********************************************************************
  Authenticate a user with a clear text password
 **********************************************************************/
 
-enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) 
+enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
+{
+       struct winbindd_domain *domain;
+       fstring name_domain, name_user;
+
+       /* Ensure null termination */
+       state->request.data.auth.user
+               [sizeof(state->request.data.auth.user)-1]='\0';
+
+       /* Ensure null termination */
+       state->request.data.auth.pass
+               [sizeof(state->request.data.auth.pass)-1]='\0';
+
+       DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
+                 state->request.data.auth.user));
+
+       /* Parse domain and username */
+       
+       parse_domain_user(state->request.data.auth.user,
+                         name_domain, name_user);
+
+       domain = find_auth_domain(name_domain);
+
+       if (domain == NULL) {
+               set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
+               DEBUG(5, ("Plain text authentication for %s returned %s "
+                         "(PAM: %d)\n",
+                         state->request.data.auth.user, 
+                         state->response.data.auth.nt_status_string,
+                         state->response.data.auth.pam_error));
+               return WINBINDD_ERROR;
+       }
+
+       async_domain_request(state->mem_ctx, domain,
+                            &state->request, &state->response,
+                            request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state) 
 {
        NTSTATUS result;
        fstring name_domain, name_user;
-       unsigned char trust_passwd[16];
-       time_t last_change_time;
-       uint32 sec_channel_type;
+       const char *srv_name_slash;
         NET_USER_INFO_3 info3;
-        struct cli_state *cli = NULL;
+       unsigned char *session_key;
+       struct rpc_pipe_client *pipe_cli;
        uchar chal[8];
-       TALLOC_CTX *mem_ctx = NULL;
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
        DOM_CRED ret_creds;
+       DOM_CRED *credentials;
        int attempts = 0;
        unsigned char local_lm_response[24];
        unsigned char local_nt_response[24];
@@ -178,12 +253,6 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
                  state->request.data.auth.user));
 
-       if (!(mem_ctx = talloc_init("winbind pam auth for %s", state->request.data.auth.user))) {
-               DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n"));
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
        /* Parse domain and username */
        
        parse_domain_user(state->request.data.auth.user, name_domain, name_user);
@@ -197,7 +266,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                DATA_BLOB names_blob;
                DATA_BLOB nt_response;
                DATA_BLOB lm_response;
-               server_chal = data_blob_talloc(mem_ctx, chal, 8); 
+               server_chal = data_blob_talloc(state->mem_ctx, chal, 8); 
                
                /* note that the 'workgroup' here is a best guess - we don't know
                   the server's domain at this point.  The 'server name' is also
@@ -218,8 +287,10 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                }
                data_blob_free(&names_blob);
                data_blob_free(&server_chal);
-               lm_resp = data_blob_talloc(mem_ctx, lm_response.data, lm_response.length);
-               nt_resp = data_blob_talloc(mem_ctx, nt_response.data, nt_response.length);
+               lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
+                                          lm_response.length);
+               nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
+                                          nt_response.length);
                data_blob_free(&lm_response);
                data_blob_free(&nt_response);
 
@@ -228,7 +299,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                    && SMBencrypt(state->request.data.auth.pass, 
                                  chal, 
                                  local_lm_response)) {
-                       lm_resp = data_blob_talloc(mem_ctx, 
+                       lm_resp = data_blob_talloc(state->mem_ctx, 
                                                   local_lm_response, 
                                                   sizeof(local_lm_response));
                } else {
@@ -238,7 +309,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                             chal,
                             local_nt_response);
 
-               nt_resp = data_blob_talloc(mem_ctx, 
+               nt_resp = data_blob_talloc(state->mem_ctx, 
                                           local_nt_response, 
                                           sizeof(local_nt_response));
        }
@@ -261,80 +332,95 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                        goto done;
                }
 
-               if (!(contact_domain = find_our_domain())) {
-                       DEBUG(1, ("Authentication for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n", 
-                                 state->request.data.auth.user, name_domain, name_user)); 
-                       result = NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
+               contact_domain = find_our_domain();
        }
 
-       if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
-               result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-               goto done;
+       srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
+                                        contact_domain->dcname);
+       if (srv_name_slash == NULL) {
+               DEBUG(0, ("talloc_asprintf failed\n"));
+               return WINBINDD_ERROR;
        }
-
+               
        /* check authentication loop */
 
        do {
+               DOM_CRED clnt_creds;
+
                ZERO_STRUCT(info3);
                ZERO_STRUCT(ret_creds);
                retry = False;
-       
-               /* Don't shut this down - it belongs to the connection cache code */
-               result = cm_get_netlogon_cli(contact_domain, trust_passwd, 
-                                            sec_channel_type, False, &cli);
+
+               result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+                                            &pipe_cli, &session_key,
+                                            &credentials);
 
                if (!NT_STATUS_IS_OK(result)) {
                        DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
                        goto done;
                }
 
-               result = cli_netlogon_sam_network_logon(cli, mem_ctx,
-                                                       &ret_creds,
-                                                       name_user, name_domain, 
-                                                       global_myname(), chal, 
-                                                       lm_resp, nt_resp,
-                                                       &info3);
+               credentials->timestamp.time = time(NULL);
+               memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
+
+               /* Calculate the new credentials. */
+               cred_create(session_key, &credentials->challenge,
+                           clnt_creds.timestamp, &(clnt_creds.challenge));
+
+               result = rpccli_netlogon_sam_network_logon(pipe_cli,
+                                                          state->mem_ctx,
+                                                          srv_name_slash,
+                                                          &clnt_creds,
+                                                          &ret_creds,
+                                                          name_user,
+                                                          name_domain, 
+                                                          global_myname(),
+                                                          chal, lm_resp,
+                                                          nt_resp, &info3,
+                                                          session_key);
                attempts += 1;
-               
-               /* We have to try a second time as cm_get_netlogon_cli
+
+               /* We have to try a second time as cm_connect_netlogon
                   might not yet have noticed that the DC has killed
                   our connection. */
 
-               if ( cli->fd == -1 ) {
+               if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
                        retry = True;
                        continue;
-               } 
+               }
                
-               /* if we get access denied, a possible cuase was that we had and open
-                  connection to the DC, but someone changed our machine account password
-                  out from underneath us using 'net rpc changetrustpw' */
+               /* if we get access denied, a possible cause was that we had
+                  and open connection to the DC, but someone changed our
+                  machine account password out from underneath us using 'net
+                  rpc changetrustpw' */
                   
-               if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
-                       DEBUG(3,("winbindd_pam_auth: sam_logon returned ACCESS_DENIED.  Maybe the trust account "
-                               "password was changed and we didn't know it.  Killing connections to domain %s\n",
+               if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+                       DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+                                "ACCESS_DENIED.  Maybe the trust account "
+                               "password was changed and we didn't know it. "
+                                "Killing connections to domain %s\n",
                                name_domain));
-                       winbindd_cm_flush();
+                       invalidate_cm_connection(&contact_domain->conn);
                        retry = True;
-                       cli = NULL;
                } 
                
        } while ( (attempts < 2) && retry );
 
-        if (cli != NULL) {
-               /* We might have come out of the loop above with cli == NULL,
-                  so don't dereference that. */
-               clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
+       if (NT_STATUS_IS_OK(result) &&
+           (!clnt_deal_with_creds(session_key, credentials,
+                                 &ret_creds))) {
+               DEBUG(3, ("DC %s sent wrong credentials\n",
+                         pipe_cli->cli->srv_name_slash));
+               result = NT_STATUS_ACCESS_DENIED;
        }
-       
+
        if (NT_STATUS_IS_OK(result)) {
-               netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
+               netsamlogon_cache_store(state->mem_ctx, name_user, &info3);
                wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
 
                /* Check if the user is in the right group */
 
-               if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
+               if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
                        DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
                                  state->request.data.auth.user, 
                                  state->request.data.auth.require_membership_of_sid));
@@ -407,9 +493,6 @@ done:
                SAFE_FREE(afsname);
        }
                
-       if (mem_ctx) 
-               talloc_destroy(mem_ctx);
-       
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
 
@@ -417,15 +500,79 @@ done:
  Challenge Response Authentication Protocol 
 **********************************************************************/
 
-enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) 
+enum winbindd_result winbindd_crap_auth(struct winbindd_cli_state *state)
 {
+       struct winbindd_domain *domain = NULL;
+       const char *domain_name = NULL;
        NTSTATUS result;
-       unsigned char trust_passwd[16];
-       time_t last_change_time;
-       uint32 sec_channel_type;
+
+       if (!state->privileged) {
+               char *error_string = NULL;
+               DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
+                         "denied.  !\n"));
+               DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
+                            "on %s are set correctly.\n",
+                            get_winbind_priv_pipe_dir()));
+               /* send a better message than ACCESS_DENIED */
+               error_string = talloc_asprintf(state->mem_ctx,
+                                              "winbind client not authorized "
+                                              "to use winbindd_pam_auth_crap."
+                                              " Ensure permissions on %s "
+                                              "are set correctly.",
+                                              get_winbind_priv_pipe_dir());
+               fstrcpy(state->response.data.auth.error_string, error_string);
+               result = NT_STATUS_ACCESS_DENIED;
+               goto done;
+       }
+
+       /* Ensure null termination */
+       state->request.data.auth_crap.user
+               [sizeof(state->request.data.auth_crap.user)-1]=0;
+       state->request.data.auth_crap.domain
+               [sizeof(state->request.data.auth_crap.domain)-1]=0;
+
+       DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
+                 (unsigned long)state->pid,
+                 state->request.data.auth_crap.domain,
+                 state->request.data.auth_crap.user));
+
+       if (*state->request.data.auth_crap.domain != '\0') {
+               domain_name = state->request.data.auth_crap.domain;
+       } else if (lp_winbind_use_default_domain()) {
+               domain_name = lp_workgroup();
+       }
+
+       if (domain_name != NULL)
+               domain = find_auth_domain(domain_name);
+
+       if (domain != NULL) {
+               async_domain_request(state->mem_ctx, domain,
+                                    &state->request, &state->response,
+                                    request_finished_cont, state);
+               return WINBINDD_PENDING;
+       }
+
+       result = NT_STATUS_NO_SUCH_USER;
+
+ done:
+       set_auth_errors(&state->response, result);
+       DEBUG(5, ("CRAP authentication for %s returned %s (PAM: %d)\n",
+                 state->request.data.auth.user, 
+                 state->response.data.auth.nt_status_string,
+                 state->response.data.auth.pam_error));
+       return WINBINDD_ERROR;
+}
+
+
+enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
+                                                struct winbindd_cli_state *state) 
+{
+       NTSTATUS result;
+       const char *srv_name_slash;
         NET_USER_INFO_3 info3;
-        struct cli_state *cli = NULL;
-       TALLOC_CTX *mem_ctx = NULL;
+       unsigned char *session_key;
+       struct rpc_pipe_client *pipe_cli;
+       DOM_CRED *credentials;
        const char *name_user = NULL;
        const char *name_domain = NULL;
        const char *workstation;
@@ -436,30 +583,13 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
 
        DATA_BLOB lm_resp, nt_resp;
 
-       if (!state->privileged) {
-               char *error_string = NULL;
-               DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied.  !\n"));
-               DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions on %s are set correctly.\n", 
-                            get_winbind_priv_pipe_dir()));
-               /* send a better message than ACCESS_DENIED */
-               asprintf(&error_string, "winbind client not authorized to use winbindd_pam_auth_crap.  Ensure permissions on %s are set correctly.",
-                        get_winbind_priv_pipe_dir());
-               fstrcpy(state->response.data.auth.error_string, error_string);
-               SAFE_FREE(error_string);
-               result =  NT_STATUS_ACCESS_DENIED;
-               goto done;
-       }
+       /* This is child-only, so no check for privileged access is needed
+          anymore */
 
        /* Ensure null termination */
        state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
        state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
 
-       if (!(mem_ctx = talloc_init("winbind pam auth crap for %s", state->request.data.auth_crap.user))) {
-               DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
        name_user = state->request.data.auth_crap.user;
 
        if (*state->request.data.auth_crap.domain) {
@@ -491,8 +621,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                goto done;
        }
 
-       lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
-       nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
+       lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
+       nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
        
 
        /* what domain should we contact? */
@@ -512,26 +642,25 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                        goto done;
                }
 
-               if (!(contact_domain = find_our_domain())) {
-                       DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n", 
-                                 state->request.data.auth_crap.user, name_domain, name_user)); 
-                       result = NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
-       }
-               
-       if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
-               result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-               goto done;
+               contact_domain = find_our_domain();
        }
 
+       srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
+                                        contact_domain->dcname);
+       if (srv_name_slash == NULL) {
+               DEBUG(0, ("talloc_asprintf failed\n"));
+               return WINBINDD_ERROR;
+       }
+               
        do {
+               DOM_CRED clnt_creds;
                ZERO_STRUCT(info3);
                ZERO_STRUCT(ret_creds);
                retry = False;
 
-               /* Don't shut this down - it belongs to the connection cache code */
-               result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli);
+               result = cm_connect_netlogon(contact_domain, state->mem_ctx,
+                                            &pipe_cli, &session_key,
+                                            &credentials);
 
                if (!NT_STATUS_IS_OK(result)) {
                        DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
@@ -539,51 +668,66 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                        goto done;
                }
 
-               result = cli_netlogon_sam_network_logon(cli, mem_ctx,
-                                                       &ret_creds,
-                                                       name_user, name_domain,
-                                                       workstation,
-                                                       state->request.data.auth_crap.chal, 
-                                                       lm_resp, nt_resp, 
-                                                       &info3);
+               credentials->timestamp.time = time(NULL);
+               memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
+
+               /* Calculate the new credentials. */
+               cred_create(session_key, &credentials->challenge,
+                           clnt_creds.timestamp, &(clnt_creds.challenge));
+
+               result = rpccli_netlogon_sam_network_logon(pipe_cli,
+                                                          state->mem_ctx,
+                                                          srv_name_slash,
+                                                          &clnt_creds,
+                                                          &ret_creds,
+                                                          name_user,
+                                                          name_domain, 
+                                                          global_myname(),
+                                                          state->request.data.auth_crap.chal,
+                                                          lm_resp,
+                                                          nt_resp, &info3,
+                                                          session_key);
 
                attempts += 1;
 
-               /* We have to try a second time as cm_get_netlogon_cli
+               /* We have to try a second time as cm_connect_netlogon
                   might not yet have noticed that the DC has killed
                   our connection. */
 
-               if ( cli->fd == -1 ) {
+               if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
                        retry = True;
                        continue;
-               } 
+               }
 
                /* if we get access denied, a possible cause was that we had and open
                   connection to the DC, but someone changed our machine account password
                   out from underneath us using 'net rpc changetrustpw' */
                   
-               if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
-                       DEBUG(3,("winbindd_pam_auth_crap: sam_logon returned ACCESS_DENIED.  Maybe the trust account "
-                               "password was changed and we didn't know it.  Killing connections to domain %s\n",
-                               contact_domain->name));
-                       winbindd_cm_flush();
+               if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+                       DEBUG(3,("winbindd_pam_auth: sam_logon returned "
+                                "ACCESS_DENIED.  Maybe the trust account "
+                               "password was changed and we didn't know it. "
+                                "Killing connections to domain %s\n",
+                               name_domain));
+                       invalidate_cm_connection(&contact_domain->conn);
                        retry = True;
-                       cli = NULL;
                } 
-               
+
        } while ( (attempts < 2) && retry );
 
-       if (cli != NULL) {
-               /* We might have come out of the loop above with cli == NULL,
-                  so don't dereference that. */
-               clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
+       if (NT_STATUS_IS_OK(result) &&
+           (!clnt_deal_with_creds(session_key, credentials,
+                                 &ret_creds))) {
+               DEBUG(3, ("DC %s sent wrong credentials\n",
+                         pipe_cli->cli->srv_name_slash));
+               result = NT_STATUS_ACCESS_DENIED;
        }
 
        if (NT_STATUS_IS_OK(result)) {
-               netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
+               netsamlogon_cache_store( state->mem_ctx, name_user, &info3 );
                wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
                
-               if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
+               if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
                        DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
                                  state->request.data.auth_crap.user, 
                                  state->request.data.auth_crap.require_membership_of_sid));
@@ -591,19 +735,19 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                }
 
                if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
-                       result = append_info3_as_ndr(mem_ctx, state, &info3);
+                       result = append_info3_as_ndr(state->mem_ctx, state, &info3);
                } else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
                        /* ntlm_auth should return the unix username, per 
                           'winbind use default domain' settings and the like */
                        
                        fstring username_out;
                        const char *nt_username, *nt_domain;
-                       if (!(nt_username = unistr2_tdup(mem_ctx, &(info3.uni_user_name)))) {
+                       if (!(nt_username = unistr2_tdup(state->mem_ctx, &(info3.uni_user_name)))) {
                                /* If the server didn't give us one, just use the one we sent them */
                                nt_username = name_user;
                        }
                        
-                       if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3.uni_logon_dom)))) {
+                       if (!(nt_domain = unistr2_tdup(state->mem_ctx, &(info3.uni_logon_dom)))) {
                                /* If the server didn't give us one, just use the one we sent them */
                                nt_domain = name_domain;
                        }
@@ -653,9 +797,6 @@ done:
               state->response.data.auth.nt_status_string,
               state->response.data.auth.pam_error));         
 
-       if (mem_ctx) 
-               talloc_destroy(mem_ctx);
-       
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
 
@@ -666,20 +807,13 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
        NTSTATUS result;
        char *oldpass, *newpass;
        fstring domain, user;
-       CLI_POLICY_HND *hnd;
-       TALLOC_CTX *mem_ctx;
+       POLICY_HND dom_pol;
        struct winbindd_domain *contact_domain;
+       struct rpc_pipe_client *cli;
 
        DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
                state->request.data.chauthtok.user));
 
-       if (!(mem_ctx = talloc_init("winbind password change for %s", 
-                                   state->request.data.chauthtok.user))) {
-               DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
        /* Setup crap */
 
        if (state == NULL)
@@ -701,12 +835,15 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
 
        /* Get sam handle */
 
-       if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(contact_domain, &hnd)) ) {
+       result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
+                               &dom_pol);
+       if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
                goto done;
        }
 
-       result = cli_samr_chgpasswd_user(hnd->cli, mem_ctx, user, newpass, oldpass);
+       result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass,
+                                           oldpass);
 
 done:    
        state->response.data.auth.nt_status = NT_STATUS_V(result);
@@ -721,8 +858,5 @@ done:
               state->response.data.auth.nt_status_string,
               state->response.data.auth.pam_error));         
 
-       if (mem_ctx)
-               talloc_destroy(mem_ctx);
-
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
index f0484d35eeffa9e718ab5ca4152862e672b9c2fe..4b22712e0ac83df6fb97b525608af9ad16bec966 100644 (file)
@@ -57,7 +57,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
        enum SID_NAME_USE type;
 
        uint32 num_names;
-       DOM_SID **sid_mem;
+       DOM_SID *sid_mem;
        char **names;
        uint32 *types;
 
@@ -126,7 +126,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
 
        for (i=0; i<num_names; i++) {
                DEBUG(10, ("Adding group member SID %s\n",
-                          sid_string_static(sid_mem[i])));
+                          sid_string_static(&sid_mem[i])));
 
                if (types[i] != SID_NAME_USER) {
                        DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
@@ -297,24 +297,29 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
                                  const DOM_SID *user_sid,
-                                 uint32 *num_groups, DOM_SID ***user_gids)
+                                 uint32 *num_groups, DOM_SID **user_gids)
 {
        return NT_STATUS_NO_SUCH_USER;
 }
 
 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
                                   TALLOC_CTX *mem_ctx,
-                                  uint32 num_sids, DOM_SID **sids,
-                                  uint32 *num_aliases, uint32 **aliases)
+                                  uint32 num_sids, const DOM_SID *sids,
+                                  uint32 *num_aliases, uint32 **rids)
 {
-       return NT_STATUS_NO_SUCH_USER;
+       BOOL result;
+
+       result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
+                                           sids, num_sids, rids, num_aliases);
+
+       return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
 }
 
 /* Lookup group membership given a rid.   */
 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                const DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID ***sid_mem, char ***names, 
+                               DOM_SID **sid_mem, char ***names, 
                                uint32 **name_types)
 {
        return NT_STATUS_OK;
diff --git a/source/nsswitch/winbindd_reconnect.c b/source/nsswitch/winbindd_reconnect.c
new file mode 100644 (file)
index 0000000..1a90717
--- /dev/null
@@ -0,0 +1,273 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Wrapper around winbindd_rpc.c to centralize retry logic.
+
+   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.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods msrpc_methods;
+
+/* List all users */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               uint32 *num_entries, 
+                               WINBIND_USERINFO **info)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.query_user_list(domain, mem_ctx,
+                                              num_entries, info);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.query_user_list(domain, mem_ctx,
+                                                      num_entries, info);
+       return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               uint32 *num_entries, 
+                               struct acct_info **info)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+                                              num_entries, info);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
+                                                      num_entries, info);
+       return result;
+}
+
+/* List all domain groups */
+
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint32 *num_entries, 
+                                 struct acct_info **info)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+                                                num_entries, info);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.enum_local_groups(domain, mem_ctx,
+                                                        num_entries, info);
+
+       return result;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const char *domain_name,
+                           const char *name,
+                           DOM_SID *sid,
+                           enum SID_NAME_USE *type)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.name_to_sid(domain, mem_ctx,
+                                          domain_name, name,
+                                          sid, type);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.name_to_sid(domain, mem_ctx,
+                                                  domain_name, name,
+                                                  sid, type);
+
+       return result;
+}
+
+/*
+  convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const DOM_SID *sid,
+                           char **domain_name,
+                           char **name,
+                           enum SID_NAME_USE *type)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+                                          domain_name, name, type);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
+                                                  domain_name, name, type);
+
+       return result;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain, 
+                          TALLOC_CTX *mem_ctx, 
+                          const DOM_SID *user_sid,
+                          WINBIND_USERINFO *user_info)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+                                         user_info);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
+                                                 user_info);
+
+       return result;
+}
+
+/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 const DOM_SID *user_sid,
+                                 uint32 *num_groups, DOM_SID **user_gids)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+                                                user_sid, num_groups,
+                                                user_gids);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
+                                                        user_sid, num_groups,
+                                                        user_gids);
+
+       return result;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+                                  TALLOC_CTX *mem_ctx,
+                                  uint32 num_sids, const DOM_SID *sids,
+                                  uint32 *num_aliases, uint32 **alias_rids)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+                                                 num_sids, sids,
+                                                 num_aliases,
+                                                 alias_rids);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
+                                                         num_sids, sids,
+                                                         num_aliases,
+                                                         alias_rids);
+
+       return result;
+}
+
+/* Lookup group membership given a rid.   */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               const DOM_SID *group_sid, uint32 *num_names, 
+                               DOM_SID **sid_mem, char ***names, 
+                               uint32 **name_types)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+                                              group_sid, num_names,
+                                              sid_mem, names,
+                                              name_types);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
+                                                      group_sid, num_names,
+                                                      sid_mem, names,
+                                                      name_types);
+
+       return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.sequence_number(domain, seq);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.sequence_number(domain, seq);
+
+       return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               uint32 *num_domains,
+                               char ***names,
+                               char ***alt_names,
+                               DOM_SID **dom_sids)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.trusted_domains(domain, mem_ctx,
+                                              num_domains, names,
+                                              alt_names, dom_sids);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.trusted_domains(domain, mem_ctx,
+                                                      num_domains, names,
+                                                      alt_names, dom_sids);
+
+       return result;
+}
+
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+       NTSTATUS result;
+
+       result = msrpc_methods.alternate_name(domain);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
+               result = msrpc_methods.alternate_name(domain);
+
+       return result;
+}
+
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods reconnect_methods = {
+       False,
+       query_user_list,
+       enum_dom_groups,
+       enum_local_groups,
+       name_to_sid,
+       sid_to_name,
+       query_user,
+       lookup_usergroups,
+       lookup_useraliases,
+       lookup_groupmem,
+       sequence_number,
+       trusted_domains,
+       alternate_name
+};
index 854688da4e8cd67c18d45ad6c2aa5050037ff01d..2b4c020d889a54e82245a8b52735fb3268738259 100644 (file)
@@ -37,37 +37,20 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                               uint32 *num_entries, 
                               WINBIND_USERINFO **info)
 {
-       CLI_POLICY_HND *hnd;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS result;
        POLICY_HND dom_pol;
-       BOOL got_dom_pol = False;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       unsigned int i, start_idx, retry;
+       unsigned int i, start_idx;
        uint32 loop_count;
+       struct rpc_pipe_client *cli;
 
        DEBUG(3,("rpc: query_user_list\n"));
 
        *num_entries = 0;
        *info = NULL;
 
-       retry = 0;
-       do {
-               /* Get sam handle */
-
-               if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
-                       return result;
-
-               /* Get domain handle */
-
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                               des_access, &domain->sid, &dom_pol);
-
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_dom_pol = True;
+               return result;
 
        i = start_idx = 0;
        loop_count = 0;
@@ -83,28 +66,30 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                ZERO_STRUCT( info1 );
                ctr.sam.info1 = &info1;
        
-               if (!(ctx2 = talloc_init("winbindd enum_users"))) {
-                       result = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }               
+               if (!(ctx2 = talloc_init("winbindd enum_users")))
+                       return NT_STATUS_NO_MEMORY;
 
                /* this next bit is copied from net_user_list_internal() */
 
-               get_query_dispinfo_params( loop_count, &max_entries, &max_size );
+               get_query_dispinfo_params(loop_count, &max_entries,
+                                         &max_size);
 
-               result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, &dom_pol,
-                       &start_idx, 1, &num_dom_users, max_entries, max_size, &ctr);
+               result = rpccli_samr_query_dispinfo(cli, mem_ctx, &dom_pol,
+                                                   &start_idx, 1,
+                                                   &num_dom_users,
+                                                   max_entries, max_size,
+                                                   &ctr);
 
                loop_count++;
 
                *num_entries += num_dom_users;
 
-               *info = TALLOC_REALLOC_ARRAY( mem_ctx, *info, WINBIND_USERINFO, *num_entries);
+               *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info, WINBIND_USERINFO,
+                                            *num_entries);
 
                if (!(*info)) {
-                       result = NT_STATUS_NO_MEMORY;
                        talloc_destroy(ctx2);
-                       goto done;
+                       return NT_STATUS_NO_MEMORY;
                }
 
                for (j = 0; j < num_dom_users; i++, j++) {
@@ -116,7 +101,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                        
                        (*info)[i].acct_name = talloc_strdup(mem_ctx, username );
                        (*info)[i].full_name = talloc_strdup(mem_ctx, fullname );
-                       (*info)[i].user_sid = rid_to_talloced_sid(domain, mem_ctx, rid );
+                       sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
                        
                        /* For the moment we set the primary group for
                           every user to be the Domain Users group.
@@ -126,19 +111,14 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                           force group' smb.conf parameter or
                           something like that. */
                           
-                       (*info)[i].group_sid = rid_to_talloced_sid(domain
-                               mem_ctx, DOMAIN_GROUP_RID_USERS);
+                       sid_compose(&(*info)[i].group_sid, &domain->sid
+                                   DOMAIN_GROUP_RID_USERS);
                }
 
                talloc_destroy(ctx2);
 
        } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
- done:
-
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
        return result;
 }
 
@@ -148,28 +128,17 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                                uint32 *num_entries, 
                                struct acct_info **info)
 {
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       CLI_POLICY_HND *hnd;
        POLICY_HND dom_pol;
        NTSTATUS status;
        uint32 start = 0;
-       int retry;
-       NTSTATUS result;
+       struct rpc_pipe_client *cli;
 
        *num_entries = 0;
        *info = NULL;
 
        DEBUG(3,("rpc: enum_dom_groups\n"));
 
-       retry = 0;
-       do {
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
-                       return result;
-
-               status = cli_samr_open_domain(hnd->cli, mem_ctx,
-                                             &hnd->pol, des_access, &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
+       status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(status))
                return status;
 
@@ -181,10 +150,10 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
 
                /* start is updated by this call. */
-               status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
-                                                 &start,
-                                                 0xFFFF, /* buffer size? */
-                                                 &info2, &count);
+               status = rpccli_samr_enum_dom_groups(cli, mem_ctx2, &dom_pol,
+                                                    &start,
+                                                    0xFFFF, /* buffer size? */
+                                                    &info2, &count);
 
                if (!NT_STATUS_IS_OK(status) && 
                    !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
@@ -192,11 +161,13 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                        break;
                }
 
-               (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
+               (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+                                              struct acct_info,
+                                              (*num_entries) + count);
                if (! *info) {
                        talloc_destroy(mem_ctx2);
-                       cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       break;
                }
 
                memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
@@ -204,9 +175,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                talloc_destroy(mem_ctx2);
        } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
 
-       cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
-       return status;
+       return NT_STATUS_OK;
 }
 
 /* List all domain groups */
@@ -216,25 +185,17 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
                                uint32 *num_entries, 
                                struct acct_info **info)
 {
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       CLI_POLICY_HND *hnd;
        POLICY_HND dom_pol;
        NTSTATUS result;
-       int retry;
+       struct rpc_pipe_client *cli;
 
        *num_entries = 0;
        *info = NULL;
 
-       retry = 0;
-       do {
-               if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
-                       return result;
-
-               result = cli_samr_open_domain( hnd->cli, mem_ctx, &hnd->pol, 
-                                               des_access, &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
+       DEBUG(3,("rpc: enum_local_groups\n"));
 
-       if ( !NT_STATUS_IS_OK(result))
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       if (!NT_STATUS_IS_OK(result))
                return result;
 
        do {
@@ -244,31 +205,32 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 
                mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
 
-               result = cli_samr_enum_als_groups( hnd->cli, mem_ctx2, &dom_pol,
-                                         &start, 0xFFFF, &info2, &count);
+               result = rpccli_samr_enum_als_groups( cli, mem_ctx2, &dom_pol,
+                                                     &start, 0xFFFF, &info2,
+                                                     &count);
                                          
-               if ( !NT_STATUS_IS_OK(result) 
-                       && !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) ) 
+               if (!NT_STATUS_IS_OK(result) &&
+                   !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) ) 
                {
                        talloc_destroy(mem_ctx2);
-                       break;
+                       return result;
                }
 
-               (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
+               (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
+                                              struct acct_info,
+                                              (*num_entries) + count);
                if (! *info) {
                        talloc_destroy(mem_ctx2);
-                       cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
                        return NT_STATUS_NO_MEMORY;
                }
 
                memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
                (*num_entries) += count;
                talloc_destroy(mem_ctx2);
-       } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
-       cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+       } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
-       return result;
+       return NT_STATUS_OK;
 }
 
 /* convert a single name to a sid in a domain */
@@ -279,12 +241,12 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
                            DOM_SID *sid,
                            enum SID_NAME_USE *type)
 {
-       CLI_POLICY_HND *hnd;
        NTSTATUS result;
        DOM_SID *sids = NULL;
        uint32 *types = NULL;
        const char *full_name;
-       int retry;
+       struct rpc_pipe_client *cli;
+       POLICY_HND lsa_policy;
 
         if(name == NULL || *name=='\0') {
                 DEBUG(3,("rpc: name_to_sid name=%s\n", domain_name));
@@ -300,25 +262,22 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
 
        DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", name?name:"", domain_name ));
 
-       retry = 0;
-       do {
-               if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd))) {
-                       return result;
-               }
-        
-               result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, 
-                                             &full_name, &sids, &types);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
-                       hnd && hnd->cli && hnd->cli->fd == -1);
+       result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
+
+       result = rpccli_lsa_lookup_names(cli, mem_ctx, &lsa_policy, 1, 
+                                        &full_name, &sids, &types);
         
+       if (!NT_STATUS_IS_OK(result))
+               return result;
+
        /* Return rid and type if lookup successful */
 
-       if (NT_STATUS_IS_OK(result)) {
-               sid_copy(sid, &sids[0]);
-               *type = (enum SID_NAME_USE)types[0];
-       }
+       sid_copy(sid, &sids[0]);
+       *type = (enum SID_NAME_USE)types[0];
 
-       return result;
+       return NT_STATUS_OK;
 }
 
 /*
@@ -331,34 +290,30 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
                            char **name,
                            enum SID_NAME_USE *type)
 {
-       CLI_POLICY_HND *hnd;
        char **domains;
        char **names;
        uint32 *types;
        NTSTATUS result;
-       int retry;
+       struct rpc_pipe_client *cli;
+       POLICY_HND lsa_policy;
 
        DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_static(sid),
                        domain->name ));
 
-       retry = 0;
-       do {
-               if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd)))
-                       return result;
-        
-               result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
-                                            1, sid, &domains, &names, &types);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
-                       hnd && hnd->cli && hnd->cli->fd == -1);
+       result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-       if (NT_STATUS_IS_OK(result)) {
-               *type = (enum SID_NAME_USE)types[0];
-               *domain_name = domains[0];
-               *name = names[0];
-               DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
-       }
+       result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
+                                       1, sid, &domains, &names, &types);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-       return result;
+       *type = (enum SID_NAME_USE)types[0];
+       *domain_name = domains[0];
+       *name = names[0];
+       DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
+       return NT_STATUS_OK;
 }
 
 /* Lookup user information from a rid or username. */
@@ -367,20 +322,19 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
                           const DOM_SID *user_sid, 
                           WINBIND_USERINFO *user_info)
 {
-       CLI_POLICY_HND *hnd = NULL;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        POLICY_HND dom_pol, user_pol;
-       BOOL got_dom_pol = False, got_user_pol = False;
        SAM_USERINFO_CTR *ctr;
-       int retry;
        fstring sid_string;
        uint32 user_rid;
        NET_USER_INFO_3 *user;
+       struct rpc_pipe_client *cli;
 
-       DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid)));
-       if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
-               goto done;
-       }
+       DEBUG(3,("rpc: query_user rid=%s\n",
+                sid_to_string(sid_string, user_sid)));
+
+       if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+               return NT_STATUS_UNSUCCESSFUL;
        
        /* try netsamlogon cache first */
                        
@@ -389,12 +343,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
                                
                DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
                        sid_string_static(user_sid)));
-                       
-               user_info->user_sid  = rid_to_talloced_sid( domain, mem_ctx, user_rid );
-               user_info->group_sid = rid_to_talloced_sid( domain, mem_ctx, user->group_rid );
+
+               sid_compose(&user_info->user_sid, &domain->sid, user_rid);
+               sid_compose(&user_info->group_sid, &domain->sid,
+                           user->group_rid);
                                
-               user_info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name);
-               user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name);
+               user_info->acct_name = unistr2_tdup(mem_ctx,
+                                                   &user->uni_user_name);
+               user_info->full_name = unistr2_tdup(mem_ctx,
+                                                   &user->uni_full_name);
                                                                
                SAFE_FREE(user);
                                
@@ -403,82 +360,59 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        
        /* no cache; hit the wire */
                
-       retry = 0;
-       do {
-               /* Get sam handle; if we fail here there is no hope */
-               
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) 
-                       goto done;
-                       
-               /* Get domain handle */
-
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                             SEC_RIGHTS_MAXIMUM_ALLOWED, 
-                                             &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
-                       hnd && hnd->cli && hnd->cli->fd == -1);
-
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_dom_pol = True;
+               return result;
 
        /* Get user handle */
-       result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
-                                   SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+       result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
+                                      SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
+                                      &user_pol);
 
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_user_pol = True;
+               return result;
 
        /* Get user info */
-       result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 
-                                        0x15, &ctr);
+       result = rpccli_samr_query_userinfo(cli, mem_ctx, &user_pol,
+                                           0x15, &ctr);
 
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
 
-       cli_samr_close(hnd->cli, mem_ctx, &user_pol);
-       got_user_pol = False;
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-       user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid);
-       user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid);
+       sid_compose(&user_info->user_sid, &domain->sid, user_rid);
+       sid_compose(&user_info->group_sid, &domain->sid,
+                   ctr->info.id21->group_rid);
        user_info->acct_name = unistr2_tdup(mem_ctx, 
                                            &ctr->info.id21->uni_user_name);
        user_info->full_name = unistr2_tdup(mem_ctx, 
                                            &ctr->info.id21->uni_full_name);
 
- done:
-       /* Clean up policy handles */
-       if (got_user_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &user_pol);
-
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
-       return result;
+       return NT_STATUS_OK;
 }                                   
 
 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
                                  const DOM_SID *user_sid,
-                                 uint32 *num_groups, DOM_SID ***user_grpsids)
+                                 uint32 *num_groups, DOM_SID **user_grpsids)
 {
-       CLI_POLICY_HND *hnd;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        POLICY_HND dom_pol, user_pol;
        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       BOOL got_dom_pol = False, got_user_pol = False;
        DOM_GID *user_groups;
        unsigned int i;
-       unsigned int retry;
        fstring sid_string;
        uint32 user_rid;
        NET_USER_INFO_3 *user;
+       struct rpc_pipe_client *cli;
+
+       DEBUG(3,("rpc: lookup_usergroups sid=%s\n",
+                sid_to_string(sid_string, user_sid)));
 
-       DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid)));
+       if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
+               return NT_STATUS_UNSUCCESSFUL;
 
        *num_groups = 0;
        *user_grpsids = NULL;
@@ -492,9 +426,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                        
                *num_groups = user->num_groups;
                                
-               (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID*, *num_groups);
+               (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
                for (i=0;i<(*num_groups);i++) {
-                       (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid);
+                       sid_copy(&((*user_grpsids)[i]), &domain->sid);
+                       sid_append_rid(&((*user_grpsids)[i]),
+                                      user->gids[i].g_rid);
                }
                                
                SAFE_FREE(user);
@@ -504,124 +440,73 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
 
        /* no cache; hit the wire */
        
-       retry = 0;
-       do {
-               /* Get sam handle; if we fail here there is no hope */
-               
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))                 
-                       goto done;
-
-               /* Get domain handle */
-               
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                             des_access, &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && 
-                       hnd && hnd->cli && hnd->cli->fd == -1);
-
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_dom_pol = True;
-
-
-       if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
-               goto done;
-       }
+               return result;
 
        /* Get user handle */
-       result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
+       result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
                                        des_access, user_rid, &user_pol);
 
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_user_pol = True;
+               return result;
 
        /* Query user rids */
-       result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, 
+       result = rpccli_samr_query_usergroups(cli, mem_ctx, &user_pol, 
                                           num_groups, &user_groups);
 
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+
        if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
-               goto done;
+               return result;
 
-       (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
-       if (!(*user_grpsids)) {
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
+       if (!(*user_grpsids))
+               return NT_STATUS_NO_MEMORY;
 
        for (i=0;i<(*num_groups);i++) {
-               (*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid);
+               sid_copy(&((*user_grpsids)[i]), &domain->sid);
+               sid_append_rid(&((*user_grpsids)[i]),
+                               user_groups[i].g_rid);
        }
        
- done:
-       /* Clean up policy handles */
-       if (got_user_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &user_pol);
-
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
-       return result;
+       return NT_STATUS_OK;
 }
 
 NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
                                  TALLOC_CTX *mem_ctx,
-                                 uint32 num_sids, DOM_SID **sids,
+                                 uint32 num_sids, const DOM_SID *sids,
                                  uint32 *num_aliases, uint32 **alias_rids)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       CLI_POLICY_HND *hnd;
-       BOOL got_dom_pol = False;
        POLICY_HND dom_pol;
        DOM_SID2 *sid2;
-       int i, retry;
+       int i;
+       struct rpc_pipe_client *cli;
 
        *num_aliases = 0;
        *alias_rids = NULL;
 
-       retry = 0;
-       do {
-               /* Get sam handle; if we fail here there is no hope */
-               
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain,
-                                                               &hnd)))
-                       goto done;
-
-               /* Get domain handle */
-               
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                             SEC_RIGHTS_MAXIMUM_ALLOWED,
-                                             &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && 
-                       hnd && hnd->cli && hnd->cli->fd == -1);
+       DEBUG(3,("rpc: lookup_useraliases\n"));
 
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_dom_pol = True;
+               return result;
 
        sid2 = TALLOC_ARRAY(mem_ctx, DOM_SID2, num_sids);
 
-       if (sid2 == NULL) {
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       if (sid2 == NULL)
+               return NT_STATUS_NO_MEMORY;
 
        for (i=0; i<num_sids; i++) {
-               sid_copy(&sid2[i].sid, sids[i]);
+               sid_copy(&sid2[i].sid, &sids[i]);
                sid2[i].num_auths = sid2[i].sid.num_auths;
        }
 
-       result = cli_samr_query_useraliases(hnd->cli, mem_ctx, &dom_pol,
-                                           num_sids, sid2,
-                                           num_aliases, alias_rids);
-
- done:
+       result = rpccli_samr_query_useraliases(cli, mem_ctx, &dom_pol,
+                                              num_sids, sid2,
+                                              num_aliases, alias_rids);
 
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-       
        return result;
 }
 
@@ -630,71 +515,54 @@ NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                const DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID ***sid_mem, char ***names, 
+                               DOM_SID **sid_mem, char ***names, 
                                uint32 **name_types)
 {
-        CLI_POLICY_HND *hnd = NULL;
         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
         uint32 i, total_names = 0;
         POLICY_HND dom_pol, group_pol;
         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-        BOOL got_dom_pol = False, got_group_pol = False;
        uint32 *rid_mem = NULL;
        uint32 group_rid;
-       int retry;
        unsigned int j;
        fstring sid_string;
+       struct rpc_pipe_client *cli;
 
-       DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name, sid_to_string(sid_string, group_sid)));
+       DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
+                 sid_to_string(sid_string, group_sid)));
 
-       if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid)) {
-               goto done;
-       }
+       if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
+               return NT_STATUS_UNSUCCESSFUL;
 
        *num_names = 0;
 
-       retry = 0;
-       do {
-               /* Get sam handle */
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
-                       goto done;
-
-               /* Get domain handle */
-
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                               des_access, &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
-
-        if (!NT_STATUS_IS_OK(result))
-                goto done;
-
-        got_dom_pol = True;
-
-        /* Get group handle */
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-        result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
-                                     des_access, group_rid, &group_pol);
+        result = rpccli_samr_open_group(cli, mem_ctx, &dom_pol,
+                                       des_access, group_rid, &group_pol);
 
         if (!NT_STATUS_IS_OK(result))
-                goto done;
-
-        got_group_pol = True;
+               return result;
 
         /* Step #1: Get a list of user rids that are the members of the
            group. */
 
-        result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
-                                         &group_pol, num_names, &rid_mem,
-                                         name_types);
+        result = rpccli_samr_query_groupmem(cli, mem_ctx,
+                                           &group_pol, num_names, &rid_mem,
+                                           name_types);
+
+       rpccli_samr_close(cli, mem_ctx, &group_pol);
 
         if (!NT_STATUS_IS_OK(result))
-                goto done;
+               return result;
 
        if (!*num_names) {
                names = NULL;
                name_types = NULL;
                sid_mem = NULL;
-               goto done;
+               return NT_STATUS_OK;
        }
 
         /* Step #2: Convert list of rids into list of usernames.  Do this
@@ -706,16 +574,13 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
         *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
         *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
-        *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, *num_names);
+        *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
 
-       for (j=0;j<(*num_names);j++) {
-               (*sid_mem)[j] = rid_to_talloced_sid(domain, mem_ctx, (rid_mem)[j]);
-       }
+       for (j=0;j<(*num_names);j++)
+               sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
        
-       if (*num_names>0 && (!*names || !*name_types)) {
-               result = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       if (*num_names>0 && (!*names || !*name_types))
+               return NT_STATUS_NO_MEMORY;
 
         for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
                 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
@@ -725,18 +590,19 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
                 /* Lookup a chunk of rids */
 
-                result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
-                                              &dom_pol,
-                                              num_lookup_rids,
-                                              &rid_mem[i],
-                                              &tmp_num_names,
-                                              &tmp_names, &tmp_types);
+                result = rpccli_samr_lookup_rids(cli, mem_ctx,
+                                                &dom_pol,
+                                                num_lookup_rids,
+                                                &rid_mem[i],
+                                                &tmp_num_names,
+                                                &tmp_names, &tmp_types);
 
-               /* see if we have a real error (and yes the STATUS_SOME_UNMAPPED is
-                  the one returned from 2k) */
+               /* see if we have a real error (and yes the
+                  STATUS_SOME_UNMAPPED is the one returned from 2k) */
                
-                if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED))
-                        goto done;
+                if (!NT_STATUS_IS_OK(result) &&
+                   !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
+                       return result;
                        
                 /* Copy result into array.  The talloc system will take
                    care of freeing the temporary arrays later on. */
@@ -752,16 +618,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
         *num_names = total_names;
 
-       result = NT_STATUS_OK;
-       
-done:
-        if (got_group_pol)
-                cli_samr_close(hnd->cli, mem_ctx, &group_pol);
-
-        if (got_dom_pol)
-                cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
-        return result;
+       return NT_STATUS_OK;
 }
 
 #ifdef HAVE_LDAP
@@ -780,11 +637,12 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq)
        *seq = DOM_SEQUENCE_NONE;
 
        /*
-        * Parameterised (5) second timeout on open. This is needed as the search timeout
-        * doesn't seem to apply to doing an open as well. JRA.
+        * Parameterised (5) second timeout on open. This is needed as the
+        * search timeout doesn't seem to apply to doing an open as well. JRA.
         */
 
-       if ((ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout())) == NULL)
+       ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
+       if (ldp == NULL)
                return -1;
 
        /* Timeout if no response within 20 seconds. */
@@ -792,7 +650,7 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq)
        to.tv_usec = 0;
 
        if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
-                           CONST_DISCARD(char **, &attrs[0]), 0, &to, &res))
+                          CONST_DISCARD(char **, attrs), 0, &to, &res))
                goto done;
 
        if (ldap_count_entries(ldp, res) != 1)
@@ -838,8 +696,10 @@ static int get_ldap_sequence_number( const char* domain, uint32 *seq)
        for (i = 0; i < count; i++) {
                fstring ipstr;
 
-               /* since the is an LDAP lookup, default to the LDAP_PORT is not set */
-               port = (ip_list[i].port!= PORT_NONE) ? ip_list[i].port : LDAP_PORT;
+               /* since the is an LDAP lookup, default to the LDAP_PORT is
+                * not set */
+               port = (ip_list[i].port!= PORT_NONE) ?
+                       ip_list[i].port : LDAP_PORT;
 
                fstrcpy( ipstr, inet_ntoa(ip_list[i].ip) );
                
@@ -850,12 +710,14 @@ static int get_ldap_sequence_number( const char* domain, uint32 *seq)
                        goto done;
 
                /* add to failed connection cache */
-               add_failed_connection_entry( domain, ipstr, NT_STATUS_UNSUCCESSFUL );
+               add_failed_connection_entry( domain, ipstr,
+                                            NT_STATUS_UNSUCCESSFUL );
        }
 
 done:
        if ( ret == 0 ) {
-               DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s:%d)\n", 
+               DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
+                         "number for Domain (%s) from DC (%s:%d)\n", 
                        domain, inet_ntoa(ip_list[i].ip), port));
        }
 
@@ -870,14 +732,12 @@ done:
 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
 {
        TALLOC_CTX *mem_ctx;
-       CLI_POLICY_HND *hnd;
        SAM_UNK_CTR ctr;
        NTSTATUS result;
        POLICY_HND dom_pol;
-       BOOL got_dom_pol = False;
        BOOL got_seq_num = False;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
        int retry;
+       struct rpc_pipe_client *cli;
 
        DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
 
@@ -887,41 +747,39 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
                return NT_STATUS_NO_MEMORY;
 
        retry = 0;
-       do {
-#ifdef HAVE_LDAP
-               if ( domain->native_mode ) 
-               {
-                       DEBUG(8,("using get_ldap_seq() to retrieve the sequence number\n"));
-
-                       if ( get_ldap_sequence_number( domain->name, seq ) == 0 ) {                     
-                               result = NT_STATUS_OK;
-                               DEBUG(10,("domain_sequence_number: LDAP for domain %s is %u\n",
-                                       domain->name, *seq));
-                               goto done;
-                       }
 
-                       DEBUG(10,("domain_sequence_number: failed to get LDAP sequence number for domain %s\n",
-                       domain->name ));
-               }
-#endif /* HAVE_LDAP */
-               /* Get sam handle */
-               if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
+#ifdef HAVE_LDAP
+       if ( domain->native_mode ) 
+       {
+               int res;
+
+               DEBUG(8,("using get_ldap_seq() to retrieve the "
+                        "sequence number\n"));
+
+               res =  get_ldap_sequence_number( domain->name, seq );
+               if (res == 0)
+               {                       
+                       result = NT_STATUS_OK;
+                       DEBUG(10,("domain_sequence_number: LDAP for "
+                                 "domain %s is %u\n",
+                                 domain->name, *seq));
                        goto done;
+               }
 
-               /* Get domain handle */
-               result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, 
-                                     des_access, &domain->sid, &dom_pol);
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
+               DEBUG(10,("domain_sequence_number: failed to get LDAP "
+                         "sequence number for domain %s\n",
+                         domain->name ));
+       }
+#endif /* HAVE_LDAP */
 
-       if (!NT_STATUS_IS_OK(result))
+       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       if (!NT_STATUS_IS_OK(result)) {
                goto done;
-
-       got_dom_pol = True;
+       }
 
        /* Query domain info */
 
-       result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
-                                        8, &ctr);
+       result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 8, &ctr);
 
        if (NT_STATUS_IS_OK(result)) {
                *seq = ctr.info.inf8.seq_num.low;
@@ -932,8 +790,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
        /* retry with info-level 2 in case the dc does not support info-level 8
         * (like all older samba2 and samba3 dc's - Guenther */
 
-       result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
-                                        2, &ctr);
+       result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 2, &ctr);
        
        if (NT_STATUS_IS_OK(result)) {
                *seq = ctr.info.inf2.seq_num.low;
@@ -942,17 +799,16 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
 
  seq_num:
        if (got_seq_num) {
-               DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)*seq));
+               DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
+                         domain->name, (unsigned)*seq));
        } else {
-               DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
-                       (unsigned)*seq, domain->name ));
+               DEBUG(10,("domain_sequence_number: failed to get sequence "
+                         "number (%u) for domain %s\n",
+                         (unsigned)*seq, domain->name ));
        }
 
   done:
 
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
        talloc_destroy(mem_ctx);
 
        return result;
@@ -966,10 +822,10 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                char ***alt_names,
                                DOM_SID **dom_sids)
 {
-       CLI_POLICY_HND *hnd;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        uint32 enum_ctx = 0;
-       int retry;
+       struct rpc_pipe_client *cli;
+       POLICY_HND lsa_policy;
 
        DEBUG(3,("rpc: trusted_domains\n"));
 
@@ -978,46 +834,45 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        *alt_names = NULL;
        *dom_sids = NULL;
 
-       retry = 0;
-       do {
-               if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(find_our_domain(), &hnd)))
-                       goto done;
+       result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
+       if (!NT_STATUS_IS_OK(result))
+               return result;
 
-               result = STATUS_MORE_ENTRIES;
-
-               while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
-                       uint32 start_idx, num;
-                       char **tmp_names;
-                       DOM_SID *tmp_sids;
-                       int i;
-
-                       result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
-                                                       &hnd->pol, &enum_ctx,
-                                                       &num, &tmp_names,
-                                                       &tmp_sids);
-
-                       if (!NT_STATUS_IS_OK(result) &&
-                           !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
-                               break;
-
-                       start_idx = *num_domains;
-                       *num_domains += num;
-                       *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
-                                                     char *, *num_domains);
-                       *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
-                                                        DOM_SID,
-                                                        *num_domains);
-                       if ((*names == NULL) || (*dom_sids == NULL))
-                               return NT_STATUS_NO_MEMORY;
-
-                       for (i=0; i<num; i++) {
-                               (*names)[start_idx+i] = tmp_names[i];
-                               (*dom_sids)[start_idx+i] = tmp_sids[i];
-                       }
-               }
-       } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&  hnd && hnd->cli && hnd->cli->fd == -1);
+       result = STATUS_MORE_ENTRIES;
 
-done:
+       while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+               uint32 start_idx, num;
+               char **tmp_names;
+               DOM_SID *tmp_sids;
+               int i;
+
+               result = rpccli_lsa_enum_trust_dom(cli, mem_ctx,
+                                                  &lsa_policy, &enum_ctx,
+                                                  &num, &tmp_names,
+                                                  &tmp_sids);
+
+               if (!NT_STATUS_IS_OK(result) &&
+                   !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
+                       break;
+
+               start_idx = *num_domains;
+               *num_domains += num;
+               *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
+                                             char *, *num_domains);
+               *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
+                                                DOM_SID, *num_domains);
+               *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
+                                                char *, *num_domains);
+               if ((*names == NULL) || (*dom_sids == NULL) ||
+                   (*alt_names == NULL))
+                       return NT_STATUS_NO_MEMORY;
+
+               for (i=0; i<num; i++) {
+                       (*names)[start_idx+i] = tmp_names[i];
+                       (*dom_sids)[start_idx+i] = tmp_sids[i];
+                       (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
+               }
+       }
        return result;
 }
 
index 060e66fbc2d616ede18fcf2e97770075d7c33140..f8fb5e93c2ec1aabdcfe004694b2663646f3f92b 100644 (file)
 
 /* Convert a string  */
 
+static void lookupsid_recv(void *private, BOOL success,
+                          const char *dom_name, const char *name,
+                          enum SID_NAME_USE type);
+
 enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
 {
-       enum SID_NAME_USE type;
        DOM_SID sid;
-       fstring name;
-       fstring dom_name;
 
        /* Ensure null termination */
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
@@ -41,38 +42,46 @@ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, 
                  state->request.data.sid));
 
-       /* Lookup sid from PDC using lsa_lookup_sids() */
-
        if (!string_to_sid(&sid, state->request.data.sid)) {
                DEBUG(5, ("%s not a SID\n", state->request.data.sid));
                return WINBINDD_ERROR;
        }
 
-       /* Lookup the sid */
+       winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
+       return WINBINDD_PENDING;
+}
 
-       if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) {
-               return WINBINDD_ERROR;
+static void lookupsid_recv(void *private, BOOL success,
+                          const char *dom_name, const char *name,
+                          enum SID_NAME_USE type)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               DEBUG(5, ("lookupsid returned an error\n"));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
        }
 
        fstrcpy(state->response.data.name.dom_name, dom_name);
        fstrcpy(state->response.data.name.name, name);
-
        state->response.data.name.type = type;
-
-       return WINBINDD_OK;
+       state->response.result =  WINBINDD_OK;
+       request_finished(state);
 }
 
-
 /**
  * Look up the SID for a qualified name.  
  **/
+
+static void lookupname_recv(void *private, BOOL success,
+                           const DOM_SID *sid, enum SID_NAME_USE type);
+
 enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
 {
-       enum SID_NAME_USE type;
-       fstring sid_str;
        char *name_domain, *name_user;
-       DOM_SID sid;
-       struct winbindd_domain *domain;
        char *p;
 
        /* Ensure null termination */
@@ -95,27 +104,48 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
                  name_domain, lp_winbind_separator(), name_user));
 
-       if ((domain = find_lookup_domain_from_name(name_domain)) == NULL) {
-               DEBUG(0, ("could not find domain entry for domain %s\n", 
-                         name_domain));
-               return WINBINDD_ERROR;
-       }
+       winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
+                                 lookupname_recv, state);
+       return WINBINDD_PENDING;
+}
 
-       /* Lookup name from PDC using lsa_lookup_names() */
-       if (!winbindd_lookup_sid_by_name(domain, name_domain, name_user, &sid, &type)) {
-               return WINBINDD_ERROR;
+static void lookupname_recv(void *private, BOOL success,
+                           const DOM_SID *sid, enum SID_NAME_USE type)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               DEBUG(5, ("lookupname returned an error\n"));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
        }
 
-       sid_to_string(sid_str, &sid);
-       fstrcpy(state->response.data.sid.sid, sid_str);
+       sid_to_string(state->response.data.sid.sid, sid);
        state->response.data.sid.type = type;
+       state->response.result = WINBINDD_OK;
+       request_finished(state);
+       return;
+}
 
-       return WINBINDD_OK;
+static struct winbindd_child static_idmap_child;
+
+void init_idmap_child(void)
+{
+       setup_domain_child(NULL, &static_idmap_child, "idmap");
+}
+
+struct winbindd_child *idmap_child(void)
+{
+       return &static_idmap_child;
 }
 
 /* Convert a sid to a uid.  We assume we only have one rid attached to the
    sid. */
 
+static void sid2uid_recv(void *private, BOOL success, uid_t uid);
+
 enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
 {
        DOM_SID sid;
@@ -127,105 +157,53 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
        DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
                  state->request.data.sid));
 
-       if (!string_to_sid(&sid, state->request.data.sid)) {
-               DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
+       if (idmap_proxyonly()) {
+               DEBUG(8, ("IDMAP proxy only\n"));
                return WINBINDD_ERROR;
        }
-       
-       /* This gets a little tricky.  If we assume that usernames are syncd between
-          /etc/passwd and the windows domain (such as a member of a Samba domain),
-          the we need to get the uid from the OS and not alocate one ourselves */
-          
-       if ( lp_winbind_trusted_domains_only() ) {
-               struct winbindd_domain *domain = NULL;
-               DOM_SID sid2;
-               uint32 rid;
-               
-               domain = find_our_domain();
-               if ( !domain ) {
-                       DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
-                       return WINBINDD_ERROR;
-               }
-
-               sid_copy( &sid2, &sid );
-               sid_split_rid( &sid2, &rid );
-               
-               if ( sid_equal( &sid2, &domain->sid ) ) {
-               
-                       fstring domain_name;
-                       fstring user;
-                       enum SID_NAME_USE type;
-                       struct passwd *pw = NULL;
-                       unid_t id;
-                       
-                       /* ok...here's we know that we are dealing with our
-                          own domain (the one to which we are joined).  And
-                          we know that there must be a UNIX account for this user.
-                          So we lookup the sid and the call getpwnam().*/
-                          
-                       
-                       /* But first check and see if we don't already have a mapping */
-                          
-                       if ( NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), ID_QUERY_ONLY)) )
-                               return WINBINDD_OK;
-                               
-                       /* now fall back to the hard way */
-                       
-                       if ( !winbindd_lookup_name_by_sid(&sid, domain_name, user, &type) )
-                               return WINBINDD_ERROR;
-                               
-                       if ( !(pw = getpwnam(user)) ) {
-                               DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
-                                       "set but this user [%s] doesn't exist!\n", user));
-                               return WINBINDD_ERROR;
-                       }
-                       
-                       state->response.data.uid = pw->pw_uid;
-
-                       id.uid = pw->pw_uid;
-                       idmap_set_mapping( &sid, id, ID_USERID );
-
-                       return WINBINDD_OK;
-               }
 
+       if (!string_to_sid(&sid, state->request.data.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.sid));
+               return WINBINDD_ERROR;
        }
-       
-       /* Find uid for this sid and return it */
+
+       /* Query only the local tdb, everything else might possibly block */
 
        result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
-                                 ID_QUERY_ONLY);
+                                 ID_QUERY_ONLY|ID_CACHE_ONLY);
 
-       if (NT_STATUS_IS_OK(result))
+       if (NT_STATUS_IS_OK(result)) {
                return WINBINDD_OK;
+       }
 
-       if (state->request.flags & WBFLAG_QUERY_ONLY)
-               return WINBINDD_ERROR;
-
-       /* The query-only did not work, allocate a new uid *if* it's a user */
-
-       {
-               fstring dom_name, name;
-               enum SID_NAME_USE type;
-
-               if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type))
-                       return WINBINDD_ERROR;
+       winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
+       return WINBINDD_PENDING;
+}
 
-               if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))
-                       return WINBINDD_ERROR;
+static void sid2uid_recv(void *private, BOOL success, uid_t uid)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not convert sid %s\n",
+                         state->request.data.sid));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
        }
-       
-       result = idmap_sid_to_uid(&sid, &(state->response.data.uid), 0);
 
-       if (NT_STATUS_IS_OK(result))
-               return WINBINDD_OK;
-
-       DEBUG(4, ("Could not get uid for sid %s\n", state->request.data.sid));
-       return WINBINDD_ERROR;
+       state->response.result = WINBINDD_OK;
+       state->response.data.uid = uid;
+       request_finished(state);
 }
 
 /* Convert a sid to a gid.  We assume we only have one rid attached to the
    sid.*/
 
+static void sid2gid_recv(void *private, BOOL success, gid_t gid);
+
 enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
 {
        DOM_SID sid;
@@ -234,253 +212,301 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
        /* Ensure null termination */
        state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
-       DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid, 
+       DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
                  state->request.data.sid));
 
-       if (!string_to_sid(&sid, state->request.data.sid)) {
-               DEBUG(1, ("Could not cvt string to sid %s\n", state->request.data.sid));
+       if (idmap_proxyonly()) {
+               DEBUG(8, ("IDMAP proxy only\n"));
                return WINBINDD_ERROR;
        }
 
-       /* This gets a little tricky.  If we assume that usernames are syncd between
-          /etc/passwd and the windows domain (such as a member of a Samba domain),
-          the we need to get the uid from the OS and not alocate one ourselves */
-          
-       if ( lp_winbind_trusted_domains_only() ) {
-               struct winbindd_domain *domain = NULL;
-               DOM_SID sid2;
-               uint32 rid;
-               unid_t id;
-               
-               domain = find_our_domain();
-               if ( !domain ) {
-                       DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
-                       return WINBINDD_ERROR;
-               }
-               
-               sid_copy( &sid2, &sid );
-               sid_split_rid( &sid2, &rid );
-
-               if ( sid_equal( &sid2, &domain->sid ) ) {
-               
-                       fstring domain_name;
-                       fstring group;
-                       enum SID_NAME_USE type;
-                       struct group *grp = NULL;
-                       
-                       /* ok...here's we know that we are dealing with our
-                          own domain (the one to which we are joined).  And
-                          we know that there must be a UNIX account for this group.
-                          So we lookup the sid and the call getpwnam().*/
-                       
-                       /* But first check and see if we don't already have a mapping */
-                          
-                       if ( NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), ID_QUERY_ONLY)) )
-                               return WINBINDD_OK;
-                               
-                       /* now fall back to the hard way */
-                       
-                       if ( !winbindd_lookup_name_by_sid(&sid, domain_name, group, &type) )
-                               return WINBINDD_ERROR;
-                               
-                       if ( !(grp = getgrnam(group)) ) {
-                               DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
-                                       "set but this group [%s] doesn't exist!\n", group));
-                               return WINBINDD_ERROR;
-                       }
-                       
-                       state->response.data.gid = grp->gr_gid;
-
-                       id.gid = grp->gr_gid;
-                       idmap_set_mapping( &sid, id, ID_GROUPID );
-
-                       return WINBINDD_OK;
-               }
-
+       if (!string_to_sid(&sid, state->request.data.sid)) {
+               DEBUG(1, ("Could not get convert sid %s from string\n",
+                         state->request.data.sid));
+               return WINBINDD_ERROR;
        }
-       
-       /* Find gid for this sid and return it */
+
+       /* Query only the local tdb, everything else might possibly block */
 
        result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
-                                 ID_QUERY_ONLY);
+                                 ID_QUERY_ONLY|ID_CACHE_ONLY);
 
-       if (NT_STATUS_IS_OK(result))
+       if (NT_STATUS_IS_OK(result)) {
                return WINBINDD_OK;
+       }
 
-       if (state->request.flags & WBFLAG_QUERY_ONLY)
-               return WINBINDD_ERROR;
+       winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
+       return WINBINDD_PENDING;
+}
 
-       /* The query-only did not work, allocate a new gid *if* it's a group */
-
-       {
-               fstring dom_name, name;
-               enum SID_NAME_USE type;
-
-               if (sid_check_is_in_our_domain(&sid)) {
-                       /* This is for half-created aliases... */
-                       type = SID_NAME_ALIAS;
-               } else {
-                       /* Foreign domains need to be looked up by the DC if
-                        * it's the right type */
-                       if (!winbindd_lookup_name_by_sid(&sid, dom_name, name,
-                                                        &type))
-                               return WINBINDD_ERROR;
-               }
-
-               if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
-                   (type != SID_NAME_WKN_GRP))
-                       return WINBINDD_ERROR;
+static void sid2gid_recv(void *private, BOOL success, gid_t gid)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private, struct winbindd_cli_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not convert sid %s\n",
+                         state->request.data.sid));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
        }
-       
-       result = idmap_sid_to_gid(&sid, &(state->response.data.gid), 0);
-
-       if (NT_STATUS_IS_OK(result))
-               return WINBINDD_OK;
 
-       DEBUG(4, ("Could not get gid for sid %s\n", state->request.data.sid));
-       return WINBINDD_ERROR;
+       state->response.result = WINBINDD_OK;
+       state->response.data.gid = gid;
+       request_finished(state);
 }
 
 /* Convert a uid to a sid */
 
+struct uid2sid_state {
+       struct winbindd_cli_state *cli_state;
+       uid_t uid;
+       fstring name;
+       DOM_SID sid;
+       enum SID_NAME_USE type;
+};
+
+static void uid2sid_uid2name_recv(void *private, BOOL success,
+                                 const char *username);
+static void uid2sid_lookupname_recv(void *private, BOOL success,
+                                   const DOM_SID *sid,
+                                   enum SID_NAME_USE type);
+static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success);
+
 enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
 {
        DOM_SID sid;
+       NTSTATUS status;
+       struct uid2sid_state *uid2sid_state;
 
        DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, 
                  (unsigned long)state->request.data.uid));
 
-       if ( (state->request.data.uid < server_state.uid_low ) 
-               || (state->request.data.uid > server_state.uid_high) )
-       {
-               struct passwd *pw = NULL;
-               enum SID_NAME_USE type;
-               unid_t id;
-               struct winbindd_domain *domain;
-
-               /* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
-               
-               /* if we don't trust /etc/password then when can't know 
-                  anything about this uid */
-                  
-               if ( !lp_winbind_trusted_domains_only() )
-                       return WINBINDD_ERROR;
-
-
-               /* look for an idmap entry first */
-                       
-               if ( NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid)) ) 
-                       goto done;
-               
-               /* if users exist in /etc/passwd, we should try to 
-                  use that uid. Get the username and the lookup the SID */
-
-               if ( !(pw = getpwuid(state->request.data.uid)) )
-                       return WINBINDD_ERROR;
-
-               if ( !(domain = find_our_domain()) ) {
-                       DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
-                       return WINBINDD_ERROR;
-               }
-
-               if ( !winbindd_lookup_sid_by_name(domain, domain->name, pw->pw_name, &sid, &type) )
-                       return WINBINDD_ERROR;
-               
-               if ( type != SID_NAME_USER )
-                       return WINBINDD_ERROR;
-               
-               /* don't fail if we can't store it */
-
-               id.uid = pw->pw_uid;
-               idmap_set_mapping( &sid, id, ID_USERID );
-               
-               goto done;
+       if (idmap_proxyonly()) {
+               DEBUG(8, ("IDMAP proxy only\n"));
+               return WINBINDD_ERROR;
        }
 
-       /* Lookup rid for this uid */
-       
-       if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid))) {
-               DEBUG(1, ("Could not convert uid %lu to rid\n",
-                         (unsigned long)state->request.data.uid));
+       status = idmap_uid_to_sid(&sid, state->request.data.uid,
+                                 ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+       if (NT_STATUS_IS_OK(status)) {
+               sid_to_string(state->response.data.sid.sid, &sid);
+               state->response.data.sid.type = SID_NAME_USER;
+               return WINBINDD_OK;
+       }
+
+       if (is_in_uid_range(state->request.data.uid)) {
+               /* This is winbind's, so we should better have succeeded
+                * above. */
                return WINBINDD_ERROR;
        }
 
-done:
-       sid_to_string(state->response.data.sid.sid, &sid);
-       state->response.data.sid.type = SID_NAME_USER;
+       /* The only chance that this is correct is that winbind trusted
+        * domains only = yes, and the user exists in nss and the domain. */
 
-       return WINBINDD_OK;
+       if (!lp_winbind_trusted_domains_only()) {
+               return WINBINDD_ERROR;
+       }
+
+       /* The only chance that this is correct is that winbind trusted
+        * domains only = yes, and the user exists in nss and the domain. */
+
+       uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
+       if (uid2sid_state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               return WINBINDD_ERROR;
+       }
+
+       uid2sid_state->cli_state = state;
+       uid2sid_state->uid = state->request.data.uid;
+
+       winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
+                               uid2sid_uid2name_recv, uid2sid_state);
+       return WINBINDD_PENDING;
+}
+
+static void uid2sid_uid2name_recv(void *private, BOOL success,
+                                 const char *username)
+{
+       struct uid2sid_state *state =
+               talloc_get_type_abort(private, struct uid2sid_state);
+
+       DEBUG(10, ("uid2sid: uid %lu has name %s\n",
+                  (unsigned long)state->uid, username));
+
+       fstrcpy(state->name, username);
+
+       if (!success) {
+               state->cli_state->response.result = WINBINDD_ERROR;
+               request_finished(state->cli_state);
+               return;
+       }
+
+       winbindd_lookupname_async(state->cli_state->mem_ctx,
+                                 find_our_domain()->name, username,
+                                 uid2sid_lookupname_recv, state);
+}
+
+static void uid2sid_lookupname_recv(void *private, BOOL success,
+                                   const DOM_SID *sid, enum SID_NAME_USE type)
+{
+       struct uid2sid_state *state =
+               talloc_get_type_abort(private, struct uid2sid_state);
+       unid_t id;
+
+       if ((!success) || (type != SID_NAME_USER)) {
+               state->cli_state->response.result = WINBINDD_ERROR;
+               request_finished(state->cli_state);
+               return;
+       }
+
+       state->sid = *sid;
+       state->type = type;
+
+       id.uid = state->uid;
+       idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
+                               uid2sid_idmap_set_mapping_recv, state );
+}
+
+static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success)
+{
+       struct uid2sid_state *state =
+               talloc_get_type_abort(private, struct uid2sid_state);
+
+       /* don't fail if we can't store it */
+
+       sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
+       state->cli_state->response.data.sid.type = state->type;
+       state->cli_state->response.result = WINBINDD_OK;
+       request_finished(state->cli_state);
 }
 
 /* Convert a gid to a sid */
 
+struct gid2sid_state {
+       struct winbindd_cli_state *cli_state;
+       gid_t gid;
+       fstring name;
+       DOM_SID sid;
+       enum SID_NAME_USE type;
+};
+
+static void gid2sid_gid2name_recv(void *private, BOOL success,
+                                 const char *groupname);
+static void gid2sid_lookupname_recv(void *private, BOOL success,
+                                   const DOM_SID *sid,
+                                   enum SID_NAME_USE type);
+static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success);
+
 enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
 {
        DOM_SID sid;
+       NTSTATUS status;
+       struct gid2sid_state *gid2sid_state;
 
-       DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
+       DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, 
                  (unsigned long)state->request.data.gid));
-                 
-       if ( (state->request.data.gid < server_state.gid_low) 
-               || (state->request.data.gid > server_state.gid_high) )
-       {               
-               struct group *grp = NULL;
-               enum SID_NAME_USE type;
-               unid_t id;
-               struct winbindd_domain *domain;
-
-               /* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
-               
-               /* if we don't trust /etc/group then when can't know 
-                  anything about this gid */
-                  
-               if ( !lp_winbind_trusted_domains_only() )
-                       return WINBINDD_ERROR;
-
-               /* look for an idmap entry first */
-               
-               if ( NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid)) )
-                       goto done;
-                       
-               /* if users exist in /etc/group, we should try to 
-                  use that gid. Get the username and the lookup the SID */
-
-               if ( !(grp = getgrgid(state->request.data.gid)) )
-                       return WINBINDD_ERROR;
-
-               if ( !(domain = find_our_domain()) ) {
-                       DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
-                       return WINBINDD_ERROR;
-               }
-
-               if ( !winbindd_lookup_sid_by_name(domain, domain->name, grp->gr_name, &sid, &type) )
-                       return WINBINDD_ERROR;
-               
-               if ( type!=SID_NAME_DOM_GRP && type!=SID_NAME_ALIAS )
-                       return WINBINDD_ERROR;
-               
-               /* don't fail if we can't store it */
-               
-               id.gid = grp->gr_gid;
-               idmap_set_mapping( &sid, id, ID_GROUPID );
-               
-               goto done;
+
+       if (idmap_proxyonly()) {
+               DEBUG(8, ("IDMAP proxy only\n"));
+               return WINBINDD_ERROR;
        }
 
-       /* Lookup sid for this uid */
-       
-       if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid))) {
-               DEBUG(1, ("Could not convert gid %lu to sid\n",
-                         (unsigned long)state->request.data.gid));
+       status = idmap_gid_to_sid(&sid, state->request.data.gid,
+                                 ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+       if (NT_STATUS_IS_OK(status)) {
+               sid_to_string(state->response.data.sid.sid, &sid);
+               state->response.data.sid.type = SID_NAME_USER;
+               return WINBINDD_OK;
+       }
+
+       if (is_in_gid_range(state->request.data.gid)) {
+               /* This is winbind's, so we should better have succeeded
+                * above. */
                return WINBINDD_ERROR;
        }
 
-done:
-       /* Construct sid and return it */
-       sid_to_string(state->response.data.sid.sid, &sid);
-       state->response.data.sid.type = SID_NAME_DOM_GRP;
+       /* The only chance that this is correct is that winbind trusted
+        * domains only = yes, and the user exists in nss and the domain. */
 
-       return WINBINDD_OK;
+       if (!lp_winbind_trusted_domains_only()) {
+               return WINBINDD_ERROR;
+       }
+
+       /* The only chance that this is correct is that winbind trusted
+        * domains only = yes, and the user exists in nss and the domain. */
+
+       gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
+       if (gid2sid_state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               return WINBINDD_ERROR;
+       }
+
+       gid2sid_state->cli_state = state;
+       gid2sid_state->gid = state->request.data.gid;
+
+       winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
+                               gid2sid_gid2name_recv, gid2sid_state);
+       return WINBINDD_PENDING;
+}
+
+static void gid2sid_gid2name_recv(void *private, BOOL success,
+                                 const char *username)
+{
+       struct gid2sid_state *state =
+               talloc_get_type_abort(private, struct gid2sid_state);
+
+       DEBUG(10, ("gid2sid: gid %lu has name %s\n",
+                  (unsigned long)state->gid, username));
+
+       fstrcpy(state->name, username);
+
+       if (!success) {
+               state->cli_state->response.result = WINBINDD_ERROR;
+               request_finished(state->cli_state);
+               return;
+       }
+
+       winbindd_lookupname_async(state->cli_state->mem_ctx,
+                                 find_our_domain()->name, username,
+                                 gid2sid_lookupname_recv, state);
+}
+
+static void gid2sid_lookupname_recv(void *private, BOOL success,
+                                   const DOM_SID *sid, enum SID_NAME_USE type)
+{
+       struct gid2sid_state *state =
+               talloc_get_type_abort(private, struct gid2sid_state);
+       unid_t id;
+
+       if ((!success) ||
+           ((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
+               state->cli_state->response.result = WINBINDD_ERROR;
+               request_finished(state->cli_state);
+               return;
+       }
+
+       state->sid = *sid;
+       state->type = type;
+
+       id.gid = state->gid;
+       idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
+                               gid2sid_idmap_set_mapping_recv, state );
+}
+
+static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success)
+{
+       struct gid2sid_state *state = private;
+
+       /* don't fail if we can't store it */
+
+       sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
+       state->cli_state->response.data.sid.type = state->type;
+       state->cli_state->response.result = WINBINDD_OK;
+       request_finished(state->cli_state);
 }
 
 enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
@@ -491,6 +517,15 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
        }
 
+       async_request(state->mem_ctx, idmap_child(),
+                     &state->request, &state->response,
+                     request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain,
+                                               struct winbindd_cli_state *state)
+{
        /* We tell idmap to always allocate a user RID. There might be a good
         * reason to keep RID allocation for users to even and groups to
         * odd. This needs discussion I think. For now only allocate user
@@ -502,3 +537,45 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
 
        return WINBINDD_OK;
 }
+
+enum winbindd_result winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state)
+{
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
+                         "denied!\n"));
+               return WINBINDD_ERROR;
+       }
+
+       async_request(state->mem_ctx, idmap_child(),
+                     &state->request, &state->response,
+                     request_finished_cont, state);
+       return WINBINDD_PENDING;
+}
+
+enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain,
+                                                       struct winbindd_cli_state *state)
+{
+       NTSTATUS result;
+       DOM_SID sid;
+
+       /* We tell idmap to always allocate a user RID. This is really
+        * historic and needs to be fixed. I *think* this has to do with the
+        * way winbind determines its free RID space. */
+
+       result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid,
+                                   USER_RID_TYPE);
+
+       if (!NT_STATUS_IS_OK(result))
+               return WINBINDD_ERROR;
+
+       sid_copy(&sid, get_global_sam_sid());
+       sid_append_rid(&sid, state->response.data.rid_and_gid.rid);
+
+       result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid,
+                                 0);
+
+       if (!NT_STATUS_IS_OK(result))
+               return WINBINDD_ERROR;
+
+       return WINBINDD_OK;
+}
index 7a9b5cf96a0eb838bf36cef174e842b5bef37922..d19279399325984f672bf3e73347650e0df32a9b 100644 (file)
@@ -106,174 +106,295 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
        return True;
 }
 
-/* Return a password structure from a username.  */
+/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
 
-enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) 
+enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
+                                           struct winbindd_cli_state *state)
 {
+       DOM_SID sid;
        WINBIND_USERINFO user_info;
-       DOM_SID user_sid;
        NTSTATUS status;
-       fstring name_domain, name_user;
-       enum SID_NAME_USE name_type;
-       struct winbindd_domain *domain;
-       TALLOC_CTX *mem_ctx;
-       
+
        /* Ensure null termination */
-       state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+       state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
 
-       DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
-                 state->request.data.username));
-       
-       /* Parse domain and username */
+       DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, 
+                 state->request.data.sid));
 
-       parse_domain_user(state->request.data.username, 
-                         name_domain, name_user);
-       
-       /* should we deal with users for our domain? */
-       
-       if ((domain = find_domain_from_name(name_domain)) == NULL) {
-               DEBUG(5, ("no such domain: %s\n", name_domain));
+       if (!string_to_sid(&sid, state->request.data.sid)) {
+               DEBUG(5, ("%s not a SID\n", state->request.data.sid));
                return WINBINDD_ERROR;
        }
-       
-       if ( domain->primary && lp_winbind_trusted_domains_only()) {
-               DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n", 
-                       name_domain, name_user));
-               return WINBINDD_ERROR;
-       }       
-       
-       /* Get rid and name type from name */
 
-       if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, &name_type)) {
-               DEBUG(1, ("user '%s' does not exist\n", name_user));
+       status = domain->methods->query_user(domain, state->mem_ctx,
+                                            &sid, &user_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("error getting user info for sid %s\n",
+                         sid_string_static(&sid)));
                return WINBINDD_ERROR;
        }
 
-       if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
-               DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, 
-                         name_type));
-               return WINBINDD_ERROR;
-       }
-       
-       /* Get some user info. */
-    
-       if (!(mem_ctx = talloc_init("winbindd_getpwnam([%s]\\[%s])", 
-                                         name_domain, name_user))) {
-               DEBUG(1, ("out of memory\n"));
+       fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
+       fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
+       if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
+                               &state->response.data.user_info.group_rid)) {
+               DEBUG(1, ("Could not extract group rid out of %s\n",
+                         sid_string_static(&sid)));
                return WINBINDD_ERROR;
        }
 
-       status = domain->methods->query_user(domain, mem_ctx, &user_sid, 
-                                            &user_info);
+       return WINBINDD_OK;
+}
 
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("error getting user info for user '[%s]\\[%s]'\n", 
-                         name_domain, name_user));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+struct getpwsid_state {
+       struct winbindd_cli_state *state;
+       struct winbindd_domain *domain;
+       char *username;
+       char *fullname;
+       DOM_SID user_sid;
+       uid_t uid;
+       DOM_SID group_sid;
+       gid_t gid;
+};
+
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+                                   const char *acct_name,
+                                   const char *full_name, uint32 group_rid);
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid);
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid);
+
+static void winbindd_getpwsid(struct winbindd_cli_state *state,
+                             const DOM_SID *sid)
+{
+       struct getpwsid_state *s;
+
+       s = TALLOC_P(state->mem_ctx, struct getpwsid_state);
+       if (s == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               goto error;
        }
-    
-       /* Now take all this information and fill in a passwd structure */      
-       if (!winbindd_fill_pwent(name_domain, user_info.acct_name, 
-                                user_info.user_sid, user_info.group_sid, 
-                                user_info.full_name,
-                                &state->response.data.pw)) {
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+
+       s->state = state;
+       s->domain = find_domain_from_sid_noinit(sid);
+       if (s->domain == NULL) {
+               DEBUG(3, ("Could not find domain for sid %s\n",
+                         sid_string_static(sid)));
+               goto error;
        }
 
-       talloc_destroy(mem_ctx);
+       sid_copy(&s->user_sid, sid);
+
+       query_user_async(s->state->mem_ctx, s->domain, sid,
+                        getpwsid_queryuser_recv, s);
+       return;
+
+ error:
+       s->state->response.result = WINBINDD_ERROR;
+       request_finished(state);
+}
        
-       return WINBINDD_OK;
-}       
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+                                   const char *acct_name,
+                                   const char *full_name, uint32 group_rid)
+{
+       struct getpwsid_state *s =
+               talloc_get_type_abort(private, struct getpwsid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not query user %s\\%s\n", s->domain->name,
+                         s->username));
+               s->state->response.result = WINBINDD_ERROR;
+               request_finished(s->state);
+               return;
+       }
 
-/* Return a password structure given a uid number */
+       s->username = talloc_strdup(s->state->mem_ctx, acct_name);
+       s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
+       sid_copy(&s->group_sid, &s->domain->sid);
+       sid_append_rid(&s->group_sid, group_rid);
 
-enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+       winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
+                              getpwsid_sid2uid_recv, s);
+}
+
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid)
 {
-       DOM_SID user_sid;
-       struct winbindd_domain *domain;
-       fstring dom_name;
-       fstring user_name;
-       enum SID_NAME_USE name_type;
-       WINBIND_USERINFO user_info;
-       TALLOC_CTX *mem_ctx;
-       NTSTATUS status;
-       gid_t gid;
-       
-       /* Bug out if the uid isn't in the winbind range */
+       struct getpwsid_state *s =
+               talloc_get_type_abort(private, struct getpwsid_state);
+
+       if (!success) {
+               DEBUG(5, ("Could not query user's %s\\%s uid\n",
+                         s->domain->name, s->username));
+               s->state->response.result = WINBINDD_ERROR;
+               request_finished(s->state);
+               return;
+       }
 
-       if ((state->request.data.uid < server_state.uid_low ) ||
-           (state->request.data.uid > server_state.uid_high))
-               return WINBINDD_ERROR;
+       s->uid = uid;
+       winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+                              getpwsid_sid2gid_recv, s);
+}
 
-       DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid, 
-                 (unsigned long)state->request.data.uid));
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
+{
+       struct getpwsid_state *s =
+               talloc_get_type_abort(private, struct getpwsid_state);
+       struct winbindd_pw *pw;
+       fstring output_username;
+       char *homedir;
+       char *shell;
 
-       /* Get rid from uid */
+       s->state->response.result = WINBINDD_ERROR;
 
-       if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&user_sid, state->request.data.uid))) {
-               DEBUG(1, ("could not convert uid %lu to SID\n", 
-                         (unsigned long)state->request.data.uid));
-               return WINBINDD_ERROR;
+       if (!success) {
+               DEBUG(5, ("Could not query user's %s\\%s\n gid",
+                         s->domain->name, s->username));
+               goto done;
        }
+
+       s->gid = gid;
+
+       pw = &s->state->response.data.pw;
+       pw->pw_uid = s->uid;
+       pw->pw_gid = s->gid;
+       fill_domain_username(output_username, s->domain->name, s->username); 
+       safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
+       safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
+
+       /* Home directory and shell - use template config parameters.  The
+          defaults are /tmp for the home directory and /bin/false for
+          shell. */
        
-       /* Get name and name type from rid */
+       /* The substitution of %U and %D in the 'template homedir' is done
+          by alloc_sub_specified() below. */
 
-       if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) {
-               fstring temp;
-               
-               sid_to_string(temp, &user_sid);
-               DEBUG(1, ("could not lookup sid %s\n", temp));
-               return WINBINDD_ERROR;
+       fstrcpy(current_user_info.domain, s->domain->name);
+
+       homedir = alloc_sub_specified(lp_template_homedir(), s->username,
+                                     s->domain->name, pw->pw_uid, pw->pw_gid);
+       if (homedir == NULL) {
+               DEBUG(5, ("Could not compose homedir\n"));
+               goto done;
        }
+       safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
+       SAFE_FREE(homedir);
        
-       domain = find_domain_from_sid(&user_sid);
+       shell = alloc_sub_specified(lp_template_shell(), s->username,
+                                   s->domain->name, pw->pw_uid, pw->pw_gid);
+       if (shell == NULL) {
+               DEBUG(5, ("Could not compose shell\n"));
+               goto done;
+       }
+       safe_strcpy(pw->pw_shell, shell, sizeof(pw->pw_shell) - 1);
+       SAFE_FREE(shell);
+
+       /* Password - set to "x" as we can't generate anything useful here.
+          Authentication can be done using the pam_winbind module. */
+
+       safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+
+       s->state->response.result = WINBINDD_OK;
+
+ done:
+       request_finished(s->state);
+}
 
-       if (!domain) {
-               DEBUG(1,("Can't find domain from sid\n"));
+/* Return a password structure from a username.  */
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+                                  const DOM_SID *sid, enum SID_NAME_USE type);
+
+enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
+{
+       struct winbindd_domain *domain;
+       fstring domname, username;
+
+       /* Ensure null termination */
+       state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+
+       DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
+                 state->request.data.username));
+
+       if (!parse_domain_user(state->request.data.username, domname,
+                              username)) {
+               DEBUG(0, ("Could not parse domain user: %s\n",
+                         state->request.data.username));
                return WINBINDD_ERROR;
        }
-
-       /* Get some user info */
        
-       if (!(mem_ctx = talloc_init("winbind_getpwuid(%lu)",
-                                   (unsigned long)state->request.data.uid))) {
+       /* Get info for the domain */
 
-               DEBUG(1, ("out of memory\n"));
+       domain = find_lookup_domain_from_name(domname);
+
+       if (domain == NULL) {
+               DEBUG(7, ("could not find domain entry for domain %s\n",
+                         domname));
                return WINBINDD_ERROR;
        }
 
-       status = domain->methods->query_user(domain, mem_ctx, &user_sid, 
-                                            &user_info);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("error getting user info for user '%s'\n", 
-                         user_name));
-               talloc_destroy(mem_ctx);
+       if ( domain->primary && lp_winbind_trusted_domains_only()) {
+               DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+                        "getgroups() for %s\\%s.\n", domname, username));
                return WINBINDD_ERROR;
+       }       
+
+       /* Get rid and name type from name.  The following costs 1 packet */
+
+       winbindd_lookupname_async(state->mem_ctx, domname, username,
+                                 getpwnam_name2sid_recv, state);
+       return WINBINDD_PENDING;
+}
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+                                  const DOM_SID *sid, enum SID_NAME_USE type)
+{
+       struct winbindd_cli_state *state = private;
+
+       if (!success) {
+               DEBUG(5, ("Could not lookup name for user %s\n",
+                         state->request.data.username));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
+       }
+
+       if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+               DEBUG(5, ("%s is not a user\n", state->request.data.username));
+               state->response.result = WINBINDD_ERROR;
+               request_finished(state);
+               return;
        }
+
+       winbindd_getpwsid(state, sid);
+}
+
+/* Return a password structure given a uid number */
+
+enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+{
+       DOM_SID user_sid;
+       NTSTATUS status;
        
-       /* Check group has a gid number */
+       /* Bug out if the uid isn't in the winbind range */
 
-       if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_info.group_sid, &gid, 0))) {
-               DEBUG(1, ("error getting group id for user %s\n", user_name));
-               talloc_destroy(mem_ctx);
+       if ((state->request.data.uid < server_state.uid_low ) ||
+           (state->request.data.uid > server_state.uid_high))
                return WINBINDD_ERROR;
-       }
 
-       /* Fill in password structure */
+       DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid, 
+                 (unsigned long)state->request.data.uid));
 
-       if (!winbindd_fill_pwent(domain->name, user_info.acct_name, user_info.user_sid, 
-                                user_info.group_sid,
-                                user_info.full_name, &state->response.data.pw)) {
-               talloc_destroy(mem_ctx);
+       status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
+                                 ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(5, ("Could not find SID for uid %lu\n",
+                         (unsigned long)state->request.data.uid));
                return WINBINDD_ERROR;
        }
-       
-       talloc_destroy(mem_ctx);
 
-       return WINBINDD_OK;
+       winbindd_getpwsid(state, &user_sid);
+       return WINBINDD_PENDING;
 }
 
 /*
@@ -365,14 +486,13 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
    field is incremented to the index of the next user to fetch.  Return True if
    some users were returned, False otherwise. */
 
-static BOOL get_sam_user_entries(struct getent_state *ent)
+static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
 {
        NTSTATUS status;
        uint32 num_entries;
        WINBIND_USERINFO *info;
        struct getpwent_user *name_list = NULL;
        BOOL result = False;
-       TALLOC_CTX *mem_ctx;
        struct winbindd_domain *domain;
        struct winbindd_methods *methods;
        unsigned int i;
@@ -380,10 +500,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
        if (ent->num_sam_entries)
                return False;
 
-       if (!(mem_ctx = talloc_init("get_sam_user_entries(%s)",
-                                   ent->domain_name)))
-               return False;
-
        if (!(domain = find_domain_from_name(ent->domain_name))) {
                DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
                          ent->domain_name));
@@ -433,8 +549,10 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
                }
                
                /* User and group ids */
-               sid_copy(&name_list[ent->num_sam_entries+i].user_sid, info[i].user_sid);
-               sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_sid);
+               sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
+                        &info[i].user_sid);
+               sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
+                        &info[i].group_sid);
        }
                
        ent->num_sam_entries += num_entries;
@@ -447,8 +565,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
 
  done:
 
-       talloc_destroy(mem_ctx);
-
        return result;
 }
 
@@ -497,7 +613,8 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
 
                if (ent->num_sam_entries == ent->sam_entry_index) {
 
-                       while(ent && !get_sam_user_entries(ent)) {
+                       while(ent &&
+                             !get_sam_user_entries(ent, state->mem_ctx)) {
                                struct getent_state *next_ent;
 
                                /* Free state information for this domain */
@@ -560,14 +677,10 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
        uint32 num_entries = 0, total_entries = 0;
        char *ted, *extra_data = NULL;
        int extra_data_len = 0;
-       TALLOC_CTX *mem_ctx;
        enum winbindd_result rv = WINBINDD_ERROR;
 
        DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
 
-       if (!(mem_ctx = talloc_init("winbindd_list_users")))
-               return WINBINDD_ERROR;
-
        /* Ensure null termination */
        state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';  
        which_domain = state->request.domain_name;
@@ -585,14 +698,11 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
                   
                if ( *which_domain && !strequal(which_domain, domain->name) )
                        continue;
-
-               if ( !domain->initialized )
-                       set_dc_type_and_flags( domain );
                        
                methods = domain->methods;
 
                /* Query display info */
-               status = methods->query_user_list(domain, mem_ctx, 
+               status = methods->query_user_list(domain, state->mem_ctx, 
                                                  &num_entries, &info);
 
                if (num_entries == 0)
@@ -646,7 +756,5 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
 
  done:
 
-       talloc_destroy(mem_ctx);
-
        return rv;
 }
index 739a7ed2a73355cf268ef1e424753bf3cd0da69e..21ae4611c25721e15a41de79fbe6be66d9f5cab6 100644 (file)
@@ -24,9 +24,6 @@
 #include "includes.h"
 #include "winbindd.h"
 
-extern struct winbindd_methods cache_methods;
-extern struct winbindd_methods passdb_methods;
-
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
@@ -65,8 +62,7 @@ struct winbindd_domain *domain_list(void)
        /* Initialise list */
 
        if (!_domain_list) 
-               if (!init_domain_list()) 
-                       return NULL;
+               init_domain_list();
 
        return _domain_list;
 }
@@ -91,12 +87,7 @@ static BOOL is_internal_domain(const DOM_SID *sid)
        if (sid == NULL)
                return False;
 
-       if ( sid_compare_domain( sid, get_global_sam_sid() ) == 0 )
-               return True;
-       if ( sid_compare_domain( sid, &global_sid_Builtin ) == 0 )
-               return True;
-
-       return False;
+       return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
 }
 
 
@@ -181,80 +172,115 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
   rescan our domains looking for new trusted domains
 ********************************************************************/
 
+struct trustdom_state {
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_response *response;
+};
+
+static void trustdom_recv(void *private, BOOL success);
+
 static void add_trusted_domains( struct winbindd_domain *domain )
 {
        TALLOC_CTX *mem_ctx;
-       NTSTATUS result;
-       time_t t;
-       char **names;
-       char **alt_names;
-       int num_domains = 0;
-       DOM_SID *dom_sids, null_sid;
-       int i;
-       struct winbindd_domain *new_domain;
-
-       /* trusted domains might be disabled */
-       if (!lp_allow_trusted_domains()) {
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+
+       struct trustdom_state *state;
+
+       mem_ctx = talloc_init("add_trusted_domains");
+       if (mem_ctx == NULL) {
+               DEBUG(0, ("talloc_init failed\n"));
                return;
        }
 
-       DEBUG(5, ("scanning trusted domain list\n"));
+       request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+       response = TALLOC_P(mem_ctx, struct winbindd_response);
+       state = TALLOC_P(mem_ctx, struct trustdom_state);
 
-       if (!(mem_ctx = talloc_init("init_domain_list")))
+       if ((request == NULL) || (response == NULL) || (state == NULL)) {
+               DEBUG(0, ("talloc failed\n"));
+               talloc_destroy(mem_ctx);
                return;
-          
-       ZERO_STRUCTP(&null_sid);
+       }
 
-       t = time(NULL);
-       
-       /* ask the DC what domains it trusts */
-       
-       result = domain->methods->trusted_domains(domain, mem_ctx, (unsigned int *)&num_domains,
-               &names, &alt_names, &dom_sids);
-               
-       if ( NT_STATUS_IS_OK(result) ) {
+       state->mem_ctx = mem_ctx;
+       state->response = response;
 
-               /* Add each domain to the trusted domain list */
-               
-               for(i = 0; i < num_domains; i++) {
-                       DEBUG(10,("Found domain %s\n", names[i]));
-                       add_trusted_domain(names[i], alt_names?alt_names[i]:NULL,
-                                          &cache_methods, &dom_sids[i]);
-                                          
-                       /* if the SID was empty, we better set it now */
-                       
-                       if ( sid_equal(&dom_sids[i], &null_sid) ) {
-                               enum SID_NAME_USE type;
-                               new_domain = find_domain_from_name(names[i]);
-                                
-                               /* this should never happen */
-                               if ( !new_domain ) {    
-                                       DEBUG(0,("rescan_trust_domains: can't find the domain I just added! [%s]\n",
-                                               names[i]));
-                                       break;
-                               }
-                                
-                               /* call the cache method; which will operate on the winbindd_domain \
-                                  passed in and choose either rpc or ads as appropriate */
-
-                               result = domain->methods->name_to_sid( domain,
-                                       mem_ctx,
-                                       new_domain->name,
-                                       NULL,
-                                       &new_domain->sid,
-                                       &type);
-                                
-                               if ( NT_STATUS_IS_OK(result) )
-                                       sid_copy( &dom_sids[i], &new_domain->sid );
-                       }
+       request->length = sizeof(*request);
+       request->cmd = WINBINDD_LIST_TRUSTDOM;
+
+       async_domain_request(mem_ctx, domain, request, response,
+                            trustdom_recv, state);
+}
+
+static void trustdom_recv(void *private, BOOL success)
+{
+       extern struct winbindd_methods cache_methods;
+       struct trustdom_state *state =
+               talloc_get_type_abort(private, struct trustdom_state);
+       struct winbindd_response *response = state->response;
+       char *p;
+
+       if ((!success) || (response->result != WINBINDD_OK)) {
+               DEBUG(1, ("Could not receive trustdoms\n"));
+               talloc_destroy(state->mem_ctx);
+               return;
+       }
+
+       p = response->extra_data;
+
+       while ((p != NULL) && (*p != '\0')) {
+               char *q, *sidstr, *alt_name;
+               DOM_SID sid;
+
+               alt_name = strchr(p, '\\');
+               if (alt_name == NULL) {
+                       DEBUG(0, ("Got invalid trustdom response\n"));
+                       break;
+               }
+
+               *alt_name = '\0';
+               alt_name += 1;
+
+               sidstr = strchr(alt_name, '\\');
+               if (sidstr == NULL) {
+                       DEBUG(0, ("Got invalid trustdom response\n"));
+                       break;
+               }
+
+               *sidstr = '\0';
+               sidstr += 1;
+
+               q = strchr(sidstr, '\n');
+               if (q != NULL)
+                       *q = '\0';
+
+               if (!string_to_sid(&sid, sidstr)) {
+                       DEBUG(0, ("Got invalid trustdom response\n"));
+                       break;
+               }
+
+               if (find_domain_from_name_noinit(p) == NULL) {
+                       struct winbindd_domain *domain;
+                       char *alternate_name = NULL;
                        
-                       /* store trusted domain in the cache */
-                       trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL,
-                                            &dom_sids[i], t + WINBINDD_RESCAN_FREQ);
+                       /* use the real alt_name if we have one, else pass in NULL */
+
+                       if ( !strequal( alt_name, "(null)" ) )
+                               alternate_name = alt_name;
+
+                       domain = add_trusted_domain(p, alternate_name,
+                                                   &cache_methods,
+                                                   &sid);
+                       setup_domain_child(domain, &domain->child, NULL);
                }
+               p=q;
+               if (p != NULL)
+                       p += 1;
        }
 
-       talloc_destroy(mem_ctx);
+       SAFE_FREE(response->extra_data);
+       talloc_destroy(state->mem_ctx);
 }
 
 /********************************************************************
@@ -264,30 +290,204 @@ static void add_trusted_domains( struct winbindd_domain *domain )
 void rescan_trusted_domains( void )
 {
        time_t now = time(NULL);
-       struct winbindd_domain *mydomain = NULL;
        
        /* see if the time has come... */
        
-       if ( (now > last_trustdom_scan) && ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
+       if ((now >= last_trustdom_scan) &&
+           ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
                return;
                
-       if ( (mydomain = find_our_domain()) == NULL ) {
-               DEBUG(0,("rescan_trusted_domains: Can't find my own domain!\n"));
-               return;
-       }
-       
        /* this will only add new domains we didn't already know about */
        
-       add_trusted_domains( mydomain );
+       add_trusted_domains( find_our_domain() );
 
        last_trustdom_scan = now;
        
        return; 
 }
 
+struct init_child_state {
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_domain *domain;
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+       void (*continuation)(void *private, BOOL success);
+       void *private;
+};
+
+static void init_child_recv(void *private, BOOL success);
+static void init_child_getdc_recv(void *private, BOOL success);
+
+enum winbindd_result init_child_connection(struct winbindd_domain *domain,
+                                          void (*continuation)(void *private,
+                                                               BOOL success),
+                                          void *private)
+{
+       TALLOC_CTX *mem_ctx;
+       struct winbindd_request *request;
+       struct winbindd_response *response;
+       struct init_child_state *state;
+
+       mem_ctx = talloc_init("init_child_connection");
+       if (mem_ctx == NULL) {
+               DEBUG(0, ("talloc_init failed\n"));
+               return WINBINDD_ERROR;
+       }
+
+       request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
+       response = TALLOC_P(mem_ctx, struct winbindd_response);
+       state = TALLOC_P(mem_ctx, struct init_child_state);
+
+       if ((request == NULL) || (response == NULL) || (state == NULL)) {
+               DEBUG(0, ("talloc failed\n"));
+               continuation(private, False);
+               return WINBINDD_ERROR;
+       }
+
+       request->length = sizeof(*request);
+
+       state->mem_ctx = mem_ctx;
+       state->domain = domain;
+       state->request = request;
+       state->response = response;
+       state->continuation = continuation;
+       state->private = private;
+
+       if (domain->primary) {
+               /* The primary domain has to find the DC name itself */
+               request->cmd = WINBINDD_INIT_CONNECTION;
+               fstrcpy(request->domain_name, domain->name);
+               request->data.init_conn.is_primary = True;
+               fstrcpy(request->data.init_conn.dcname, "");
+
+               async_request(mem_ctx, &domain->child, request, response,
+                             init_child_recv, state);
+               return WINBINDD_PENDING;
+       }
+
+       /* This is *not* the primary domain, let's ask our DC about a DC
+        * name */
+
+       request->cmd = WINBINDD_GETDCNAME;
+       fstrcpy(request->domain_name, domain->name);
+
+       async_domain_request(mem_ctx, find_our_domain(), request, response,
+                            init_child_getdc_recv, state);
+       return WINBINDD_PENDING;
+}
+
+static void init_child_getdc_recv(void *private, BOOL success)
+{
+       struct init_child_state *state =
+               talloc_get_type_abort(private, struct init_child_state);
+       const char *dcname = "";
+
+       DEBUG(10, ("Received getdcname response\n"));
+
+       if (success && (state->response->result == WINBINDD_OK)) {
+               dcname = state->response->data.dc_name;
+       }
+
+       state->request->cmd = WINBINDD_INIT_CONNECTION;
+       fstrcpy(state->request->domain_name, state->domain->name);
+       state->request->data.init_conn.is_primary = False;
+       fstrcpy(state->request->data.init_conn.dcname, dcname);
+
+       async_request(state->mem_ctx, &state->domain->child,
+                     state->request, state->response,
+                     init_child_recv, state);
+}
+
+static void init_child_recv(void *private, BOOL success)
+{
+       struct init_child_state *state =
+               talloc_get_type_abort(private, struct init_child_state);
+
+       DEBUG(5, ("Received child initialization response for domain %s\n",
+                 state->domain->name));
+
+       if ((!success) || (state->response->result != WINBINDD_OK)) {
+               DEBUG(3, ("Could not init child\n"));
+               state->continuation(state->private, False);
+               talloc_destroy(state->mem_ctx);
+               return;
+       }
+
+       fstrcpy(state->domain->name,
+               state->response->data.domain_info.name);
+       fstrcpy(state->domain->alt_name,
+               state->response->data.domain_info.alt_name);
+       string_to_sid(&state->domain->sid,
+                     state->response->data.domain_info.sid);
+       state->domain->native_mode =
+               state->response->data.domain_info.native_mode;
+       state->domain->active_directory =
+               state->response->data.domain_info.active_directory;
+       state->domain->sequence_number =
+               state->response->data.domain_info.sequence_number;
+
+       state->domain->initialized = 1;
+
+       if (state->continuation != NULL)
+               state->continuation(state->private, True);
+       talloc_destroy(state->mem_ctx);
+}
+
+enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
+                                                  struct winbindd_cli_state *state)
+{
+       struct in_addr ipaddr;
+
+       /* Ensure null termination */
+       state->request.domain_name
+               [sizeof(state->request.domain_name)-1]='\0';
+       state->request.data.init_conn.dcname
+               [sizeof(state->request.data.init_conn.dcname)-1]='\0';
+
+       fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
+
+       if (strlen(domain->dcname) > 0) {
+               if (!resolve_name(domain->dcname, &ipaddr, 0x20)) {
+                       DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
+                                 domain->dcname, domain->name));
+                       return WINBINDD_ERROR;
+               }
+
+               domain->dcaddr.sin_family = PF_INET;
+               putip((char *)&(domain->dcaddr.sin_addr), (char *)&ipaddr);
+               domain->dcaddr.sin_port = 0;
+       }
+
+       set_dc_type_and_flags(domain);
+
+       if (!domain->initialized) {
+               DEBUG(1, ("Could not initialize domain %s\n",
+                         state->request.domain_name));
+               return WINBINDD_ERROR;
+       }
+
+       fstrcpy(state->response.data.domain_info.name, domain->name);
+       fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
+       fstrcpy(state->response.data.domain_info.sid,
+               sid_string_static(&domain->sid));
+       
+       state->response.data.domain_info.native_mode
+               = domain->native_mode;
+       state->response.data.domain_info.active_directory
+               = domain->active_directory;
+       state->response.data.domain_info.primary
+               = domain->primary;
+       state->response.data.domain_info.sequence_number =
+               domain->sequence_number;
+
+       return WINBINDD_OK;
+}
+
 /* Look up global info for the winbind daemon */
-BOOL init_domain_list(void)
+void init_domain_list(void)
 {
+       extern struct winbindd_methods cache_methods;
+       extern struct winbindd_methods passdb_methods;
        struct winbindd_domain *domain;
 
        /* Free existing list */
@@ -297,50 +497,35 @@ BOOL init_domain_list(void)
 
        if (IS_DC) {
                domain = add_trusted_domain(get_global_sam_name(), NULL,
-                                           &passdb_methods, get_global_sam_sid());
+                                           &passdb_methods,
+                                           get_global_sam_sid());
        } else {
-       
-               domain = add_trusted_domain( lp_workgroup(), lp_realm(),
-                                            &cache_methods, NULL);
-       
-               /* set flags about native_mode, active_directory */
-               set_dc_type_and_flags(domain);
-       }
 
-       domain->primary = True;
+               DOM_SID our_sid;
 
-       /* get any alternate name for the primary domain */
-       
-       cache_methods.alternate_name(domain);
-       
-       /* now we have the correct netbios (short) domain name */
+               if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
+                       DEBUG(0, ("Could not fetch our SID - did we join?\n"));
+               }
        
-       if ( *domain->name )
-               set_global_myworkgroup( domain->name );
-               
-       if (!secrets_fetch_domain_sid(domain->name, &domain->sid)) {
-               DEBUG(1, ("Could not fetch sid for our domain %s\n",
-                         domain->name));
-               return False;
+               domain = add_trusted_domain( lp_workgroup(), lp_realm(),
+                                            &cache_methods, &our_sid);
        }
 
-       /* do an initial scan for trusted domains */
-       add_trusted_domains(domain);
-
+       domain->primary = True;
+       setup_domain_child(domain, &domain->child, NULL);
 
        /* Add our local SAM domains */
 
-       add_trusted_domain("BUILTIN", NULL, &passdb_methods,
-                          &global_sid_Builtin);
+       domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
+                                   &global_sid_Builtin);
+       setup_domain_child(domain, &domain->child, NULL);
 
        if (!IS_DC) {
-               add_trusted_domain(get_global_sam_name(), NULL,
-                                  &passdb_methods, get_global_sam_sid());
+               domain = add_trusted_domain(get_global_sam_name(), NULL,
+                                           &passdb_methods,
+                                           get_global_sam_sid());
+               setup_domain_child(domain, &domain->child, NULL);
        }
-       
-       /* avoid rescanning this right away */
-       last_trustdom_scan = time(NULL);
-       return True;
 }
 
 /** 
@@ -355,7 +540,7 @@ BOOL init_domain_list(void)
  * @return The domain structure for the named domain, if it is working.
  */
 
-struct winbindd_domain *find_domain_from_name(const char *domain_name)
+struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
 {
        struct winbindd_domain *domain;
 
@@ -363,10 +548,8 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
 
        for (domain = domain_list(); domain != NULL; domain = domain->next) {
                if (strequal(domain_name, domain->name) ||
-                   (domain->alt_name[0] && strequal(domain_name, domain->alt_name))) {
-                       if (!domain->initialized)
-                               set_dc_type_and_flags(domain);
-
+                   (domain->alt_name[0] &&
+                    strequal(domain_name, domain->alt_name))) {
                        return domain;
                }
        }
@@ -376,20 +559,32 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
        return NULL;
 }
 
+struct winbindd_domain *find_domain_from_name(const char *domain_name)
+{
+       struct winbindd_domain *domain;
+
+       domain = find_domain_from_name_noinit(domain_name);
+
+       if (domain == NULL)
+               return NULL;
+
+       if (!domain->initialized)
+               set_dc_type_and_flags(domain);
+
+       return domain;
+}
+
 /* Given a domain sid, return the struct winbindd domain info for it */
 
-struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
+struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
 {
        struct winbindd_domain *domain;
 
        /* Search through list */
 
        for (domain = domain_list(); domain != NULL; domain = domain->next) {
-               if (sid_compare_domain(sid, &domain->sid) == 0) {
-                       if (!domain->initialized)
-                               set_dc_type_and_flags(domain);
+               if (sid_compare_domain(sid, &domain->sid) == 0)
                        return domain;
-               }
        }
 
        /* Not found */
@@ -399,6 +594,21 @@ struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
 
 /* Given a domain sid, return the struct winbindd domain info for it */
 
+struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
+{
+       struct winbindd_domain *domain;
+
+       domain = find_domain_from_sid_noinit(sid);
+
+       if (domain == NULL)
+               return NULL;
+
+       if (!domain->initialized)
+               set_dc_type_and_flags(domain);
+
+       return domain;
+}
+
 struct winbindd_domain *find_our_domain(void)
 {
        struct winbindd_domain *domain;
@@ -410,11 +620,24 @@ struct winbindd_domain *find_our_domain(void)
                        return domain;
        }
 
-       /* Not found */
-
+       smb_panic("Could not find our domain\n");
        return NULL;
 }
 
+struct winbindd_domain *find_builtin_domain(void)
+{
+       DOM_SID sid;
+       struct winbindd_domain *domain;
+
+       string_to_sid(&sid, "S-1-5-32");
+       domain = find_domain_from_sid(&sid);
+
+       if (domain == NULL)
+               smb_panic("Could not find BUILTIN domain\n");
+
+       return domain;
+}
+
 /* Find the appropriate domain to lookup a name or SID */
 
 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
@@ -436,31 +659,24 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
 {
        if (IS_DC || strequal(domain_name, "BUILTIN") ||
            strequal(domain_name, get_global_sam_name()))
-               return find_domain_from_name(domain_name);
+               return find_domain_from_name_noinit(domain_name);
 
        return find_our_domain();
 }
 
 /* Lookup a sid in a domain from a name */
 
-BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, 
+BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+                                struct winbindd_domain *domain, 
                                 const char *domain_name,
                                 const char *name, DOM_SID *sid, 
                                 enum SID_NAME_USE *type)
 {
        NTSTATUS result;
-        TALLOC_CTX *mem_ctx;
 
-       mem_ctx = talloc_init("lookup_sid_by_name for %s\\%s\n",
-                             domain_name, name);
-       if (!mem_ctx) 
-               return False;
-        
        /* Lookup name */
        result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
 
-       talloc_destroy(mem_ctx);
-        
        /* Return rid and type if lookup successful */
        if (!NT_STATUS_IS_OK(result)) {
                *type = SID_NAME_UNKNOWN;
@@ -480,7 +696,8 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
  * @retval True if the name exists, in which case @p name and @p type
  * are set, otherwise False.
  **/
-BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
+BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
+                                DOM_SID *sid,
                                 fstring dom_name,
                                 fstring name,
                                 enum SID_NAME_USE *type)
@@ -488,7 +705,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
        char *names;
        char *dom_names;
        NTSTATUS result;
-       TALLOC_CTX *mem_ctx;
        BOOL rv = False;
        struct winbindd_domain *domain;
 
@@ -501,9 +717,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
 
        /* Lookup name */
 
-       if (!(mem_ctx = talloc_init("winbindd_lookup_name_by_sid")))
-               return False;
-        
        result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
 
        /* Return name and type if successful */
@@ -516,12 +729,9 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
                fstrcpy(name, name_deadbeef);
        }
         
-       talloc_destroy(mem_ctx);
-
        return rv;
 }
 
-
 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
 
 void free_getent_state(struct getent_state *state)
@@ -553,31 +763,30 @@ BOOL winbindd_param_init(void)
        /* Parse winbind uid and winbind_gid parameters */
 
        if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
-               DEBUG(2, ("winbindd: idmap uid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
                return False;
        }
        
        if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
-               DEBUG(2, ("winbindd: idmap gid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
                return False;
        }
        
        return True;
 }
 
-/* Check if a domain is present in a comma-separated list of domains */
-
-BOOL check_domain_env(char *domain_env, char *domain)
+BOOL is_in_uid_range(uid_t uid)
 {
-       fstring name;
-       const char *tmp = domain_env;
-
-       while(next_token(&tmp, name, ",", sizeof(fstring))) {
-               if (strequal(name, domain))
-                       return True;
-       }
+       return ((uid >= server_state.uid_low) &&
+               (uid <= server_state.uid_high));
+}
 
-       return False;
+BOOL is_in_gid_range(gid_t gid)
+{
+       return ((gid >= server_state.gid_low) &&
+               (gid <= server_state.gid_high));
 }
 
 /* Is this a domain which we may assume no DOMAIN\ prefix? */
@@ -620,6 +829,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
        return True;
 }
 
+BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
+                             char **domain, char **user)
+{
+       fstring fstr_domain, fstr_user;
+       parse_domain_user(domuser, fstr_domain, fstr_user);
+       *domain = talloc_strdup(mem_ctx, fstr_domain);
+       *user = talloc_strdup(mem_ctx, fstr_user);
+       return ((*domain != NULL) && (*user != NULL));
+}
+
 /*
     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
     'winbind separator' options.
@@ -635,14 +854,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
 */
 void fill_domain_username(fstring name, const char *domain, const char *user)
 {
-        strlower_m(CONST_DISCARD(char *, user));
+       fstring tmp_user;
+
+       fstrcpy(tmp_user, user);
 
        if (assume_domain(domain)) {
                strlcpy(name, user, sizeof(fstring));
        } else {
                slprintf(name, sizeof(fstring) - 1, "%s%c%s",
                         domain, *lp_winbind_separator(),
-                        user);
+                        tmp_user);
        }
 }
 
@@ -764,22 +985,6 @@ int winbindd_num_clients(void)
        return _num_clients;
 }
 
-/* Help with RID -> SID conversion */
-
-DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
-                                   TALLOC_CTX *mem_ctx,
-                                   uint32 rid) 
-{
-       DOM_SID *sid;
-       sid = TALLOC_P(mem_ctx, DOM_SID);
-       if (!sid) {
-               smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
-       }
-       sid_copy(sid, &domain->sid);
-       sid_append_rid(sid, rid);
-       return sid;
-}
-       
 /*****************************************************************************
  For idmap conversion: convert one record to new format
  Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
@@ -986,52 +1191,3 @@ BOOL winbindd_upgrade_idmap(void)
 
        return idmap_convert(idmap_name);
 }
-
-/*******************************************************************
- wrapper around retrieving the trust account password
-*******************************************************************/
-
-BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
-                          time_t *pass_last_set_time, uint32 *channel)
-{
-       DOM_SID sid;
-       char *pwd;
-
-       /* if we are a DC and this is not our domain, then lookup an account
-          for the domain trust */
-          
-       if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() ) 
-       {
-               if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid, 
-                       pass_last_set_time) ) 
-               {
-                       DEBUG(0, ("get_trust_pw: could not fetch trust account "
-                                 "password for trusted domain %s\n", domain));
-                       return False;
-               }
-               
-               *channel = SEC_CHAN_DOMAIN;
-               E_md4hash(pwd, ret_pwd);
-               SAFE_FREE(pwd);
-
-               return True;
-       }
-       else    /* just get the account for our domain (covers 
-                  ROLE_DOMAIN_MEMBER as well */
-       {
-               /* get the machine trust account for our domain */
-
-               if ( !secrets_fetch_trust_account_password (lp_workgroup(), ret_pwd,
-                       pass_last_set_time, channel) ) 
-               {
-                       DEBUG(0, ("get_trust_pw: could not fetch trust account "
-                                 "password for my domain %s\n", domain));
-                       return False;
-               }
-               
-               return True;
-       }
-       
-       /* Failure */
-}
-
index 9ac1d7a075b4ec14e5aa397233081475622881a9..339624a9a87dfc01eca17618acdbd92d707e5f9f 100644 (file)
@@ -225,6 +225,7 @@ typedef struct
        int min_passwd_length;
        int oplock_break_wait_time;
        int winbind_cache_time;
+       int winbind_max_idle_children;
        int iLockSpinCount;
        int iLockSpinTime;
        char *szLdapMachineSuffix;
@@ -1223,6 +1224,7 @@ static struct parm_struct parm_table[] = {
        {"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED}, 
        {"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED}, 
        {"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED}, 
+       {"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED}, 
 
        {NULL,  P_BOOL,  P_NONE,  NULL,  NULL,  NULL,  0}
 };
@@ -1567,6 +1569,7 @@ static void init_globals(void)
        Globals.bWinbindUseDefaultDomain = False;
        Globals.bWinbindTrustedDomainsOnly = False;
        Globals.bWinbindNestedGroups = False;
+       Globals.winbind_max_idle_children = 3;
 
        Globals.bEnableRidAlgorithm = True;
 
@@ -1986,6 +1989,7 @@ FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
 FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size);
 FN_LOCAL_CHAR(lp_magicchar, magic_char)
 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
+FN_GLOBAL_INTEGER(lp_winbind_max_idle_children, &Globals.winbind_max_idle_children)
 FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
 FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
 FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
index 8a3d35defd95cc9b2e302f43b0d454497ff5e98b..6fcd4582f2dce244b8992c35d6f97bf000692365 100644 (file)
@@ -112,6 +112,44 @@ BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAM
        return True;
 }
 
+BOOL sid_to_local_user_name(const DOM_SID *sid, fstring username)
+{
+       fstring dom_name;
+       fstring name;
+       enum SID_NAME_USE type;
+
+       if (!sid_check_is_in_our_domain(sid))
+               return False;
+
+       if (!lookup_sid(sid, dom_name, name, &type))
+               return False;
+       if (type != SID_NAME_USER)
+               return False;
+       fstrcpy(username, name);
+       return True;
+}
+
+BOOL sid_to_local_dom_grp_name(const DOM_SID *sid, fstring groupname)
+{
+       fstring dom_name;
+       fstring name;
+       enum SID_NAME_USE type;
+
+       if (!sid_check_is_in_our_domain(sid))
+               return False;
+
+       if (!lookup_sid(sid, dom_name, name, &type))
+               return False;
+
+       if (type != SID_NAME_DOM_GRP)
+               return False;
+
+       fstrcpy(groupname, name);
+       return True;
+}
 
 /*****************************************************************
  Id mapping cache.  This is to avoid Winbind mappings already
@@ -250,8 +288,8 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
                if (sid_compare(&pc->sid, psid) == 0) {
                        fstring sid;
                        *pgid = pc->gid;
-                       DEBUG(3,("fetch uid from cache %u -> %s\n",
-                               (unsigned int)*pgid, sid_to_string(sid, psid)));
+                       DEBUG(3,("fetch gid from cache %u -> %s\n",
+                                (unsigned int)*pgid, sid_to_string(sid, psid)));
                        DLIST_PROMOTE(gid_sid_cache_head, pc);
                        return True;
                }
index d0de24b7d8dac8e67a4bf3012b4bfa64e098517b..8e1e8ae40b2658061e64d67bb9badb63c4a38e42 100644 (file)
@@ -906,7 +906,7 @@ static int printing_value_info( char *key, REGVAL_CTR *val )
 
 static BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
 {
-       return False;
+       return True;
 }
 
 /**********************************************************************
@@ -917,7 +917,7 @@ static BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
 
 static BOOL printing_store_value( char *key, REGVAL_CTR *val )
 {
-       return False;
+       return True;
 }
 
 /* 
index 40a32c7ee0c76ca5dd2c59515e11d6ea35e52003..41063a5d7fb60f3ce623bf6b7cf63fe13b1e2690 100644 (file)
@@ -26,8 +26,9 @@
  Get information about the server and directory services
 ********************************************************************/
 
-NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                 uint16 level, DS_DOMINFO_CTR *ctr)
+NTSTATUS rpccli_ds_getprimarydominfo(struct rpc_pipe_client *cli,
+                                    TALLOC_CTX *mem_ctx, 
+                                    uint16 level, DS_DOMINFO_CTR *ctr)
 {
        prs_struct qbuf, rbuf;
        DS_Q_GETPRIMDOMINFO q;
@@ -50,7 +51,7 @@ NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        q.level = level;
        
        if (!ds_io_q_getprimdominfo("", &qbuf, 0, &q) 
-           || !rpc_api_pipe_req(cli, PI_LSARPC_DS, DS_GETPRIMDOMINFO, &qbuf, &rbuf)) {
+           || !rpc_api_pipe_req_int(cli, DS_GETPRIMDOMINFO, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -81,13 +82,23 @@ done:
        return result;
 }
 
+NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                 uint16 level, DS_DOMINFO_CTR *ctr)
+{
+       return rpccli_ds_getprimarydominfo(&cli->pipes[PI_LSARPC_DS], mem_ctx,
+                                          level, ctr);
+}
+
+
 /********************************************************************
  Enumerate trusted domains in an AD forest
 ********************************************************************/
 
-NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                 const char *server, uint32 flags, 
-                                 struct ds_domain_trust **trusts, uint32 *num_domains)
+NTSTATUS rpccli_ds_enum_domain_trusts(struct rpc_pipe_client *cli,
+                                     TALLOC_CTX *mem_ctx, 
+                                     const char *server, uint32 flags, 
+                                     struct ds_domain_trust **trusts,
+                                     uint32 *num_domains)
 {
        prs_struct qbuf, rbuf;
        DS_Q_ENUM_DOM_TRUSTS q;
@@ -110,7 +121,7 @@ NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_q_ds_enum_domain_trusts( &q, server, flags );
                
        if (!ds_io_q_enum_domain_trusts("", &qbuf, 0, &q) 
-           || !rpc_api_pipe_req(cli, PI_NETLOGON, DS_ENUM_DOM_TRUSTS, &qbuf, &rbuf)) {
+           || !rpc_api_pipe_req_int(cli, DS_ENUM_DOM_TRUSTS, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -163,3 +174,13 @@ done:
 
        return result;
 }
+
+NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                  const char *server, uint32 flags, 
+                                  struct ds_domain_trust **trusts,
+                                  uint32 *num_domains)
+{
+       return rpccli_ds_enum_domain_trusts(&cli->pipes[PI_NETLOGON], mem_ctx,
+                                           server, flags, trusts,
+                                           num_domains);
+}
index 47dd0b1ea310ff4dc68322d5b370ab61f6e42ef2..26f82cdfbe3e1ec885625373ae8e08aa37144160 100644 (file)
  *
  * @param cli Handle on an initialised SMB connection */
 
-NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                             BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
+                               TALLOC_CTX *mem_ctx,
+                               BOOL sec_qos, uint32 des_access,
+                               POLICY_HND *pol)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_OPEN_POL q;
@@ -52,6 +54,8 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        LSA_SEC_QOS qos;
        NTSTATUS result;
 
+       SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
+
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
@@ -72,7 +76,7 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        /* Marshall data and send request */
 
        if (!lsa_io_q_open_pol("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_OPENPOLICY, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_OPENPOLICY, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -100,13 +104,21 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                             BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+       return rpccli_lsa_open_policy(&cli->pipes[PI_LSARPC], mem_ctx,
+                                     sec_qos, des_access, pol);
+}
+
 /** Open a LSA policy handle
   *
   * @param cli Handle on an initialised SMB connection 
   */
 
-NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                              BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
+                                TALLOC_CTX *mem_ctx, BOOL sec_qos,
+                                uint32 des_access, POLICY_HND *pol)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_OPEN_POL2 q;
@@ -126,17 +138,17 @@ NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        if (sec_qos) {
                init_lsa_sec_qos(&qos, 2, 1, 0);
-               init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access, 
+               init_q_open_pol2(&q, cli->cli->srv_name_slash, 0, des_access, 
                                  &qos);
        } else {
-               init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access, 
+               init_q_open_pol2(&q, cli->cli->srv_name_slash, 0, des_access, 
                                  NULL);
        }
 
        /* Marshall data and send request */
 
        if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -164,16 +176,26 @@ NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                              BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+       return rpccli_lsa_open_policy2(&cli->pipes[PI_LSARPC], mem_ctx,
+                                      sec_qos, des_access, pol);
+}
+
+
 /** Close a LSA policy handle */
 
-NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                       POLICY_HND *pol)
+NTSTATUS rpccli_lsa_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, 
+                         POLICY_HND *pol)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_CLOSE q;
        LSA_R_CLOSE r;
        NTSTATUS result;
 
+       SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
+
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
@@ -187,7 +209,7 @@ NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_lsa_q_close(&q, pol);
 
        if (!lsa_io_q_close("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_CLOSE, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_CLOSE, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -215,11 +237,19 @@ NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                       POLICY_HND *pol)
+{
+       return rpccli_lsa_close(&cli->pipes[PI_LSARPC], mem_ctx, pol);
+}
+
 /** Lookup a list of sids */
 
-NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                             POLICY_HND *pol, int num_sids, const DOM_SID *sids, 
-                             char ***domains, char ***names, uint32 **types)
+NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
+                               TALLOC_CTX *mem_ctx,
+                               POLICY_HND *pol, int num_sids,
+                               const DOM_SID *sids, 
+                               char ***domains, char ***names, uint32 **types)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_LOOKUP_SIDS q;
@@ -242,7 +272,7 @@ NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
 
        if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -332,12 +362,23 @@ NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                             POLICY_HND *pol, int num_sids,
+                            const DOM_SID *sids, 
+                             char ***domains, char ***names, uint32 **types)
+{
+       return rpccli_lsa_lookup_sids(&cli->pipes[PI_LSARPC], mem_ctx,
+                                     pol, num_sids, sids,
+                                     domains, names, types);
+}
+
 /** Lookup a list of names */
 
-NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                              POLICY_HND *pol, int num_names, 
-                             const char **names, DOM_SID **sids, 
-                             uint32 **types)
+NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
+                                TALLOC_CTX *mem_ctx,
+                                POLICY_HND *pol, int num_names, 
+                                const char **names, DOM_SID **sids, 
+                                uint32 **types)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_LOOKUP_NAMES q;
@@ -359,7 +400,7 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
 
        if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -433,19 +474,31 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                              POLICY_HND *pol, int num_names, 
+                             const char **names, DOM_SID **sids, 
+                             uint32 **types)
+{
+       return rpccli_lsa_lookup_names(&cli->pipes[PI_LSARPC], mem_ctx,
+                                      pol, num_names, names, sids, types);
+}
+
 /** Query info policy
  *
  *  @param domain_sid - returned remote server's domain sid */
 
-NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                   POLICY_HND *pol, uint16 info_class, 
-                                   char **domain_name, DOM_SID **domain_sid)
+NTSTATUS rpccli_lsa_query_info_policy(struct rpc_pipe_client *cli,
+                                     TALLOC_CTX *mem_ctx,
+                                     POLICY_HND *pol, uint16 info_class, 
+                                     char **domain_name, DOM_SID **domain_sid)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_QUERY_INFO q;
        LSA_R_QUERY_INFO r;
        NTSTATUS result;
 
+       SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
+
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
@@ -459,7 +512,7 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_q_query(&q, pol, info_class);
 
        if (!lsa_io_q_query("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -523,6 +576,15 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                   POLICY_HND *pol, uint16 info_class, 
+                                   char **domain_name, DOM_SID **domain_sid)
+{
+       return rpccli_lsa_query_info_policy(&cli->pipes[PI_LSARPC], mem_ctx,
+                                           pol, info_class, domain_name,
+                                           domain_sid);
+}
+
 /** Query info policy2
  *
  *  @param domain_name - returned remote server's domain name
@@ -531,11 +593,13 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
  *  @param domain_guid - returned remote server's domain guid
  *  @param domain_sid - returned remote server's domain sid */
 
-NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                   POLICY_HND *pol, uint16 info_class, 
-                                   char **domain_name, char **dns_name,
-                                   char **forest_name, struct uuid **domain_guid,
-                                   DOM_SID **domain_sid)
+NTSTATUS rpccli_lsa_query_info_policy2(struct rpc_pipe_client *cli,
+                                      TALLOC_CTX *mem_ctx,
+                                      POLICY_HND *pol, uint16 info_class, 
+                                      char **domain_name, char **dns_name,
+                                      char **forest_name,
+                                      struct uuid **domain_guid,
+                                      DOM_SID **domain_sid)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_QUERY_INFO2 q;
@@ -558,7 +622,7 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_q_query2(&q, pol, info_class);
 
        if (!lsa_io_q_query_info2("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_LSARPC, LSA_QUERYINFO2, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, LSA_QUERYINFO2, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -616,6 +680,19 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                   POLICY_HND *pol, uint16 info_class, 
+                                   char **domain_name, char **dns_name,
+                                   char **forest_name,
+                                   struct uuid **domain_guid,
+                                   DOM_SID **domain_sid)
+{
+       return rpccli_lsa_query_info_policy2(&cli->pipes[PI_LSARPC], mem_ctx,
+                                            pol, info_class, domain_name,
+                                            dns_name, forest_name,
+                                            domain_guid, domain_sid);
+}
+
 /**
  * Enumerate list of trusted domains
  *
@@ -631,10 +708,11 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
  * @return nt status code of response
  **/
 
-NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                POLICY_HND *pol, uint32 *enum_ctx, 
-                                uint32 *num_domains,
-                                char ***domain_names, DOM_SID **domain_sids)
+NTSTATUS rpccli_lsa_enum_trust_dom(struct rpc_pipe_client *cli,
+                                  TALLOC_CTX *mem_ctx,
+                                  POLICY_HND *pol, uint32 *enum_ctx, 
+                                  uint32 *num_domains,
+                                  char ***domain_names, DOM_SID **domain_sids)
 {
        prs_struct qbuf, rbuf;
        LSA_Q_ENUM_TRUST_DOM in;
@@ -650,7 +728,7 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        
         init_q_enum_trust_dom(&in, pol, *enum_ctx, 0x10000);
 
-       CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUMTRUSTDOM, 
+       CLI_DO_RPC_EX( cli, mem_ctx, PI_LSARPC, LSA_ENUMTRUSTDOM, 
                    in, out, 
                    qbuf, rbuf,
                    lsa_io_q_enum_trust_dom,
@@ -701,6 +779,15 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return out.status;
 }
 
+NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                POLICY_HND *pol, uint32 *enum_ctx, 
+                                uint32 *num_domains,
+                                char ***domain_names, DOM_SID **domain_sids)
+{
+       return rpccli_lsa_enum_trust_dom(&cli->pipes[PI_LSARPC], mem_ctx,
+                                        pol, enum_ctx, num_domains,
+                                        domain_names, domain_sids);
+}
 
 /** Enumerate privileges*/
 
index 08b52fa71828590bba2290c5842073b04ee41821..1474c94513faa13518ff7d9f4c79abdbcfb143cf 100644 (file)
@@ -75,6 +75,55 @@ NTSTATUS cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
         return result;
 }
 
+NTSTATUS rpccli_net_req_chal(struct rpc_pipe_client *cli,
+                            const char *server_name,
+                            const char *computer_name,
+                            DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
+{
+        prs_struct qbuf, rbuf;
+        NET_Q_REQ_CHAL q;
+        NET_R_REQ_CHAL r;
+        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+        prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->cli->mem_ctx, MARSHALL);
+        prs_init(&rbuf, 0, cli->cli->mem_ctx, UNMARSHALL);
+        
+        /* create and send a MSRPC command with api NET_REQCHAL */
+
+        DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s\n",
+                 computer_name, server_name));
+        
+        /* store the parameters */
+        init_q_req_chal(&q, server_name, computer_name, clnt_chal);
+        
+        /* Marshall data and send request */
+
+        if (!net_io_q_req_chal("", &q,  &qbuf, 0) ||
+            !rpc_api_pipe_req_int(cli, NET_REQCHAL, &qbuf, &rbuf)) {
+                goto done;
+        }
+
+        /* Unmarhall response */
+
+        if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
+                goto done;
+        }
+
+        result = r.status;
+
+        /* Return result */
+
+        if (NT_STATUS_IS_OK(result)) {
+                memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
+        }
+        
+ done:
+        prs_mem_free(&qbuf);
+        prs_mem_free(&rbuf);
+        
+        return result;
+}
+
 /****************************************************************************
 LSA Authenticate 2
 
@@ -158,6 +207,61 @@ password ?).\n", cli->desthost ));
         return result;
 }
 
+NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
+                         const char *server_name,
+                         const char *account_name,
+                         uint16 sec_chan_type,
+                         const char *computer_name,
+                         const DOM_CHAL *credentials,
+                         uint32 *neg_flags,
+                         DOM_CHAL *srv_chal)
+{
+        prs_struct qbuf, rbuf;
+        NET_Q_AUTH_2 q;
+        NET_R_AUTH_2 r;
+        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+        prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+        prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+        /* create and send a MSRPC command with api NET_AUTH2 */
+
+        DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s neg: %x\n",
+                 server_name, account_name, sec_chan_type, computer_name,
+                 *neg_flags));
+
+        /* store the parameters */
+
+        init_q_auth_2(&q, server_name, account_name, sec_chan_type,
+                     computer_name, credentials, *neg_flags);
+
+        /* turn parameters into data stream */
+
+        if (!net_io_q_auth_2("", &q,  &qbuf, 0) ||
+            !rpc_api_pipe_req_int(cli, NET_AUTH2, &qbuf, &rbuf)) {
+                goto done;
+        }
+        
+        /* Unmarshall response */
+        
+        if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
+                goto done;
+        }
+
+        result = r.status;
+
+        if (NT_STATUS_IS_OK(result)) {
+               *srv_chal = r.srv_chal;
+               *neg_flags = r.srv_flgs.neg_flags;
+        }
+
+ done:
+        prs_mem_free(&qbuf);
+        prs_mem_free(&rbuf);
+        
+        return result;
+}
+
 /****************************************************************************
 LSA Authenticate 3
 
@@ -340,8 +444,9 @@ NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* GetDCName */
 
-NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                               const char *domainname, fstring dcname)
+NTSTATUS rpccli_netlogon_getdcname(struct rpc_pipe_client *cli,
+                                  TALLOC_CTX *mem_ctx, const char *mydcname,
+                                  const char *domainname, fstring newdcname)
 {
        prs_struct qbuf, rbuf;
        NET_Q_GETDCNAME q;
@@ -358,12 +463,12 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        /* Initialise input parameters */
 
-       init_net_q_getdcname(&q, cli->srv_name_slash, domainname);
+       init_net_q_getdcname(&q, mydcname, domainname);
 
        /* Marshall data and send request */
 
        if (!net_io_q_getdcname("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_NETLOGON, NET_GETDCNAME, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, NET_GETDCNAME, &qbuf, &rbuf)) {
                result = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -378,7 +483,7 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        result = r.status;
 
        if (NT_STATUS_IS_OK(result))
-               rpcstr_pull_unistr2_fstring(dcname, &r.uni_dcname);
+               rpcstr_pull_unistr2_fstring(newdcname, &r.uni_dcname);
 
  done:
        prs_mem_free(&qbuf);
@@ -387,6 +492,14 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                               const char *domainname, fstring dcname)
+{
+       return rpccli_netlogon_getdcname(&cli->pipes[PI_NETLOGON], mem_ctx,
+                                        cli->srv_name_slash, domainname,
+                                        dcname);
+}
+
 /****************************************************************************
 Generate the next creds to use.
 ****************************************************************************/
@@ -636,19 +749,25 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
  **/
 
-NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                       DOM_CRED *ret_creds,
-                                       const char *username, const char *domain, const char *workstation, 
-                                       const uint8 chal[8], 
-                                       DATA_BLOB lm_response, DATA_BLOB nt_response,
-                                       NET_USER_INFO_3 *info3)
-
+NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
+                                          TALLOC_CTX *mem_ctx,
+                                          const char *server_name_slash,
+                                          DOM_CRED *clnt_creds,
+                                          DOM_CRED *ret_creds,
+                                          const char *username,
+                                          const char *domain,
+                                          const char *workstation, 
+                                          const uint8 chal[8], 
+                                          DATA_BLOB lm_response,
+                                          DATA_BLOB nt_response,
+                                          NET_USER_INFO_3 *info3,
+                                          const uint8 *session_key)
 {
        prs_struct qbuf, rbuf;
        NET_Q_SAM_LOGON q;
        NET_R_SAM_LOGON r;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-        DOM_CRED clnt_creds, dummy_rtn_creds;
+        DOM_CRED dummy_rtn_creds;
        NET_ID_INFO_CTR ctr;
        int validation_level = 3;
        char *workstation_name_slash;
@@ -661,7 +780,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
        ZERO_STRUCT(dummy_rtn_creds);
 
        workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
-       
        if (!workstation_name_slash) {
                DEBUG(0, ("talloc_asprintf failed!\n"));
                return NT_STATUS_NO_MEMORY;
@@ -674,8 +792,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
 
        /* Initialise input parameters */
 
-       gen_next_creds(cli, &clnt_creds);
-
        q.validation_level = validation_level;
 
        if (ret_creds == NULL)
@@ -689,14 +805,14 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
                      username, workstation_name_slash, (const uchar*)chal,
                      lm_response.data, lm_response.length, nt_response.data, nt_response.length);
  
-        init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(),
-                      &clnt_creds, ret_creds, NET_LOGON_TYPE,
+        init_sam_info(&q.sam_id, server_name_slash, global_myname(),
+                      clnt_creds, ret_creds, NET_LOGON_TYPE,
                       &ctr);
 
         /* Marshall data and send request */
 
        if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_NETLOGON, NET_SAMLOGON, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -709,7 +825,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
        }
 
        ZERO_STRUCT(netlogon_sess_key);
-       memcpy(netlogon_sess_key, cli->sess_key, 8);
+       memcpy(netlogon_sess_key, session_key, 8);
        
        if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
                SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16);
@@ -740,6 +856,30 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
         return result;
 }
 
+NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli,
+                                       TALLOC_CTX *mem_ctx,
+                                       DOM_CRED *ret_creds,
+                                       const char *username,
+                                       const char *domain,
+                                       const char *workstation, 
+                                       const uint8 chal[8], 
+                                       DATA_BLOB lm_response,
+                                       DATA_BLOB nt_response,
+                                       NET_USER_INFO_3 *info3)
+{
+       DOM_CRED clnt_creds;
+
+       gen_next_creds(cli, &clnt_creds);
+
+       return rpccli_netlogon_sam_network_logon(&cli->pipes[PI_NETLOGON],
+                                                mem_ctx, cli->srv_name_slash,
+                                                &clnt_creds,
+                                                ret_creds, username,
+                                                domain, workstation, chal, 
+                                                lm_response, nt_response,
+                                                info3, cli->sess_key);
+}
+
 /***************************************************************************
 LSA Server Password Set.
 ****************************************************************************/
index 8f6576a165cb44aed84e32843ff552b133843356..5f34fbde5d26219f1f4fdf0bdc50920638d86721 100644 (file)
@@ -62,7 +62,8 @@ static uint32 get_rpc_call_id(void)
  Use SMBreadX to get rest of one fragment's worth of rpc data.
  ********************************************************************/
 
-static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
+static BOOL rpc_read(struct rpc_pipe_client *cli, prs_struct *rdata,
+                    uint32 data_to_read, uint32 *rdata_offset)
 {
        size_t size = (size_t)cli->max_recv_frag;
        int stream_offset = 0;
@@ -95,13 +96,14 @@ static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uin
                if (size > (size_t)data_to_read)
                        size = (size_t)data_to_read;
 
-               num_read = (int)cli_read(cli, cli->nt_pipe_fnum[pipe_idx], pdata, (off_t)stream_offset, size);
+               num_read = (int)cli_read(cli->cli, cli->fnum, pdata,
+                                        (off_t)stream_offset, size);
 
                DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
                          num_read, stream_offset, data_to_read));
 
-               if (cli_is_dos_error(cli)) {
-                        cli_dos_error(cli, &eclass, &ecode);
+               if (cli_is_dos_error(cli->cli)) {
+                        cli_dos_error(cli->cli, &eclass, &ecode);
                         if (eclass != ERRDOS && ecode != ERRmoredata) {
                                 DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
                                          eclass, (unsigned int)ecode));
@@ -168,7 +170,7 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
  Never on bind requests/responses.
  ****************************************************************************/
 
-static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
+static BOOL rpc_auth_pipe(struct rpc_pipe_client *cli, prs_struct *rdata,
                          uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
                          int *pauth_padding_len)
 {
@@ -219,7 +221,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
        DEBUG(10,("rpc_auth_pipe: packet:\n"));
        dump_data(100, dp, auth_len);
 
-       prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+       prs_init(&auth_verf, 0, cli->cli->mem_ctx, UNMARSHALL);
        
        /* The endinness must be preserved. JRA. */
        prs_set_endian_data( &auth_verf, rdata->bigendian_data);
@@ -394,7 +396,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
 
  ****************************************************************************/
 
-static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data, prs_struct *rdata,
+static BOOL rpc_api_pipe(struct rpc_pipe_client *cli, prs_struct *data, prs_struct *rdata,
                         uint8 expected_pkt_type)
 {
        uint32 len;
@@ -416,23 +418,24 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
        /* Create setup parameters - must be in native byte order. */
 
        setup[0] = TRANSACT_DCERPCCMD; 
-       setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* Pipe file handle. */
+       setup[1] = cli->fnum; /* Pipe file handle. */
 
-       DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum[pipe_idx]));
+       DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->fnum));
 
        /* Send the RPC request and receive a response.  For short RPC
           calls (about 1024 bytes or so) the RPC request and response
           appears in a SMBtrans request and response.  Larger RPC
           responses are received further on. */
 
-       if (!cli_api_pipe(cli, "\\PIPE\\",
+       if (!cli_api_pipe(cli->cli, "\\PIPE\\",
                  setup, 2, 0,                     /* Setup, length, max */
                  NULL, 0, 0,                      /* Params, length, max */
                  pdata, data_len, max_data,       /* data, length, max */
                  &rparam, &rparam_len,            /* return params, len */
                  &prdata, &rdata_len))            /* return data, len */
        {
-               DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
+               DEBUG(0, ("cli_pipe: return critical error. Error was %s\n",
+                         cli_errstr(cli->cli)));
                return False;
        }
 
@@ -442,7 +445,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
 
        if (prdata == NULL) {
                DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
-                       (int)cli->nt_pipe_fnum[pipe_idx]));
+                       (int)cli->fnum));
                return False;
        }
 
@@ -470,7 +473,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
        }
 
        if (rhdr.pkt_type == RPC_BINDNACK) {
-               DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum[pipe_idx]));
+               DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->fnum));
                prs_mem_free(rdata);
                return False;
        }
@@ -485,7 +488,9 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
        }
 
        if (rhdr.pkt_type != expected_pkt_type) {
-               DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum[pipe_idx], rhdr.pkt_type, expected_pkt_type));
+               DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet "
+                         "type - %d, not %d\n", (int)cli->fnum,
+                         rhdr.pkt_type, expected_pkt_type));
                prs_mem_free(rdata);
                return False;
        }
@@ -502,7 +507,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
 
                /* Read the remaining part of the first response fragment */
 
-               if (!rpc_read(cli, pipe_idx, rdata, len, &current_offset)) {
+               if (!rpc_read(cli, rdata, len, &current_offset)) {
                        prs_mem_free(rdata);
                        return False;
                }
@@ -554,12 +559,13 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
                 * First read the header of the next PDU.
                 */
 
-               prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
+               prs_init(&hps, 0, cli->cli->mem_ctx, UNMARSHALL);
                prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
 
-               num_read = cli_read(cli, cli->nt_pipe_fnum[pipe_idx], hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
-               if (cli_is_dos_error(cli)) {
-                        cli_dos_error(cli, &eclass, &ecode);
+               num_read = cli_read(cli->cli, cli->fnum, hdr_data, 0,
+                                   RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
+               if (cli_is_dos_error(cli->cli)) {
+                        cli_dos_error(cli->cli, &eclass, &ecode);
                         if (eclass != ERRDOS && ecode != ERRmoredata) {
                                 DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
                                 return False;
@@ -602,7 +608,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
                 * Now read the rest of the PDU.
                 */
 
-               if (!rpc_read(cli, pipe_idx, rdata, len, &current_offset)) {
+               if (!rpc_read(cli, rdata, len, &current_offset)) {
                        prs_mem_free(rdata);
                        return False;
                }
@@ -644,7 +650,8 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
 
  ********************************************************************/
 
-static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out, 
+static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
+                                   prs_struct *rpc_out, 
                                    uint32 rpc_call_id,
                                    RPC_IFACE *abstract, RPC_IFACE *transfer,
                                    const char *my_name, const char *domain)
@@ -783,7 +790,7 @@ static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
  the authentication handshake.
  ********************************************************************/
 
-static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
+static NTSTATUS create_rpc_bind_resp(struct rpc_pipe_client *cli,
                                 uint32 rpc_call_id,
                                 prs_struct *rpc_out)
 {
@@ -916,8 +923,8 @@ static BOOL create_auth_hdr(prs_struct *outgoing_packet,
  * @param rdata Unparsed NDR response data.
 **/
 
-BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
-                      prs_struct *data, prs_struct *rdata)
+BOOL rpc_api_pipe_req_int(struct rpc_pipe_client *cli, uint8 op_num,
+                         prs_struct *data, prs_struct *rdata)
 {
        uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
        NTSTATUS nt_status;
@@ -959,7 +966,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
                send_size = MIN(data_left, max_data);
 
                if (!prs_init(&sec_blob, send_size, /* will need at least this much */
-                             cli->mem_ctx, MARSHALL)) {
+                             cli->cli->mem_ctx, MARSHALL)) {
                        DEBUG(0,("Could not malloc %u bytes",
                                 send_size+auth_padding));
                        return False;
@@ -1066,7 +1073,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
                 * Malloc parse struct to hold it (and enough for alignments).
                 */
                if(!prs_init(&outgoing_packet, data_len + 8, 
-                            cli->mem_ctx, MARSHALL)) {
+                            cli->cli->mem_ctx, MARSHALL)) {
                        DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
                        return False;
                }
@@ -1095,10 +1102,10 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
                           prs_offset(&outgoing_packet)));
                
                if (flags & RPC_FLG_LAST)
-                       ret = rpc_api_pipe(cli, pipe_idx, &outgoing_packet, 
+                       ret = rpc_api_pipe(cli, &outgoing_packet, 
                                           rdata, RPC_RESPONSE);
                else {
-                       cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x0008,
+                       cli_write(cli->cli, cli->fnum, 0x0008,
                                   prs_data_p(&outgoing_packet),
                                   data_sent, data_len);
                }
@@ -1108,17 +1115,26 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
        }
        /* Also capture received data */
        slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s",
-                cli_pipe_get_name(cli));
+                cli_pipe_get_name(cli->cli));
        prs_dump(dump_name, op_num, rdata);
 
        return ret;
 }
 
+BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
+                      prs_struct *data, prs_struct *rdata)
+{
+       return rpc_api_pipe_req_int(&cli->pipes[pipe_idx], op_num,
+                                   data, rdata);
+}
+
+
 /****************************************************************************
  Set the handle state.
 ****************************************************************************/
 
-static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const char *pipe_name, uint16 device_state)
+static BOOL rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
+                                  const char *pipe_name, uint16 device_state)
 {
        BOOL state_set = False;
        char param[2];
@@ -1131,17 +1147,17 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const ch
                return False;
 
        DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
-       cli->nt_pipe_fnum[pipe_idx], pipe_name, device_state));
+                cli->fnum, pipe_name, device_state));
 
        /* create parameters: device state */
        SSVAL(param, 0, device_state);
 
        /* create setup parameters. */
        setup[0] = 0x0001; 
-       setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* pipe file handle.  got this from an SMBOpenX. */
+       setup[1] = cli->fnum; /* pipe file handle.  got this from an SMBOpenX. */
 
        /* send the data on \PIPE\ */
-       if (cli_api_pipe(cli, "\\PIPE\\",
+       if (cli_api_pipe(cli->cli, "\\PIPE\\",
                    setup, 2, 0,                /* setup, length, max */
                    param, 2, 0,                /* param, length, max */
                    NULL, 0, 1024,              /* data, length, max */
@@ -1281,20 +1297,21 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFAC
  Create and send the third packet in an RPC auth.
 ****************************************************************************/
 
-static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 rpc_call_id)
+static BOOL rpc_send_auth_reply(struct rpc_pipe_client *cli,
+                               prs_struct *rdata, uint32 rpc_call_id)
 {
        prs_struct rpc_out;
        ssize_t ret;
 
        prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */ 
-                cli->mem_ctx, MARSHALL);
+                cli->cli->mem_ctx, MARSHALL);
 
        if (!NT_STATUS_IS_OK(create_rpc_bind_resp(cli, rpc_call_id,
                                                  &rpc_out))) {
                return False;
        }
 
-       if ((ret = cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x8, prs_data_p(&rpc_out), 
+       if ((ret = cli_write(cli->cli, cli->fnum, 0x8, prs_data_p(&rpc_out), 
                        0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
                DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
                prs_mem_free(&rpc_out);
@@ -1309,7 +1326,7 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct
  Do an rpc bind.
 ****************************************************************************/
 
-static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name)
+static BOOL rpc_pipe_bind(struct rpc_pipe_client *cli)
 {
        RPC_IFACE abstract;
        RPC_IFACE transfer;
@@ -1318,15 +1335,16 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
        uint32 rpc_call_id;
        char buffer[MAX_PDU_FRAG_LEN];
 
-       if ( (pipe_idx < 0) || (pipe_idx >= PI_MAX_PIPES) )
+       if ( (cli->pipe_idx < 0) || (cli->pipe_idx >= PI_MAX_PIPES) )
                return False;
 
-       DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum[pipe_idx], pipe_names[pipe_idx].client_pipe));
+       DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->fnum,
+                pipe_names[cli->pipe_idx].client_pipe));
 
-       if (!valid_pipe_name(pipe_idx, &abstract, &transfer))
+       if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer))
                return False;
 
-       prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
+       prs_init(&rpc_out, 0, cli->cli->mem_ctx, MARSHALL);
 
        /*
         * Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
@@ -1391,10 +1409,10 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
                            global_myname(), cli->domain);
 
        /* Initialize the incoming data struct. */
-       prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+       prs_init(&rdata, 0, cli->cli->mem_ctx, UNMARSHALL);
 
        /* send data on \PIPE\.  receive a response */
-       if (rpc_api_pipe(cli, pipe_idx, &rpc_out, &rdata, RPC_BINDACK)) {
+       if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) {
                RPC_HDR_BA   hdr_ba;
 
                DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
@@ -1405,7 +1423,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
                        return False;
                }
 
-               if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) {
+               if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) {
                        DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
                        prs_mem_free(&rdata);
                        return False;
@@ -1421,7 +1439,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
                 */
 
                if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) 
-                   && !rpc_send_auth_reply(cli, pipe_idx, &rdata, rpc_call_id)) {
+                   && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
                        DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
                        prs_mem_free(&rdata);
                        return False;
@@ -1440,11 +1458,9 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
 BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
 {
        int fnum;
+       struct rpc_pipe_client *cli_pipe;
 
-       /* At the moment we can't have more than one pipe open over
-           a cli connection. )-: */
-
-       SMB_ASSERT(cli->nt_pipe_fnum[pipe_idx] == 0);
+       SMB_ASSERT(cli->pipes[pipe_idx].fnum == 0);
        
        /* The pipe index must fall within our array */
 
@@ -1457,7 +1473,7 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
                        return False;
                }
 
-               cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
+               cli->pipes[pipe_idx].fnum = (uint16)fnum;
        } else {
                if ((fnum = cli_open(cli, pipe_names[pipe_idx].client_pipe, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
                        DEBUG(1,("cli_nt_session_open: cli_open failed on pipe %s to machine %s.  Error was %s\n",
@@ -1465,25 +1481,32 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
                        return False;
                }
 
-               cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
+               cli->pipes[pipe_idx].fnum = (uint16)fnum;
 
                /**************** Set Named Pipe State ***************/
-               if (!rpc_pipe_set_hnd_state(cli, pipe_idx, pipe_names[pipe_idx].client_pipe, 0x4300)) {
+               if (!rpc_pipe_set_hnd_state(&cli->pipes[pipe_idx], pipe_names[pipe_idx].client_pipe, 0x4300)) {
                        DEBUG(0,("cli_nt_session_open: pipe hnd state failed.  Error was %s\n",
                                  cli_errstr(cli)));
-                       cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
-                       cli->nt_pipe_fnum[pipe_idx] = 0;
+                       cli_close(cli, cli->pipes[pipe_idx].fnum);
+                       cli->pipes[pipe_idx].fnum = 0;
                        return False;
                }
        }
 
+       cli_pipe = &cli->pipes[pipe_idx];
+       cli_pipe->pipe_idx = pipe_idx;
+       cli_pipe->cli = cli;
+       cli_pipe->pipe_auth_flags = cli->pipe_auth_flags;
+       memcpy(&cli_pipe->auth_info.sess_key,
+              cli->sess_key, sizeof(cli->sess_key));
+
        /******************* bind request on pipe *****************/
 
-       if (!rpc_pipe_bind(cli, pipe_idx, global_myname())) {
+       if (!rpc_pipe_bind(&cli->pipes[pipe_idx])) {
                DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
                         get_pipe_name_from_index(pipe_idx)));
-               cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
-               cli->nt_pipe_fnum[pipe_idx] = 0;
+               cli_close(cli, cli->pipes[pipe_idx].fnum);
+               cli->pipes[pipe_idx].fnum = 0;
                return False;
        }
 
@@ -1523,7 +1546,6 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
 {
        NTSTATUS result;        
        uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
-       int fnum;
 
        cli_nt_netlogon_netsec_session_close(cli);
 
@@ -1554,60 +1576,20 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
 
        }
 
-       /* Server offered schannel, so try it. */
+       cli->netlogon_pipe = cli->pipes[PI_NETLOGON];
+       ZERO_STRUCT(cli->pipes[PI_NETLOGON]);
 
-       memcpy(cli->auth_info.sess_key, cli->sess_key,
-              sizeof(cli->auth_info.sess_key));
+       /* Server offered schannel, so try it. */
 
-       cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum[PI_NETLOGON];
+       memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->sess_key,
+              sizeof(cli->pipes[PI_NETLOGON].auth_info.sess_key));
 
        cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
        cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
        cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
 
-       if (cli->capabilities & CAP_NT_SMBS) {
-
-               /* The secure channel connection must be opened on the same 
-                   session (TCP connection) as the one the challenge was
-                   requested from. */
-               if ((fnum = cli_nt_create(cli, PIPE_NETLOGON_PLAIN,
-                                         DESIRED_ACCESS_PIPE)) == -1) {
-                       DEBUG(0,("cli_nt_create failed to %s machine %s. "
-                                "Error was %s\n",
-                                PIPE_NETLOGON, cli->desthost,
-                                cli_errstr(cli)));
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-               
-               cli->nt_pipe_fnum[PI_NETLOGON] = (uint16)fnum;
-       } else {
-               if ((fnum = cli_open(cli, PIPE_NETLOGON,
-                                    O_CREAT|O_RDWR, DENY_NONE)) == -1) {
-                       DEBUG(0,("cli_open failed on pipe %s to machine %s. "
-                                "Error was %s\n",
-                                PIPE_NETLOGON, cli->desthost,
-                                cli_errstr(cli)));
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-
-               cli->nt_pipe_fnum[PI_NETLOGON] = (uint16)fnum;
-
-               /**************** Set Named Pipe State ***************/
-               if (!rpc_pipe_set_hnd_state(cli, PI_NETLOGON, PIPE_NETLOGON, 0x4300)) {
-                       DEBUG(0,("Pipe hnd state failed.  Error was %s\n",
-                                 cli_errstr(cli)));
-                       cli_close(cli, cli->nt_pipe_fnum[PI_NETLOGON]);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       }
-       
-       if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname())) {
-               DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
-               cli_close(cli, cli->nt_pipe_fnum[PI_NETLOGON]);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       return NT_STATUS_OK;
+       return cli_nt_session_open(cli, PI_NETLOGON) ?
+               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
 }
 
 
@@ -1640,19 +1622,20 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
        }
 
        if (!NT_STATUS_IS_OK(result)) {
-               ZERO_STRUCT(cli->auth_info.sess_key);
+               ZERO_STRUCT(cli->pipes[cli->pipe_idx].auth_info.sess_key);
                ZERO_STRUCT(cli->sess_key);
                cli->pipe_auth_flags = 0;
                cli_nt_session_close(cli);
                return result;
        }
 
-       memcpy(cli->auth_info.sess_key, cli->sess_key,
-              sizeof(cli->auth_info.sess_key));
-
-       cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum[PI_NETLOGON];
-       cli->nt_pipe_fnum[PI_NETLOGON] = 0;
+       memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->sess_key,
+              sizeof(cli->pipes[PI_NETLOGON].auth_info.sess_key));
 
+       cli_close(cli, cli->pipes[PI_NETLOGON].fnum);
+       cli->pipes[PI_NETLOGON].fnum = 0;
+       cli->pipe_idx = -1;
+       
        /* doing schannel, not per-user auth */
        cli->pipe_auth_flags = auth_flags;
 
@@ -1664,4 +1647,124 @@ const char *cli_pipe_get_name(struct cli_state *cli)
        return cli->pipe_name;
 }
 
+static struct rpc_pipe_client *cli_rpc_open(struct cli_state *cli,
+                                           int pipe_idx)
+{
+       TALLOC_CTX *mem_ctx;
+       struct rpc_pipe_client *result;
+       int fnum;
+
+       /* The pipe index must fall within our array */
+       SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
+
+       mem_ctx = talloc_init("struct rpc_pipe_client");
+       if (mem_ctx == NULL) return NULL;
+
+       result = TALLOC_P(mem_ctx, struct rpc_pipe_client);
+       if (result == NULL) return NULL;
+
+       result->mem_ctx = mem_ctx;
+
+       fnum = cli_nt_create(cli, &pipe_names[pipe_idx].client_pipe[5],
+                            DESIRED_ACCESS_PIPE);
+
+       if (fnum == -1) {
+               DEBUG(0,("cli_rpc_open failed on pipe %s "
+                        "to machine %s.  Error was %s\n",
+                        &pipe_names[pipe_idx].client_pipe[5], cli->desthost,
+                        cli_errstr(cli)));
+               talloc_destroy(result->mem_ctx);
+               return NULL;
+       }
+
+       result->fnum = fnum;
+       result->cli = cli;
+       result->pipe_idx = pipe_idx;
+
+       return result;
+}
+
+struct rpc_pipe_client *cli_rpc_open_noauth(struct cli_state *cli,
+                                           int pipe_idx)
+{
+       struct rpc_pipe_client *result;
+
+       result = cli_rpc_open(cli, pipe_idx);
+       if (result == NULL) return NULL;
+
+       result->max_xmit_frag = 0;
+       result->pipe_auth_flags = 0;
+
+       if (!rpc_pipe_bind(result)) {
+               DEBUG(0, ("rpc_pipe_bind failed\n"));
+               talloc_destroy(result->mem_ctx);
+               return NULL;
+       }
+
+       return result;
+}
+
+struct rpc_pipe_client *cli_rpc_open_ntlmssp(struct cli_state *cli,
+                                            int pipe_idx,
+                                            const char *domain,
+                                            const char *username,
+                                            const char *password)
+{
+       struct rpc_pipe_client *result;
+
+       result = cli_rpc_open(cli, pipe_idx);
+       if (result == NULL) return NULL;
+       
+       result->max_xmit_frag = 0;
+       result->pipe_auth_flags =
+               AUTH_PIPE_NTLMSSP|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL;
+       result->domain = domain;
+       result->user_name = username;
+       pwd_set_cleartext(&result->pwd, password);
+
+       if (!rpc_pipe_bind(result)) {
+               DEBUG(0, ("cli_rpc_pipe_bind failed\n"));
+               talloc_destroy(result->mem_ctx);
+               return NULL;
+       }
+
+       return result;
+}
+
+struct rpc_pipe_client *cli_rpc_open_schannel(struct cli_state *cli,
+                                             int pipe_idx,
+                                             const uchar session_key[16],
+                                             const char *domain)
+{
+       struct rpc_pipe_client *result;
+
+       result = cli_rpc_open(cli, pipe_idx);
+       if (result == NULL) return NULL;
+       
+       result->max_xmit_frag = 0;
+       result->pipe_auth_flags =
+               AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN | AUTH_PIPE_SEAL;
+       result->domain = domain;
+       memcpy(result->auth_info.sess_key, session_key, 16);
+
+       if (!rpc_pipe_bind(result)) {
+               DEBUG(0, ("cli_rpc_pipe_bind failed\n"));
+               talloc_destroy(result->mem_ctx);
+               return NULL;
+       }
+
+       return result;
+}
+
+void cli_rpc_close(struct rpc_pipe_client *cli_pipe)
+{
+       if (!cli_close(cli_pipe->cli, cli_pipe->fnum))
+               DEBUG(0,("cli_rpc_open failed on pipe %s "
+                        "to machine %s.  Error was %s\n",
+                        &pipe_names[cli_pipe->pipe_idx].client_pipe[5],
+                        cli_pipe->cli->desthost,
+                        cli_errstr(cli_pipe->cli)));
+
+       talloc_destroy(cli_pipe->mem_ctx);      
+}
 
index 45f9bd67a5ce7b3abb6c8f0deac024cdb4fcc3b0..01ec0bd51eb932ac5dd867dfb839e0c0abb6a6f5 100644 (file)
 
 /* Connect to SAMR database */
 
-NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                          uint32 access_mask, POLICY_HND *connect_pol)
+NTSTATUS rpccli_samr_connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, 
+                            uint32 access_mask, POLICY_HND *connect_pol)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_CONNECT q;
        SAMR_R_CONNECT r;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 
-       DEBUG(10,("cli_samr_connect to %s\n", cli->desthost));
+       DEBUG(10,("cli_samr_connect to %s\n", cli->cli->desthost));
 
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
@@ -47,10 +47,10 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        /* Marshall data and send request */
 
-       init_samr_q_connect(&q, cli->desthost, access_mask);
+       init_samr_q_connect(&q, cli->cli->desthost, access_mask);
 
        if (!samr_io_q_connect("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_CONNECT, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_CONNECT, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -74,6 +74,12 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                          uint32 access_mask, POLICY_HND *connect_pol)
+{
+       return rpccli_samr_connect(&cli->pipes[PI_SAMR], mem_ctx,
+                                  access_mask, connect_pol);
+}
 /* Connect to SAMR database */
 
 NTSTATUS cli_samr_connect4(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
@@ -125,8 +131,8 @@ NTSTATUS cli_samr_connect4(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Close SAMR handle */
 
-NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                        POLICY_HND *connect_pol)
+NTSTATUS rpccli_samr_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+                          POLICY_HND *connect_pol)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_CLOSE_HND q;
@@ -148,7 +154,7 @@ NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_close_hnd(&q, connect_pol);
 
        if (!samr_io_q_close_hnd("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_CLOSE_HND, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_CLOSE_HND, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -172,11 +178,18 @@ NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                        POLICY_HND *connect_pol)
+{
+       return rpccli_samr_close(&cli->pipes[PI_SAMR], mem_ctx, connect_pol);
+}
+
 /* Open handle on a domain */
 
-NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                              POLICY_HND *connect_pol, uint32 access_mask, 
-                              const DOM_SID *domain_sid, POLICY_HND *domain_pol)
+NTSTATUS rpccli_samr_open_domain(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+                                POLICY_HND *connect_pol, uint32 access_mask, 
+                                const DOM_SID *domain_sid,
+                                POLICY_HND *domain_pol)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_OPEN_DOMAIN q;
@@ -198,7 +211,7 @@ NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_open_domain(&q, connect_pol, access_mask, domain_sid);
 
        if (!samr_io_q_open_domain("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_DOMAIN, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_OPEN_DOMAIN, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -224,9 +237,21 @@ NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Open handle on a user */
 
-NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                            POLICY_HND *domain_pol, uint32 access_mask, 
-                            uint32 user_rid, POLICY_HND *user_pol)
+NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                              POLICY_HND *connect_pol, uint32 access_mask, 
+                              const DOM_SID *domain_sid,
+                             POLICY_HND *domain_pol)
+{
+       return rpccli_samr_open_domain(&cli->pipes[PI_SAMR], mem_ctx,
+                                      connect_pol, access_mask, domain_sid,
+                                      domain_pol);
+}
+
+
+NTSTATUS rpccli_samr_open_user(struct rpc_pipe_client *cli,
+                              TALLOC_CTX *mem_ctx,
+                              POLICY_HND *domain_pol, uint32 access_mask, 
+                              uint32 user_rid, POLICY_HND *user_pol)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_OPEN_USER q;
@@ -248,7 +273,7 @@ NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_open_user(&q, domain_pol, access_mask, user_rid);
 
        if (!samr_io_q_open_user("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_USER, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_OPEN_USER, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -272,11 +297,21 @@ NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                            POLICY_HND *domain_pol, uint32 access_mask, 
+                            uint32 user_rid, POLICY_HND *user_pol)
+{
+       return rpccli_samr_open_user(&cli->pipes[PI_SAMR], mem_ctx, domain_pol,
+                                    access_mask, user_rid, user_pol);
+}
+
+
 /* Open handle on a group */
 
-NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                             POLICY_HND *domain_pol, uint32 access_mask, 
-                             uint32 group_rid, POLICY_HND *group_pol)
+NTSTATUS rpccli_samr_open_group(struct rpc_pipe_client *cli,
+                               TALLOC_CTX *mem_ctx, 
+                               POLICY_HND *domain_pol, uint32 access_mask, 
+                               uint32 group_rid, POLICY_HND *group_pol)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_OPEN_GROUP q;
@@ -298,7 +333,7 @@ NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_open_group(&q, domain_pol, access_mask, group_rid);
 
        if (!samr_io_q_open_group("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_GROUP, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_OPEN_GROUP, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -322,6 +357,15 @@ NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                             POLICY_HND *domain_pol, uint32 access_mask, 
+                             uint32 group_rid, POLICY_HND *group_pol)
+{
+       return rpccli_samr_open_group(&cli->pipes[PI_SAMR], mem_ctx,
+                                     domain_pol, access_mask, group_rid,
+                                     group_pol);
+}
+
 /* Create domain group */
 
 NTSTATUS cli_samr_create_dom_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
@@ -461,9 +505,10 @@ NTSTATUS cli_samr_del_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Query user info */
 
-NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                 POLICY_HND *user_pol, uint16 switch_value, 
-                                 SAM_USERINFO_CTR **ctr)
+NTSTATUS rpccli_samr_query_userinfo(struct rpc_pipe_client *cli,
+                                   TALLOC_CTX *mem_ctx,
+                                   POLICY_HND *user_pol, uint16 switch_value, 
+                                   SAM_USERINFO_CTR **ctr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_USERINFO q;
@@ -485,7 +530,7 @@ NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_query_userinfo(&q, user_pol, switch_value);
 
        if (!samr_io_q_query_userinfo("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERINFO, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_USERINFO, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -505,6 +550,14 @@ NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                 POLICY_HND *user_pol, uint16 switch_value, 
+                                 SAM_USERINFO_CTR **ctr)
+{
+       return rpccli_samr_query_userinfo(&cli->pipes[PI_SAMR], mem_ctx,
+                                         user_pol, switch_value, ctr);
+}
+
 /* Set group info */
 
 NTSTATUS cli_samr_set_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
@@ -598,9 +651,11 @@ NTSTATUS cli_samr_query_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Query user groups */
 
-NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                   POLICY_HND *user_pol, uint32 *num_groups, 
-                                   DOM_GID **gid)
+NTSTATUS rpccli_samr_query_usergroups(struct rpc_pipe_client *cli,
+                                     TALLOC_CTX *mem_ctx, 
+                                     POLICY_HND *user_pol,
+                                     uint32 *num_groups, 
+                                     DOM_GID **gid)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_USERGROUPS q;
@@ -622,7 +677,7 @@ NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_query_usergroups(&q, user_pol);
 
        if (!samr_io_q_query_usergroups("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -644,6 +699,14 @@ NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                   POLICY_HND *user_pol, uint32 *num_groups, 
+                                   DOM_GID **gid)
+{
+       return rpccli_samr_query_usergroups(&cli->pipes[PI_SAMR], mem_ctx,
+                                           user_pol, num_groups, gid);
+}
+
 /* Set alias info */
 
 NTSTATUS cli_samr_set_aliasinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
@@ -690,9 +753,11 @@ NTSTATUS cli_samr_set_aliasinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Query user aliases */
 
-NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                   POLICY_HND *dom_pol, uint32 num_sids, DOM_SID2 *sid,
-                                  uint32 *num_aliases, uint32 **als_rids)
+NTSTATUS rpccli_samr_query_useraliases(struct rpc_pipe_client *cli,
+                                      TALLOC_CTX *mem_ctx, 
+                                      POLICY_HND *dom_pol, uint32 num_sids,
+                                      DOM_SID2 *sid,
+                                      uint32 *num_aliases, uint32 **als_rids)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_USERALIASES q;
@@ -723,7 +788,7 @@ NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_query_useraliases(&q, dom_pol, num_sids, sid_ptrs, sid);
 
        if (!samr_io_q_query_useraliases("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERALIASES, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_USERALIASES, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -745,11 +810,24 @@ NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_useraliases(struct cli_state *cli,
+                                   TALLOC_CTX *mem_ctx, 
+                                   POLICY_HND *dom_pol, uint32 num_sids,
+                                   DOM_SID2 *sid,
+                                   uint32 *num_aliases, uint32 **als_rids)
+{
+       return rpccli_samr_query_useraliases(&cli->pipes[PI_SAMR], mem_ctx,
+                                            dom_pol, num_sids, sid,
+                                            num_aliases, als_rids);
+}
+
+
 /* Query user groups */
 
-NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                 POLICY_HND *group_pol, uint32 *num_mem, 
-                                 uint32 **rid, uint32 **attr)
+NTSTATUS rpccli_samr_query_groupmem(struct rpc_pipe_client *cli,
+                                   TALLOC_CTX *mem_ctx,
+                                   POLICY_HND *group_pol, uint32 *num_mem, 
+                                   uint32 **rid, uint32 **attr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_GROUPMEM q;
@@ -771,7 +849,7 @@ NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_query_groupmem(&q, group_pol);
 
        if (!samr_io_q_query_groupmem("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -794,6 +872,15 @@ NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                 POLICY_HND *group_pol, uint32 *num_mem, 
+                                 uint32 **rid, uint32 **attr)
+{
+       return rpccli_samr_query_groupmem(&cli->pipes[PI_SAMR], mem_ctx,
+                                         group_pol, num_mem, rid, attr);
+}
+
+
 /**
  * Enumerate domain users
  *
@@ -892,10 +979,11 @@ done:
 
 /* Enumerate domain groups */
 
-NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                  POLICY_HND *pol, uint32 *start_idx, 
-                                  uint32 size, struct acct_info **dom_groups,
-                                  uint32 *num_dom_groups)
+NTSTATUS rpccli_samr_enum_dom_groups(struct rpc_pipe_client *cli,
+                                    TALLOC_CTX *mem_ctx, 
+                                    POLICY_HND *pol, uint32 *start_idx, 
+                                    uint32 size, struct acct_info **dom_groups,
+                                    uint32 *num_dom_groups)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_ENUM_DOM_GROUPS q;
@@ -918,7 +1006,7 @@ NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_enum_dom_groups(&q, pol, *start_idx, size);
 
        if (!samr_io_q_enum_dom_groups("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf))
+           !rpc_api_pipe_req_int(cli, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf))
                goto done;
 
        /* Unmarshall response */
@@ -969,12 +1057,23 @@ NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                  POLICY_HND *pol, uint32 *start_idx, 
+                                  uint32 size, struct acct_info **dom_groups,
+                                  uint32 *num_dom_groups)
+{
+       return rpccli_samr_enum_dom_groups(&cli->pipes[PI_SAMR], mem_ctx,
+                                          pol, start_idx, size, dom_groups,
+                                          num_dom_groups);
+}
+
 /* Enumerate domain groups */
 
-NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                  POLICY_HND *pol, uint32 *start_idx, 
-                                  uint32 size, struct acct_info **dom_aliases,
-                                  uint32 *num_dom_aliases)
+NTSTATUS rpccli_samr_enum_als_groups(struct rpc_pipe_client *cli,
+                                    TALLOC_CTX *mem_ctx, 
+                                    POLICY_HND *pol, uint32 *start_idx, 
+                                    uint32 size, struct acct_info **dom_aliases,
+                                    uint32 *num_dom_aliases)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_ENUM_DOM_ALIASES q;
@@ -997,7 +1096,7 @@ NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_enum_dom_aliases(&q, pol, *start_idx, size);
 
        if (!samr_io_q_enum_dom_aliases("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -1051,6 +1150,16 @@ NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                  POLICY_HND *pol, uint32 *start_idx, 
+                                  uint32 size, struct acct_info **dom_aliases,
+                                  uint32 *num_dom_aliases)
+{
+       return rpccli_samr_enum_als_groups(&cli->pipes[PI_SAMR], mem_ctx,
+                                          pol, start_idx, size, dom_aliases,
+                                          num_dom_aliases);
+}
+
 /* Query alias members */
 
 NTSTATUS cli_samr_query_aliasmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
@@ -1326,7 +1435,7 @@ NTSTATUS cli_samr_query_alias_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        SAMR_R_QUERY_ALIASINFO r;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 
-       DEBUG(10,("cli_samr_query_dom_info\n"));
+       DEBUG(10,("cli_samr_query_alias_info\n"));
 
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
@@ -1368,9 +1477,11 @@ NTSTATUS cli_samr_query_alias_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 /* Query domain info */
 
-NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                 POLICY_HND *domain_pol, uint16 switch_value,
-                                 SAM_UNK_CTR *ctr)
+NTSTATUS rpccli_samr_query_dom_info(struct rpc_pipe_client *cli,
+                                   TALLOC_CTX *mem_ctx, 
+                                   POLICY_HND *domain_pol,
+                                   uint16 switch_value,
+                                   SAM_UNK_CTR *ctr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_DOMAIN_INFO q;
@@ -1392,7 +1503,7 @@ NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_query_dom_info(&q, domain_pol, switch_value);
 
        if (!samr_io_q_query_dom_info("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -1417,12 +1528,21 @@ NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                 POLICY_HND *domain_pol, uint16 switch_value,
+                                 SAM_UNK_CTR *ctr)
+{
+       return rpccli_samr_query_dom_info(&cli->pipes[PI_SAMR], mem_ctx,
+                                         domain_pol, switch_value, ctr);
+}
+
 /* User change password */
 
-NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                const char *username, 
-                                const char *newpassword, 
-                                const char *oldpassword )
+NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
+                                   TALLOC_CTX *mem_ctx, 
+                                   const char *username, 
+                                   const char *newpassword, 
+                                   const char *oldpassword )
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_CHGPASSWD_USER q;
@@ -1477,14 +1597,14 @@ NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        /* Marshall data and send request */
 
-       init_samr_q_chgpasswd_user(&q, cli->srv_name_slash, username, 
+       init_samr_q_chgpasswd_user(&q, cli->cli->srv_name_slash, username, 
                                   new_nt_password, 
                                   old_nt_hash_enc, 
                                   new_lm_password,
                                   old_lanman_hash_enc);
 
        if (!samr_io_q_chgpasswd_user("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_CHGPASSWD_USER, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, SAMR_CHGPASSWD_USER, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -1507,6 +1627,15 @@ NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                const char *username, 
+                                const char *newpassword, 
+                                const char *oldpassword )
+{
+       return rpccli_samr_chgpasswd_user(&cli->pipes[PI_SAMR], mem_ctx,
+                                         username, newpassword, oldpassword);
+}
+
 /* This function returns the bizzare set of (max_entries, max_size) required
    for the QueryDisplayInfo RPC to actually work against a domain controller
    with large (10k and higher) numbers of users.  These values were 
@@ -1541,11 +1670,12 @@ void get_query_dispinfo_params(int loop_count, uint32 *max_entries,
 
 /* Query display info */
 
-NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                 POLICY_HND *domain_pol, uint32 *start_idx,
-                                 uint16 switch_value, uint32 *num_entries,
-                                 uint32 max_entries, uint32 max_size,
-                                SAM_DISPINFO_CTR *ctr)
+NTSTATUS rpccli_samr_query_dispinfo(struct rpc_pipe_client *cli,
+                                   TALLOC_CTX *mem_ctx, 
+                                   POLICY_HND *domain_pol, uint32 *start_idx,
+                                   uint16 switch_value, uint32 *num_entries,
+                                   uint32 max_entries, uint32 max_size,
+                                   SAM_DISPINFO_CTR *ctr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_QUERY_DISPINFO q;
@@ -1570,7 +1700,7 @@ NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
                                   *start_idx, max_entries, max_size);
 
        if (!samr_io_q_query_dispinfo("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -1601,14 +1731,26 @@ NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                 POLICY_HND *domain_pol, uint32 *start_idx,
+                                 uint16 switch_value, uint32 *num_entries,
+                                 uint32 max_entries, uint32 max_size,
+                                SAM_DISPINFO_CTR *ctr)
+{
+       return rpccli_samr_query_dispinfo(&cli->pipes[PI_SAMR], mem_ctx,
+                                         domain_pol, start_idx, switch_value,
+                                         num_entries, max_entries, max_size, ctr);
+}
+
 /* Lookup rids.  Note that NT4 seems to crash if more than ~1000 rids are
    looked up in one packet. */
 
-NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                              POLICY_HND *domain_pol,
-                              uint32 num_rids, uint32 *rids, 
-                              uint32 *num_names, char ***names,
-                              uint32 **name_types)
+NTSTATUS rpccli_samr_lookup_rids(struct rpc_pipe_client *cli,
+                                TALLOC_CTX *mem_ctx, 
+                                POLICY_HND *domain_pol,
+                                uint32 num_rids, uint32 *rids, 
+                                uint32 *num_names, char ***names,
+                                uint32 **name_types)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_LOOKUP_RIDS q;
@@ -1636,7 +1778,7 @@ NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        init_samr_q_lookup_rids(mem_ctx, &q, domain_pol, 1000, num_rids, rids);
 
        if (!samr_io_q_lookup_rids("", &q, &qbuf, 0) ||
-           !rpc_api_pipe_req(cli, PI_SAMR, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
+           !rpc_api_pipe_req_int(cli, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
                goto done;
        }
 
@@ -1679,6 +1821,17 @@ NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return result;
 }
 
+NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                              POLICY_HND *domain_pol,
+                              uint32 num_rids, uint32 *rids, 
+                              uint32 *num_names, char ***names,
+                              uint32 **name_types)
+{
+       return rpccli_samr_lookup_rids(&cli->pipes[PI_SAMR], mem_ctx, 
+                                      domain_pol, num_rids, rids, 
+                                      num_names, names, name_types);
+}
+
 /* Lookup names */
 
 NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
index cccad9ad559d5c740ff036dd1ffd10f8c09098b0..493536eb2a2e70b6e1fecc3e4c1ec0f5504382b9 100644 (file)
@@ -1240,6 +1240,32 @@ BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_
        return True;
 }
 
+BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth,
+                     const char **str)
+{
+       size_t len;
+       char *tmp_str;
+
+       if (UNMARSHALLING(ps))
+               len = strlen(&ps->data_p[ps->data_offset]);
+       else
+               len = strlen(*str);
+
+       tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
+
+       if (tmp_str == NULL)
+               return False;
+
+       if (MARSHALLING(ps))
+               strncpy(tmp_str, *str, len);
+
+       if (!prs_string(name, ps, depth, tmp_str, len+1))
+               return False;
+
+       *str = tmp_str;
+       return True;
+}
+
 /*******************************************************************
  prs_uint16 wrapper. Call this and it sets up a pointer to where the
  uint16 should be stored, or gets the size if reading.
index 14004327ad43eeab4a1f13a1110f9c80fa60d350..feaeae4da6819ab6b197ae654d00fae54ef16006 100644 (file)
@@ -315,7 +315,7 @@ static NTSTATUS cmd_sign(struct cli_state *cli, TALLOC_CTX *mem_ctx,
                /* still have session, just need to use it again */
                cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
                cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
-               if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
+               if (cli->pipes[cli->pipe_idx].fnum != 0)
                        cli_nt_session_close(cli);
        }
 
@@ -332,7 +332,7 @@ static NTSTATUS cmd_seal(struct cli_state *cli, TALLOC_CTX *mem_ctx,
                cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
                cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
                cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
-               if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
+               if (cli->pipes[cli->pipe_idx].fnum != 0)
                        cli_nt_session_close(cli);
        }
        return NT_STATUS_OK; 
@@ -346,7 +346,7 @@ static NTSTATUS cmd_none(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        } else {
                /* still have session, just need to use it again */
                cli->pipe_auth_flags = 0;
-               if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
+               if (cli->pipes[cli->pipe_idx].fnum != 0)
                        cli_nt_session_close(cli);
        }
        cli->pipe_auth_flags = 0;
@@ -362,34 +362,19 @@ static NTSTATUS setup_schannel(struct cli_state *cli, int pipe_auth_flags,
        uchar trust_password[16];
        uint32 sec_channel_type;
        if (argc == 2) {
-               strhex_to_str((char *)cli->auth_info.sess_key,
-                             strlen(argv[1]), 
-                             argv[1]);
-               memcpy(cli->sess_key, cli->auth_info.sess_key, sizeof(cli->sess_key));
-
+               strhex_to_str(cli->sess_key, strlen(argv[1]), argv[1]);
                cli->pipe_auth_flags = pipe_auth_flags;
                return NT_STATUS_OK;
        }
 
        /* Cleanup */
 
-       if ((memcmp(cli->auth_info.sess_key, zeros, sizeof(cli->auth_info.sess_key)) != 0)) {
-               if (cli->pipe_auth_flags == pipe_auth_flags) {
+       if ((memcmp(cli->sess_key, zeros, sizeof(cli->sess_key)) != 0) &&
+           (cli->pipe_auth_flags == pipe_auth_flags)) {
                        /* already in this mode nothing to do */
                        return NT_STATUS_OK;
-               } else {
-                       /* schannel is setup, just need to use it again with new flags */
-                       cli->pipe_auth_flags = pipe_auth_flags;
-
-                       if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
-                               cli_nt_session_close(cli);
-                       return NT_STATUS_OK;
-               }
        }
        
-       if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
-               cli_nt_session_close(cli);
-
        if (!secrets_fetch_trust_account_password(lp_workgroup(),
                                                  trust_password,
                                                  NULL, &sec_channel_type)) {
@@ -399,8 +384,8 @@ static NTSTATUS setup_schannel(struct cli_state *cli, int pipe_auth_flags,
        ret = cli_nt_setup_netsec(cli, sec_channel_type, pipe_auth_flags, trust_password);
        if (NT_STATUS_IS_OK(ret)) {
                char *hex_session_key;
-               hex_encode(cli->auth_info.sess_key,
-                          sizeof(cli->auth_info.sess_key),
+               hex_encode(cli->pipes[cli->pipe_idx].auth_info.sess_key,
+                          sizeof(cli->pipes[cli->pipe_idx].auth_info.sess_key),
                           &hex_session_key);
                printf("Got Session key: %s\n", hex_session_key);
                SAFE_FREE(hex_session_key);
@@ -523,7 +508,7 @@ static NTSTATUS do_cmd(struct cli_state *cli,
 
        if (cmd_entry->pipe_idx != -1
            && cmd_entry->pipe_idx != cli->pipe_idx) {
-               if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
+               if (cli->pipes[cli->pipe_idx].fnum != 0)
                        cli_nt_session_close(cli);
                
                if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
@@ -549,7 +534,7 @@ static NTSTATUS do_cmd(struct cli_state *cli,
                                              trust_password,
                                              &neg_flags, 2);
                if (!NT_STATUS_IS_OK(ntresult)) {
-                       ZERO_STRUCT(cli->auth_info.sess_key);
+                       ZERO_STRUCT(cli->pipes[cli->pipe_idx].auth_info.sess_key);
                        printf("nt_setup_creds failed with %s\n", nt_errstr(ntresult));
                        return ntresult;
                }
index d18157643b1e0a67b9efbcbfaccab785bb2a4673..91fe97e23a44610c689138d64ee608c3519f8160 100644 (file)
@@ -153,11 +153,16 @@ BOOL idmap_init(const char **remote_backend)
  Don't do id mapping. This is used to make winbind a netlogon proxy only.
 **************************************************************************/
 
-void idmap_proxyonly(void)
+void idmap_set_proxyonly(void)
 {
        proxyonly = True;
 }
 
+BOOL idmap_proxyonly(void)
+{
+       return proxyonly;
+}
+
 /**************************************************************************
  This is a rare operation, designed to allow an explicit mapping to be
  set up for a sid to a POSIX id.
@@ -223,7 +228,7 @@ NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
                return NT_STATUS_OK;
        }
 
-       if (remote_map == NULL) {
+       if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY)) {
                return ret;
        }
 
@@ -288,7 +293,7 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
        if (NT_STATUS_IS_OK(ret))
                return ret;
 
-       if (remote_map == NULL)
+       if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY))
                return ret;
 
        /* We have a second chance, ask our authoritative backend */
index 5773cd34790840111e3b700cfb5d75f87552f51e..b4a8c8a75285cf217fc92e485f4b4e2322d8a7ce 100644 (file)
@@ -71,7 +71,8 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
        else
                fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
 
-       pstr_sprintf(id_str, "%d", ((id_type & ID_USERID) ? id.uid : id.gid));  
+       pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
+                                                (unsigned long)id.gid));       
        
        smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
 
@@ -500,9 +501,9 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
                type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
 
        pstrcpy( suffix, lp_ldap_idmap_suffix() );
-       pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))",
+       pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
                LDAP_OBJ_IDMAP_ENTRY, type,  
-               ((id_type & ID_USERID) ? id.uid : id.gid));
+               ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
                
        attr_list = get_attr_list( sidmap_attr_list );
        rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
@@ -700,8 +701,8 @@ static NTSTATUS verify_idpool( void )
                        return NT_STATUS_UNSUCCESSFUL;
                }
                
-               fstr_sprintf( uid_str, "%d", luid );
-               fstr_sprintf( gid_str, "%d", lgid );
+               fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
+               fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
 
                smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
                smbldap_set_mod( &mods, LDAP_MOD_ADD, 
index 41689f413b91302e1b8f986d87fd96b9c6d3a40f..3c9f420a9a7eb21a264fb80e4235d2d7b50250b2 100644 (file)
@@ -100,14 +100,13 @@ BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
  Returns SID pointer.
 *****************************************************************/  
 
-NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
+NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid, int flags)
 {
        unid_t id;
-       int flags;
 
        DEBUG(10,("idmap_uid_to_sid: uid = [%lu]\n", (unsigned long)uid));
 
-       flags = ID_USERID;
+       flags |= ID_USERID;
        id.uid = uid;
        
        return idmap_get_sid_from_id(sid, id, flags);
@@ -118,20 +117,15 @@ NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
  Returns SID pointer.
 *****************************************************************/  
 
-NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid)
+NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid, int flags)
 {
        unid_t id;
-       int flags;
 
        DEBUG(10,("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid));
 
-       flags = ID_GROUPID;
-#if 0  /* JERRY */
-       if (!idmap_check_ugid_is_in_free_range(gid)) {
-               flags |= ID_QUERY_ONLY;
-       }
-#endif
+       flags |= ID_GROUPID;
        id.gid = gid;
+
        return idmap_get_sid_from_id(sid, id, flags);
 }
 
index 98e36983b09df4fd0bad60b541cf1893380a218b..28067c1a0ae73b3f8f48441cd735016eb256a0f8 100644 (file)
@@ -288,7 +288,7 @@ enum client_action
        {
                int i;
                for (i=0; i<PI_MAX_PIPES; i++)
-                       smb_cli->nt_pipe_fnum[i]   = 0xffff;
+                       smb_cli->pipes[i].fnum   = 0xffff;
        }
 
        setup_logging(pname, True);
index 9793932b5137039f7a78401a9764b645a853b595..000e77345efe56f5f6fb62115125e1806234d212 100644 (file)
@@ -141,7 +141,7 @@ int run_rpc_command(struct cli_state *cli_arg, const int pipe_idx, int conn_flag
        }
                
        if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
-               if (cli->nt_pipe_fnum[cli->pipe_idx])
+               if (cli->pipes[cli->pipe_idx].fnum)
                        cli_nt_session_close(cli);
        }
 
@@ -663,11 +663,11 @@ static NTSTATUS rpc_user_del_internals(const DOM_SID *domain_sid,
        }
 
        /* Display results */
-       if (!NT_STATUS_IS_OK(result)) {
+    if (!NT_STATUS_IS_OK(result)) {
                d_printf("Failed to delete user account - %s\n", nt_errstr(result));
-       } else {
-               d_printf("Deleted user account\n");
-       }
+    } else {
+        d_printf("Deleted user account\n");
+    }
 
  done:
        return result;
@@ -4452,6 +4452,7 @@ static int rpc_trustdom_add(int argc, const char **argv)
        }
 }
 
+
 /**
  * Remove interdomain trust account from the RPC server.
  * All parameters (except for argc and argv) are passed by run_rpc_command
@@ -4582,6 +4583,7 @@ static int rpc_trustdom_del(int argc, const char **argv)
                return -1;
        }
 }
 
 /**
  * Establish trust relationship to a trusting domain.
@@ -4676,7 +4678,7 @@ static int rpc_trustdom_establish(int argc, const char **argv)
                cli_shutdown(cli);
                return -1;
        }
-       
+
        /*
         * Call LsaOpenPolicy and LsaQueryInfo
         */
@@ -4739,7 +4741,7 @@ static int rpc_trustdom_establish(int argc, const char **argv)
                return -1;
        }
 
-       if (cli->nt_pipe_fnum[cli->pipe_idx])
+       if (cli->pipes[cli->pipe_idx].fnum)
                cli_nt_session_close(cli);
 
        cli_shutdown(cli);
index 2f2393ca7aa345c37abc40449f318b6c6e95341c..6888076a147fda5fbf7f87d8aa596ea3109c7b42 100644 (file)
@@ -77,7 +77,7 @@ static int net_rpc_join_ok(const char *domain)
        
 done:
        /* Close down pipe - this will clean up open policy handles */
-       if (cli->nt_pipe_fnum[cli->pipe_idx])
+       if (cli->pipes[cli->pipe_idx].fnum)
                cli_nt_session_close(cli);
 
        cli_shutdown(cli);
@@ -346,7 +346,7 @@ int net_rpc_join_newstyle(int argc, const char **argv)
 done:
        /* Close down pipe - this will clean up open policy handles */
 
-       if (cli->nt_pipe_fnum[cli->pipe_idx])
+       if (cli->pipes[cli->pipe_idx].fnum)
                cli_nt_session_close(cli);
 
        /* Display success or failure */
index 5a7b6548c29cb4ad0b07810fc2c3ef62b0dd1d6c..c0de85cea5d4eac826e567a4b0968e5ba28e71cd 100644 (file)
@@ -428,8 +428,7 @@ static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
                        return False;
                }
 
-               notify_printer_byname(argv[2], attribute,
-                                      CONST_DISCARD(char *, argv[4]));
+               notify_printer_byname(argv[2], attribute, argv[4]);
 
                goto send;
        }
@@ -573,6 +572,53 @@ static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
        return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
 }
 
+static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
+{
+       fstring unix_name;
+       memset( (char *)n, '\0', sizeof(struct nmb_name) );
+       fstrcpy(unix_name, name);
+       strupper_m(unix_name);
+       push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
+       n->name_type = (unsigned int)type & 0xFF;
+       push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
+}
+
+static BOOL do_nodestatus(const pid_t pid, const int argc,
+                         const char **argv)
+{
+       struct packet_struct p;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
+               return False;
+       }
+
+       ZERO_STRUCT(p);
+
+       p.ip = *interpret_addr2(argv[1]);
+       p.port = 137;
+       p.packet_type = NMB_PACKET;
+
+       p.packet.nmb.header.name_trn_id = 10;
+       p.packet.nmb.header.opcode = 0;
+       p.packet.nmb.header.response = False;
+       p.packet.nmb.header.nm_flags.bcast = False;
+       p.packet.nmb.header.nm_flags.recursion_available = False;
+       p.packet.nmb.header.nm_flags.recursion_desired = False;
+       p.packet.nmb.header.nm_flags.trunc = False;
+       p.packet.nmb.header.nm_flags.authoritative = False;
+       p.packet.nmb.header.rcode = 0;
+       p.packet.nmb.header.qdcount = 1;
+       p.packet.nmb.header.ancount = 0;
+       p.packet.nmb.header.nscount = 0;
+       p.packet.nmb.header.arcount = 0;
+       my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
+       p.packet.nmb.question.question_type = 0x21;
+       p.packet.nmb.question.question_class = 0x1;
+
+       return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
+}
+
 /* A list of message type supported */
 
 static const struct {
@@ -597,6 +643,7 @@ static const struct {
        { "shutdown", do_shutdown, "Shut down daemon" },
        { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
        { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
+       { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
        { "noop", do_noop, "Do nothing" },
        { NULL }
 };