1
0
mirror of https://github.com/samba-team/samba.git synced 2025-10-16 11:33:16 +03:00

r7415: * big change -- volker's new async winbindd from trunk

(This used to be commit a0ac9a8ffd)
This commit is contained in:
Gerald Carter
2005-06-08 22:10:34 +00:00
committed by Gerald (Jerry) Carter
parent 66bb4f03c3
commit fed660877c
51 changed files with 7628 additions and 3246 deletions

View File

@@ -328,7 +328,6 @@ GROUPDB_OBJ = groupdb/mapping.o
PROFILE_OBJ = profile/profile.o PROFILE_OBJ = profile/profile.o
PROFILES_OBJ = utils/profiles.o PROFILES_OBJ = utils/profiles.o
EDITREG_OBJ = utils/editreg.o
OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.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_cm.o \
nsswitch/winbindd_wins.o \ nsswitch/winbindd_wins.o \
nsswitch/winbindd_rpc.o \ nsswitch/winbindd_rpc.o \
nsswitch/winbindd_reconnect.o \
nsswitch/winbindd_ads.o \ nsswitch/winbindd_ads.o \
nsswitch/winbindd_passdb.o \ nsswitch/winbindd_passdb.o \
nsswitch/winbindd_dual.o nsswitch/winbindd_dual.o \
nsswitch/winbindd_async.o
WINBINDD_OBJ = \ WINBINDD_OBJ = \
$(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_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) \ NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \ libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \
libads/kerberos_verify.o $(SECRETS_OBJ) $(SERVER_MUTEX_OBJ) \ libads/kerberos_verify.o $(SECRETS_OBJ) $(SERVER_MUTEX_OBJ) \
libads/authdata.o $(RPC_PARSE_OBJ0) \ libads/authdata.o $(RPC_PARSE_OBJ0) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(DOSERR_OBJ) $(SMBLDAP_OBJ) $(DOSERR_OBJ)
###################################################################### ######################################################################
# now the rules... # now the rules...
@@ -852,10 +853,6 @@ bin/profiles@EXEEXT@: $(PROFILES_OBJ) @BUILD_POPT@ bin/.dummy
@echo Linking $@ @echo Linking $@
@$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ @SOCKWRAP@ @$(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 bin/smbspool@EXEEXT@: $(CUPS_OBJ) bin/.dummy
@echo Linking $@ @echo Linking $@
@$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) @$(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 \ @$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_SPOOLSS_OBJ) -lc \
@SONAMEFLAG@`basename $@` @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) bin/librpc_netdfs.@SHLIBEXT@: $(RPC_DFS_OBJ)
@echo "Linking $@" @echo "Linking $@"
@$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_DFS_OBJ) -lc \ @$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_DFS_OBJ) -lc \
@@ -1496,7 +1498,8 @@ headers:
$(MAKE) nsswitch/winbindd_proto.h; \ $(MAKE) nsswitch/winbindd_proto.h; \
$(MAKE) web/swat_proto.h; \ $(MAKE) web/swat_proto.h; \
$(MAKE) client/client_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 proto: headers

View File

@@ -57,6 +57,27 @@ struct print_job_info
time_t t; 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 { struct cli_state {
int port; int port;
int fd; int fd;
@@ -124,25 +145,19 @@ struct cli_state {
of the pipe we're talking to, of the pipe we're talking to,
if any */ if any */
uint16 nt_pipe_fnum[PI_MAX_PIPES]; /* Pipe handle. */ struct rpc_pipe_client pipes[PI_MAX_PIPES];
/* Secure pipe parameters */ /* Secure pipe parameters */
int pipe_auth_flags; int pipe_auth_flags;
uint16 saved_netlogon_pipe_fnum; /* The "first" pipe to get struct rpc_pipe_client netlogon_pipe; /* The "first" pipe to get
the session key for the the session key for the
schannel. */ schannel. */
struct netsec_auth_struct auth_info;
NTLMSSP_STATE *ntlmssp_pipe_state;
unsigned char sess_key[16]; /* Current session key. */ unsigned char sess_key[16]; /* Current session key. */
DOM_CRED clnt_cred; /* Client credential. */ DOM_CRED clnt_cred; /* Client credential. */
fstring mach_acct; /* MYNAME$. */ fstring mach_acct; /* MYNAME$. */
fstring srv_name_slash; /* \\remote server. */ fstring srv_name_slash; /* \\remote server. */
fstring clnt_name_slash; /* \\local client. */ fstring clnt_name_slash; /* \\local client. */
uint16 max_xmit_frag;
uint16 max_recv_frag;
BOOL use_kerberos; BOOL use_kerberos;
BOOL fallback_after_kerberos; BOOL fallback_after_kerberos;

View File

@@ -35,6 +35,7 @@
#define ID_TYPEMASK 0x0f #define ID_TYPEMASK 0x0f
#define ID_QUERY_ONLY 0x10 #define ID_QUERY_ONLY 0x10
#define ID_CACHE_ONLY 0x20
/* Filled out by IDMAP backends */ /* Filled out by IDMAP backends */
struct idmap_methods { struct idmap_methods {

View File

@@ -804,7 +804,12 @@ extern int errno;
#include "tdb/tdb.h" #include "tdb/tdb.h"
#include "tdb/spinlock.h" #include "tdb/spinlock.h"
#include "tdb/tdbutil.h" #include "tdb/tdbutil.h"
#include "talloc.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 "nt_status.h"
#include "ads.h" #include "ads.h"
#include "interfaces.h" #include "interfaces.h"

View File

@@ -46,6 +46,7 @@
/* nmbd messages */ /* nmbd messages */
#define MSG_FORCE_ELECTION 1001 #define MSG_FORCE_ELECTION 1001
#define MSG_WINS_NEW_ENTRY 1002 #define MSG_WINS_NEW_ENTRY 1002
#define MSG_SEND_PACKET 1003
/* printing messages */ /* printing messages */
/* #define MSG_PRINTER_NOTIFY 2001*/ /* Obsolete */ /* #define MSG_PRINTER_NOTIFY 2001*/ /* Obsolete */
@@ -63,6 +64,10 @@
#define MSG_SMB_SAM_REPL 3004 #define MSG_SMB_SAM_REPL 3004
#define MSG_SMB_UNLOCK 3005 #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() */ /* Flags to classify messages - used in message_send_all() */
/* Sender will filter by flag. */ /* Sender will filter by flag. */

View File

@@ -21,9 +21,10 @@
#ifndef _RPC_CLIENT_H #ifndef _RPC_CLIENT_H
#define _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;\ { r_out.status = default_error;\
prs_init( &q_ps, MAX_PDU_FRAG_LEN, ctx, MARSHALL ); \ prs_init( &q_ps, MAX_PDU_FRAG_LEN, ctx, MARSHALL ); \
prs_init( &r_ps, 0, ctx, UNMARSHALL );\ prs_init( &r_ps, 0, ctx, UNMARSHALL );\
@@ -38,4 +39,22 @@
prs_mem_free( &r_ps );\ 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 */ #endif /* _RPC_CLIENT_H */

View 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__ #ifdef __INSURE__
/******************************************************************* /*******************************************************************

View File

@@ -342,6 +342,12 @@ BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
return False; 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 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 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) DOM_SID **sids, int *num)
{ {
if (mem_ctx != NULL) if (mem_ctx != NULL)

View File

@@ -2128,3 +2128,69 @@ BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
*num += 1; *num += 1;
return True; 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;
}

View File

@@ -88,8 +88,7 @@ int kerberos_kinit_password(const char *principal,
return code; return code;
} }
if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password,
CONST_DISCARD(char *, password),
kerb_prompter, kerb_prompter,
NULL, 0, NULL, NULL))) { NULL, 0, NULL, NULL))) {
krb5_free_principal(ctx, me); krb5_free_principal(ctx, me);

View File

@@ -26,105 +26,101 @@
* cli_send_mailslot, send a mailslot for client code ... * cli_send_mailslot, send a mailslot for client code ...
*/ */
int cli_send_mailslot(int dgram_sock, BOOL unique, const char *mailslot, BOOL cli_send_mailslot(BOOL unique, const char *mailslot,
char *buf, int len, uint16 priority,
const char *srcname, int src_type, char *buf, int len,
const char *dstname, int dest_type, const char *srcname, int src_type,
struct in_addr dest_ip, struct in_addr src_ip, const char *dstname, int dest_type,
int dest_port, int src_port) struct in_addr dest_ip)
{ {
struct packet_struct p; struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram; struct dgram_packet *dgram = &p.packet.dgram;
char *ptr, *p2; char *ptr, *p2;
char tmp[4]; char tmp[4];
pid_t nmbd_pid;
memset((char *)&p, '\0', sizeof(p)); if ((nmbd_pid = pidfile_pid("nmbd")) == 0) {
DEBUG(3, ("No nmbd found\n"));
return False;
}
/* if (!message_init())
* Next, build the DGRAM ... return False;
*/
/* DIRECT GROUP or UNIQUE datagram. */ memset((char *)&p, '\0', sizeof(p));
dgram->header.msg_type = unique ? 0x10 : 0x11;
dgram->header.flags.node_type = M_NODE; /*
dgram->header.flags.first = True; * Next, build the DGRAM ...
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; /* DIRECT GROUP or UNIQUE datagram. */
dgram->header.source_port = ntohs(src_port); dgram->header.msg_type = unique ? 0x10 : 0x11;
dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */ dgram->header.flags.node_type = M_NODE;
dgram->header.packet_offset = 0; 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->source_name,srcname,src_type);
make_nmb_name(&dgram->dest_name,dstname,dest_type); make_nmb_name(&dgram->dest_name,dstname,dest_type);
ptr = &dgram->data[0]; ptr = &dgram->data[0];
/* Setup the smb part. */ /* Setup the smb part. */
ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
memcpy(tmp,ptr,4); memcpy(tmp,ptr,4);
set_message(ptr,17,strlen(mailslot) + 1 + len,True); set_message(ptr,17,strlen(mailslot) + 1 + len,True);
memcpy(ptr,tmp,4); memcpy(ptr,tmp,4);
SCVAL(ptr,smb_com,SMBtrans); SCVAL(ptr,smb_com,SMBtrans);
SSVAL(ptr,smb_vwv1,len); SSVAL(ptr,smb_vwv1,len);
SSVAL(ptr,smb_vwv11,len); SSVAL(ptr,smb_vwv11,len);
SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
SSVAL(ptr,smb_vwv13,3); SSVAL(ptr,smb_vwv13,3);
SSVAL(ptr,smb_vwv14,1); SSVAL(ptr,smb_vwv14,1);
SSVAL(ptr,smb_vwv15,1); SSVAL(ptr,smb_vwv15,priority);
SSVAL(ptr,smb_vwv16,2); SSVAL(ptr,smb_vwv16,2);
p2 = smb_buf(ptr); p2 = smb_buf(ptr);
fstrcpy(p2,mailslot); fstrcpy(p2,mailslot);
p2 = skip_string(p2,1); p2 = skip_string(p2,1);
memcpy(p2,buf,len); memcpy(p2,buf,len);
p2 += len; p2 += len;
dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
p.ip = dest_ip; p.packet_type = DGRAM_PACKET;
p.port = dest_port; p.ip = dest_ip;
p.fd = dgram_sock; p.timestamp = time(NULL);
p.timestamp = time(NULL);
p.packet_type = DGRAM_PACKET;
DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot, DEBUG(4,("send_mailslot: Sending to mailslot %s from %s ",
nmb_namestr(&dgram->source_name), inet_ntoa(src_ip))); mailslot, nmb_namestr(&dgram->source_name)));
DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip))); DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name),
inet_ntoa(dest_ip)));
return send_packet(&p);
return message_send_pid(nmbd_pid, MSG_SEND_PACKET, &p, sizeof(p),
False);
} }
/* /*
* cli_get_response: Get a response ... * 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; struct packet_struct *p;
packet = receive_dgram_packet(dgram_sock, 5, mailslot); p = receive_unexpected(DGRAM_PACKET, 0, mailslot);
if (packet) { /* We got one, pull what we want out of the SMB data ... */ if (p == NULL)
return False;
struct dgram_packet *dgram = &packet->packet.dgram; memcpy(buf, &p->packet.dgram.data[92],
MIN(bufsiz, p->packet.dgram.datasize-92));
/*
* We should probably parse the SMB, but for now, we will pull what
* from fixed, known locations ...
*/
/* Copy the data to buffer, respecting sizes ... */
memcpy(buf, &dgram->data[92], MIN(bufsiz, (dgram->datasize - 92)));
}
else
return -1;
return 0;
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) int cli_get_backup_list(const char *myname, const char *send_to_name)
{ {
pstring outbuf; pstring outbuf;
char *p; char *p;
struct in_addr sendto_ip, my_ip; struct in_addr sendto_ip;
int dgram_sock;
struct sockaddr_in sock_out;
socklen_t name_size;
if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) { if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name)); DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
return False; return False;
} }
my_ip.s_addr = inet_addr("0.0.0.0"); memset(cli_backup_list, '\0', sizeof(cli_backup_list));
memset(outbuf, '\0', sizeof(outbuf));
if (!resolve_name(myname, &my_ip, 0x00)) { /* FIXME: Call others here */
DEBUG(0, ("Could not resolve name: %s<00>\n", myname)); p = outbuf;
} SCVAL(p, 0, ANN_GetBackupListReq);
p++;
if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) { SCVAL(p, 0, 1); /* Count pointer ... */
p++;
DEBUG(4, ("open_sock_out failed ...")); SIVAL(p, 0, 1); /* The sender's token ... */
return False; p += 4;
} cli_send_mailslot(True, "\\MAILSLOT\\BROWSE", 1, outbuf,
PTR_DIFF(p, outbuf), myname, 0, send_to_name,
0x1d, sendto_ip);
/* Make it a broadcast socket ... */ /* We should check the error and return if we got one */
set_socket_options(dgram_sock, "SO_BROADCAST"); /* Now, get the response ... */
/* Make it non-blocking??? */ cli_get_response("\\MAILSLOT\\BROWSE",
cli_backup_list, sizeof(cli_backup_list));
if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) { return True;
DEBUG(0, ("Unable to set non blocking on dgram sock\n"));
}
/* 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;
}
}
/* Now, figure out what socket name we were bound to. We want the port */
name_size = sizeof(sock_out);
getsockname(dgram_sock, (struct sockaddr *)&sock_out, &name_size);
DEBUG(5, ("Socket bound to IP:%s, port: %d\n", inet_ntoa(sock_out.sin_addr), ntohs(sock_out.sin_port)));
/* Now, build the request */
memset(cli_backup_list, '\0', sizeof(cli_backup_list));
memset(outbuf, '\0', sizeof(outbuf));
p = outbuf;
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;
} }

View File

@@ -22,8 +22,6 @@
#include "includes.h" #include "includes.h"
extern int smb_read_error;
/**************************************************************************** /****************************************************************************
Change the timeout (in milliseconds). 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) BOOL cli_receive_smb(struct cli_state *cli)
{ {
extern int smb_read_error;
BOOL ret; BOOL ret;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ /* 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); cli_null_set_signing(cli);
for (i=0; i<PI_MAX_PIPES; i++) 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->initialised = 1;
cli->allocated = alloced_cli; cli->allocated = alloced_cli;
@@ -353,14 +352,14 @@ void cli_nt_session_close(struct cli_state *cli)
{ {
int i; int i;
if (cli->ntlmssp_pipe_state) {
ntlmssp_end(&cli->ntlmssp_pipe_state);
}
for (i=0; i<PI_MAX_PIPES; i++) { for (i=0; i<PI_MAX_PIPES; i++) {
if (cli->nt_pipe_fnum[i] != 0) if (cli->pipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
cli_close(cli, cli->nt_pipe_fnum[i]); ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state);
cli->nt_pipe_fnum[i] = 0; }
if (cli->pipes[i].fnum != 0)
cli_close(cli, cli->pipes[i].fnum);
cli->pipes[i].fnum = 0;
} }
cli->pipe_idx = -1; 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) void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
{ {
if (cli->saved_netlogon_pipe_fnum != 0) { if (cli->netlogon_pipe.fnum != 0) {
cli_close(cli, cli->saved_netlogon_pipe_fnum); cli_close(cli, cli->netlogon_pipe.fnum);
cli->saved_netlogon_pipe_fnum = 0; 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->secblob);
data_blob_free(&cli->user_session_key); data_blob_free(&cli->user_session_key);
if (cli->ntlmssp_pipe_state) if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP)
ntlmssp_end(&cli->ntlmssp_pipe_state); ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state);
if (cli->mem_ctx) { if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx); talloc_destroy(cli->mem_ctx);

View File

@@ -505,7 +505,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*/ */
if (cli_is_dos_error(cli)) { if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode); 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); cli_signing_trans_stop(cli);
return(False); return(False);
} }
@@ -639,7 +639,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
} }
if (cli_is_dos_error(cli)) { if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode); 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); cli_signing_trans_stop(cli);
return(False); return(False);
} }

View 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. 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_WINS_NEW_ENTRY, nmbd_wins_new_entry);
message_register(MSG_SHUTDOWN, nmbd_terminate); message_register(MSG_SHUTDOWN, nmbd_terminate);
message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services); 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 ) ); DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );

View File

@@ -257,6 +257,32 @@ BOOL winbind_allocate_rid(uint32 *rid)
return True; 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 /* Fetch the list of groups a user is a member of from winbindd. This is
used by winbind_getgroups. */ used by winbind_getgroups. */

View File

@@ -167,6 +167,32 @@ static BOOL wbinfo_get_usersids(char *user_sid)
return True; 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 */ /* Convert NetBIOS name to IP */
static BOOL wbinfo_wins_byname(char *name) static BOOL wbinfo_wins_byname(char *name)
@@ -224,7 +250,6 @@ static BOOL wbinfo_wins_byip(char *ip)
static BOOL wbinfo_list_domains(void) static BOOL wbinfo_list_domains(void)
{ {
struct winbindd_response response; struct winbindd_response response;
fstring name;
ZERO_STRUCT(response); ZERO_STRUCT(response);
@@ -238,9 +263,19 @@ static BOOL wbinfo_list_domains(void)
if (response.extra_data) { if (response.extra_data) {
const char *extra_data = (char *)response.extra_data; const char *extra_data = (char *)response.extra_data;
fstring name;
char *p;
while(next_token(&extra_data, name, ",", sizeof(fstring))) 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); d_printf("%s\n", name);
}
SAFE_FREE(response.extra_data); SAFE_FREE(response.extra_data);
} }
@@ -316,6 +351,32 @@ static BOOL wbinfo_domain_info(const char *domain_name)
return True; 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 */ /* Check trust account password */
static BOOL wbinfo_check_secret(void) static BOOL wbinfo_check_secret(void)
@@ -889,6 +950,8 @@ enum {
OPT_GET_AUTH_USER, OPT_GET_AUTH_USER,
OPT_DOMAIN_NAME, OPT_DOMAIN_NAME,
OPT_SEQUENCE, OPT_SEQUENCE,
OPT_GETDCNAME,
OPT_USERDOMGROUPS,
OPT_USERSIDS 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" }, { "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" }, { "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-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" }, { "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" }, { "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" }, { "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 }, { "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" }, { "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" }, { "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; goto done;
} }
break; 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': { case 'a': {
BOOL got_error = False; BOOL got_error = False;
@@ -1116,6 +1190,9 @@ int main(int argc, char **argv)
case OPT_GET_AUTH_USER: case OPT_GET_AUTH_USER:
wbinfo_get_auth_user(); wbinfo_get_auth_user();
break; break;
case OPT_GETDCNAME:
wbinfo_getdcname(string_arg);
break;
/* generic configuration options */ /* generic configuration options */
case OPT_DOMAIN_NAME: case OPT_DOMAIN_NAME:
break; break;

View File

@@ -6,6 +6,7 @@
Copyright (C) by Tim Potter 2000-2002 Copyright (C) by Tim Potter 2000-2002
Copyright (C) Andrew Tridgell 2002 Copyright (C) Andrew Tridgell 2002
Copyright (C) Jelmer Vernooij 2003 Copyright (C) Jelmer Vernooij 2003
Copyright (C) Volker Lendecke 2004
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
BOOL opt_nocache = False; BOOL opt_nocache = False;
BOOL opt_dual_daemon = True; BOOL opt_dual_daemon = True;
static BOOL interactive = False;
extern BOOL override_logfile; extern BOOL override_logfile;
@@ -131,7 +133,6 @@ static void winbindd_status(void)
static void print_winbindd_status(void) static void print_winbindd_status(void)
{ {
winbindd_status(); winbindd_status();
winbindd_cm_status();
} }
/* Flush client cache */ /* Flush client cache */
@@ -163,6 +164,17 @@ static void terminate(void)
pstr_sprintf(path, "%s/%s", pstr_sprintf(path, "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME); WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path); 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); exit(0);
} }
@@ -190,14 +202,11 @@ static void sighup_handler(int signum)
sys_select_signal(); sys_select_signal();
} }
static BOOL do_sigchld;
static void sigchld_handler(int signum) static void sigchld_handler(int signum)
{ {
pid_t pid; do_sigchld = True;
int status;
while ((pid = wait(&status)) != -1 || errno == EINTR) {
continue; /* Reap children */
}
sys_select_signal(); sys_select_signal();
} }
@@ -215,13 +224,7 @@ static void msg_shutdown(int msg_type, pid_t src, void *buf, size_t len)
terminate(); terminate();
} }
struct dispatch_table { static struct winbindd_dispatch_table 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[] = {
/* User functions */ /* User functions */
@@ -234,6 +237,8 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" }, { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
{ WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" }, { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
{ WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
"GETUSERDOMGROUPS" },
/* Group functions */ /* Group functions */
@@ -247,14 +252,15 @@ static struct dispatch_table dispatch_table[] = {
/* PAM auth functions */ /* PAM auth functions */
{ WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" }, { 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" }, { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
/* Enumeration functions */ /* Enumeration functions */
{ WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" }, { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
{ WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" }, { 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" }, { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
/* SID related functions */ /* 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_UID, winbindd_sid_to_uid, "SID_TO_UID" },
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" }, { 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_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, winbindd_allocate_rid, "ALLOCATE_RID" },
{ WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid,
"ALLOCATE_RID_AND_GID" },
/* Miscellaneous */ /* Miscellaneous */
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" }, { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
{ WINBINDD_PING, winbindd_ping, "PING" }, { WINBINDD_PING, winbindd_ping, "PING" },
{ WINBINDD_INFO, winbindd_info, "INFO" }, { 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_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" }, { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" }, { 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 */ /* WINS functions */
@@ -293,7 +304,7 @@ static struct dispatch_table dispatch_table[] = {
static void process_request(struct winbindd_cli_state *state) 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 /* Free response data - we may be interrupted and receive another
command before being able to send this data off. */ 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); ZERO_STRUCT(state->response);
state->response.result = WINBINDD_ERROR; state->response.result = WINBINDD_PENDING;
state->response.length = sizeof(struct winbindd_response); state->response.length = sizeof(struct winbindd_response);
state->mem_ctx = talloc_init("winbind request");
if (state->mem_ctx == NULL)
return;
/* Process command */ /* Process command */
for (table = dispatch_table; table->fn; table++) { for (table = dispatch_table; table->fn; table++) {
if (state->request.cmd == table->cmd) { 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); state->response.result = table->fn(state);
break; break;
} }
} }
if (!table->fn) if (!table->fn) {
DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd )); DEBUG(10,("process_request: unknown request fn number %d\n",
(int)state->request.cmd ));
state->response.result = WINBINDD_ERROR;
}
}
/* In case extra data pointer is NULL */ /*
* 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.
*/
if (!state->response.extra_data) static struct fd_event *fd_events = NULL;
state->response.length = sizeof(struct winbindd_response);
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);
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;
}
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 */ /* 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 */ /* 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; return;
ZERO_STRUCTP(state);
state->sock = sock; state->sock = sock;
state->last_access = time(NULL); state->last_access = time(NULL);
state->privileged = privileged; 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 */ /* Add to connection list */
winbindd_add_client(state); winbindd_add_client(state);
@@ -384,11 +630,18 @@ static void remove_client(struct winbindd_cli_state *state)
client was killed unexpectedly */ client was killed unexpectedly */
SAFE_FREE(state->response.extra_data); 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 */ /* Remove from list and free */
winbindd_remove_client(state); 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) { for (state = winbindd_client_list(); state; state = state->next) {
if (state->read_buf_len == 0 && state->write_buf_len == 0 && 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++; nidle++;
if (!last_access || state->last_access < last_access) { if (!last_access || state->last_access < last_access) {
last_access = state->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->request.null_term = '\0';
state->pid = state->request.pid; state->pid = state->request.pid;
process_request(state); process_request(state);
/* Update client 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, /* Process incoming clients on listen_sock. We use a tricky non-blocking,
non-forking, non-threaded model which allows us to handle many non-forking, non-threaded model which allows us to handle many
simultaneous connections while remaining impervious to many denial of 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) static void process_loop(void)
{ {
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;
/* We'll be doing this a lot */ /* We'll be doing this a lot */
while (1) { /* Handle messages */
struct winbindd_cli_state *state;
fd_set r_fds, w_fds;
int maxfd, listen_sock, listen_priv_sock, selret;
struct timeval timeout;
again: message_dispatch();
/* Handle messages */
message_dispatch(); /* refresh the trusted domain cache */
/* refresh the trusted domain cache */
rescan_trusted_domains(); rescan_trusted_domains();
/* Free up temporary memory */ /* Free up temporary memory */
lp_talloc_free(); lp_talloc_free();
main_loop_talloc_free(); main_loop_talloc_free();
/* Initialise fd lists for select() */ /* Initialise fd lists for select() */
listen_sock = open_winbindd_socket(); listen_sock = open_winbindd_socket();
listen_priv_sock = open_winbindd_priv_socket(); listen_priv_sock = open_winbindd_priv_socket();
if (listen_sock == -1 || listen_priv_sock == -1) { if (listen_sock == -1 || listen_priv_sock == -1) {
perror("open_winbind_socket"); perror("open_winbind_socket");
exit(1); exit(1);
}
maxfd = MAX(listen_sock, listen_priv_sock);
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 */
state = winbindd_client_list();
while (state) {
struct winbindd_cli_state *next = state->next;
/* Dispose of client connection if it is marked as
finished */
if (state->finished)
remove_client(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) {
maxfd = MAX(listen_sock, listen_priv_sock); FD_SET(ev->fd, &w_fds);
maxfd = MAX(ev->fd, maxfd);
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 */ /* Call select */
state = winbindd_client_list();
while (state) {
/* Dispose of client connection if it is marked as
finished */
if (state->finished) {
struct winbindd_cli_state *next = state->next;
remove_client(state);
state = next;
continue;
}
/* Select requires we know the highest fd used */
if (state->sock > maxfd)
maxfd = state->sock;
/* Add fd for reading */
if (state->read_buf_len != sizeof(state->request))
FD_SET(state->sock, &r_fds);
/* Add fd for writing */
if (state->write_buf_len)
FD_SET(state->sock, &w_fds);
state = state->next;
}
/* 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) if (selret == 0)
continue; 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"); perror("select");
exit(1); 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) { ev = fd_events;
dual_select(&w_fds); 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)) { if (FD_ISSET(listen_sock, &r_fds)) {
while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) { while (winbindd_num_clients() >
DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n", WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); DEBUG(5,("winbindd: Exceeding %d client "
if (!remove_idle_client()) { "connections, removing idle "
DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n", "connection.\n",
WINBINDD_MAX_SIMULTANEOUS_CLIENTS)); WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
break; if (!remove_idle_client()) {
} DEBUG(0,("winbindd: Exceeding %d "
} "client connections, no idle "
/* new, non-privileged connection */ "connection found\n",
new_connection(listen_sock, False); WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
} break;
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;
}
}
} }
} }
/* 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);
}
no_fds_ready:
#if 0 #if 0
winbindd_check_cache_size(time(NULL)); winbindd_check_cache_size(time(NULL));
#endif #endif
/* Check signal handling things */ /* Check signal handling things */
if (do_sigterm) if (do_sigterm)
terminate(); 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); msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
do_sighup = False; do_sighup = False;
} }
if (do_sigusr2) { if (do_sigusr2) {
print_winbindd_status(); print_winbindd_status();
do_sigusr2 = False; 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) int main(int argc, char **argv)
{ {
pstring logfile; pstring logfile;
static BOOL interactive = False;
static BOOL Fork = True; static BOOL Fork = True;
static BOOL log_stdout = False; static BOOL log_stdout = False;
struct poptOption long_options[] = { struct poptOption long_options[] = {
@@ -886,7 +992,7 @@ int main(int argc, char **argv)
if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) || if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
(!idmap_init(lp_idmap_backend())) ) { (!idmap_init(lp_idmap_backend())) ) {
DEBUG(1, ("Could not init idmap -- netlogon proxy only\n")); 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 /* 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_domain_list();
init_idmap_child();
/* Loop waiting for requests */ /* Loop waiting for requests */
process_loop(); while (1)
process_loop();
trustdom_cache_shutdown(); trustdom_cache_shutdown();

View File

@@ -32,11 +32,25 @@
#undef DBGC_CLASS #undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND #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 {
struct winbindd_cli_state *prev, *next; /* Linked list pointers */ struct winbindd_cli_state *prev, *next; /* Linked list pointers */
int sock; /* Open socket from client */ int sock; /* Open socket from client */
struct fd_event fd_event;
pid_t pid; /* pid of client */ pid_t pid; /* pid of client */
int read_buf_len, write_buf_len; /* Indexes in request/response */ int read_buf_len, write_buf_len; /* Indexes in request/response */
BOOL finished; /* Can delete from list */ 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) */ time_t last_access; /* Time of last access (read or write) */
BOOL privileged; /* Is the client 'privileged' */ BOOL privileged; /* Is the client 'privileged' */
TALLOC_CTX *mem_ctx; /* memory per request */
struct winbindd_request request; /* Request from client */ struct winbindd_request request; /* Request from client */
struct winbindd_response response; /* Respose to client */ struct winbindd_response response; /* Respose to client */
BOOL getpwent_initialized; /* Has getpwent_state been initialized? */ BOOL getpwent_initialized; /* Has getpwent_state been
BOOL getgrent_initialized; /* Has getgrent_state been initialized? */ * initialized? */
BOOL getgrent_initialized; /* Has getgrent_state been
* initialized? */
struct getent_state *getpwent_state; /* State for getpwent() */ struct getent_state *getpwent_state; /* State for getpwent() */
struct getent_state *getgrent_state; /* State for getgrent() */ 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 */ 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 */ extern struct winbindd_state server_state; /* Server information */
typedef struct { typedef struct {
char *acct_name; char *acct_name;
char *full_name; char *full_name;
DOM_SID *user_sid; /* NT user and primary group SIDs */ DOM_SID user_sid; /* NT user and primary group SIDs */
DOM_SID *group_sid; DOM_SID group_sid;
} WINBIND_USERINFO; } 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 */ /* Structures to hold per domain information */
struct winbindd_domain { struct winbindd_domain {
@@ -123,6 +181,14 @@ struct winbindd_domain {
uint32 sequence_number; uint32 sequence_number;
NTSTATUS last_status; 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 */ /* Linked list info */
struct winbindd_domain *prev, *next; struct winbindd_domain *prev, *next;
@@ -181,13 +247,14 @@ struct winbindd_methods {
NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain, NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid, 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 /* Lookup all aliases that the sids delivered are member of. This is
* to implement 'domain local groups' correctly */ * to implement 'domain local groups' correctly */
NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain, NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
uint32 num_sids, DOM_SID **sids, uint32 num_sids,
const DOM_SID *sids,
uint32 *num_aliases, uint32 *num_aliases,
uint32 **alias_rids); uint32 **alias_rids);
@@ -196,7 +263,7 @@ struct winbindd_methods {
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, const DOM_SID *group_sid,
uint32 *num_names, uint32 *num_names,
DOM_SID ***sid_mem, char ***names, DOM_SID **sid_mem, char ***names,
uint32 **name_types); uint32 **name_types);
/* return the current global sequence number */ /* return the current global sequence number */

View File

@@ -27,8 +27,6 @@
#ifdef HAVE_ADS #ifdef HAVE_ADS
extern struct winbindd_methods msrpc_methods, cache_methods;
#undef DBGC_CLASS #undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND #define DBGC_CLASS DBGC_WINBIND
@@ -78,6 +76,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
status = ads_connect(ads); status = ads_connect(ads);
if (!ADS_ERR_OK(status) || !ads->config.realm) { 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", DEBUG(1,("ads_connect for domain %s failed: %s\n",
domain->name, ads_errstr(status))); domain->name, ads_errstr(status)));
ads_destroy(&ads); 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)) { for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
char *name, *gecos; char *name, *gecos;
DOM_SID sid;
DOM_SID *sid2;
DOM_SID *group_sid;
uint32 group; uint32 group;
uint32 atype; uint32 atype;
@@ -171,7 +167,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
name = ads_pull_username(ads, mem_ctx, msg); name = ads_pull_username(ads, mem_ctx, msg);
gecos = ads_pull_string(ads, mem_ctx, msg, "name"); 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)); DEBUG(1,("No sid for %s !?\n", name));
continue; continue;
} }
@@ -180,20 +177,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
continue; 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].acct_name = name;
(*info)[i].full_name = gecos; (*info)[i].full_name = gecos;
(*info)[i].user_sid = sid2; sid_compose(&(*info)[i].group_sid, &domain->sid, group);
(*info)[i].group_sid = group_sid;
i++; i++;
} }
@@ -386,8 +372,6 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
char *sidstr; char *sidstr;
uint32 group_rid; uint32 group_rid;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
DOM_SID *sid2;
fstring sid_string;
DEBUG(3,("ads: query_user\n")); DEBUG(3,("ads: query_user\n"));
@@ -404,13 +388,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
free(ldap_exp); free(ldap_exp);
free(sidstr); free(sidstr);
if (!ADS_ERR_OK(rc) || !msg) { 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; goto done;
} }
count = ads_count_replies(ads, msg); count = ads_count_replies(ads, msg);
if (count != 1) { 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; 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"); info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid))); DEBUG(1,("No primary group for %s !?\n",
sid_string_static(sid)));
goto done; goto done;
} }
sid2 = TALLOC_P(mem_ctx, DOM_SID);
if (!sid2) {
status = NT_STATUS_NO_MEMORY;
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; status = NT_STATUS_OK;
@@ -449,7 +428,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const char *user_dn, const char *user_dn,
DOM_SID *primary_group, DOM_SID *primary_group,
uint32 *num_groups, DOM_SID ***user_gids) uint32 *num_groups, DOM_SID **user_sids)
{ {
ADS_STATUS rc; ADS_STATUS rc;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -502,34 +481,24 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
goto done; goto done;
} }
(*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1); *user_sids = NULL;
(*user_gids)[0] = primary_group; *num_groups = 0;
*num_groups = 1; 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)) { for (msg = ads_first_entry(ads, res); msg;
msg = ads_next_entry(ads, msg)) {
DOM_SID group_sid; DOM_SID group_sid;
if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
DEBUG(1,("No sid for this group ?!?\n")); DEBUG(1,("No sid for this group ?!?\n"));
continue; 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); add_sid_to_array(mem_ctx, &group_sid, user_sids, num_groups);
(*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)); DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn));
done: done:
@@ -543,7 +512,7 @@ done:
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *sid, const DOM_SID *sid,
uint32 *num_groups, DOM_SID ***user_gids) uint32 *num_groups, DOM_SID **user_sids)
{ {
ADS_STRUCT *ads = NULL; ADS_STRUCT *ads = NULL;
const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL}; const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
@@ -553,7 +522,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
char *user_dn; char *user_dn;
DOM_SID *sids; DOM_SID *sids;
int i; int i;
DOM_SID *primary_group; DOM_SID primary_group;
uint32 primary_group_rid; uint32 primary_group_rid;
fstring sid_string; fstring sid_string;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -596,7 +565,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
goto done; 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); 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 */ unless we are talking to a buggy Win2k server */
if (count == 0) { if (count == 0) {
return lookup_usergroups_alt(domain, mem_ctx, user_dn, return lookup_usergroups_alt(domain, mem_ctx, user_dn,
primary_group, &primary_group,
num_groups, user_gids); num_groups, user_sids);
} }
(*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1); *user_sids = NULL;
(*user_gids)[0] = primary_group; *num_groups = 0;
*num_groups = 1;
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;
}
sid_copy((*user_gids)[*num_groups], &sids[i]); add_sid_to_array(mem_ctx, &primary_group, user_sids, num_groups);
(*num_groups)++;
} for (i=0;i<count;i++)
add_sid_to_array_unique(mem_ctx, &sids[i],
user_sids, num_groups);
status = NT_STATUS_OK; status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
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: done:
return status; return status;
} }
@@ -641,7 +604,7 @@ done:
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names, const DOM_SID *group_sid, uint32 *num_names,
DOM_SID ***sid_mem, char ***names, DOM_SID **sid_mem, char ***names,
uint32 **name_types) uint32 **name_types)
{ {
ADS_STATUS rc; ADS_STATUS rc;
@@ -652,8 +615,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
NTSTATUS status = NT_STATUS_UNSUCCESSFUL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
char *sidstr; char *sidstr;
char **members; char **members;
int i; int i, num_members;
size_t num_members;
fstring sid_string; fstring sid_string;
BOOL more_values; BOOL more_values;
const char **attrs; 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 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); (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
(*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, 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)) { if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) {
(*names)[*num_names] = name; (*names)[*num_names] = name;
(*name_types)[*num_names] = name_type; (*name_types)[*num_names] = name_type;
(*sid_mem)[*num_names] = TALLOC_P(mem_ctx, DOM_SID); sid_copy(&(*sid_mem)[*num_names], &sid);
if (!(*sid_mem)[*num_names]) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
sid_copy((*sid_mem)[*num_names], &sid);
(*num_names)++; (*num_names)++;
} }
} }
@@ -827,9 +784,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
struct ds_domain_trust *domains = NULL; struct ds_domain_trust *domains = NULL;
int count = 0; int count = 0;
int i; int i;
struct cli_state *cli = NULL;
/* i think we only need our forest and downlevel trusted domains */ /* i think we only need our forest and downlevel trusted domains */
uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND; uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
struct rpc_pipe_client *cli;
DEBUG(3,("ads: trusted_domains\n")); DEBUG(3,("ads: trusted_domains\n"));
@@ -837,16 +794,27 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*alt_names = NULL; *alt_names = NULL;
*names = NULL; *names = NULL;
*dom_sids = 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))); domain->name, nt_errstr(result)));
return NT_STATUS_UNSUCCESSFUL; return NT_STATUS_UNSUCCESSFUL;
} }
if ( NT_STATUS_IS_OK(result) ) if ( NT_STATUS_IS_OK(result) )
result = cli_ds_enum_domain_trusts( cli, mem_ctx, cli->desthost, result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
flags, &domains, (unsigned int *)&count ); cli->cli->desthost,
flags, &domains,
(unsigned int *)&count);
if ( NT_STATUS_IS_OK(result) && 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)) ) { if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n")); DEBUG(0, ("trusted_domains: out of memory\n"));
result = NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
goto done;
} }
if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) { if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n")); DEBUG(0, ("trusted_domains: out of memory\n"));
result = NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
goto done;
} }
if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) { if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
DEBUG(0, ("trusted_domains: out of memory\n")); DEBUG(0, ("trusted_domains: out of memory\n"));
result = NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
goto done;
} }
/* Copy across names and sids */ /* Copy across names and sids */
@@ -882,13 +847,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*num_domains = count; *num_domains = count;
} }
done:
/* remove connection; This is a special case to the \NETLOGON pipe */
if ( cli )
cli_shutdown( cli );
return result; return result;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -26,12 +26,6 @@
#include "includes.h" #include "includes.h"
#include "winbindd.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 #undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND #define DBGC_CLASS DBGC_WINBIND
@@ -53,6 +47,8 @@ static struct winbind_cache *wcache;
/* flush the cache */ /* flush the cache */
void wcache_flush_cache(void) void wcache_flush_cache(void)
{ {
extern BOOL opt_nocache;
if (!wcache) if (!wcache)
return; return;
if (wcache->tdb) { if (wcache->tdb) {
@@ -106,9 +102,11 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
struct winbind_cache *ret = wcache; struct winbind_cache *ret = wcache;
if (!domain->backend) { if (!domain->backend) {
extern struct winbindd_methods reconnect_methods;
switch (lp_security()) { switch (lp_security()) {
#ifdef HAVE_ADS #ifdef HAVE_ADS
case SEC_ADS: { case SEC_ADS: {
extern struct winbindd_methods ads_methods;
/* always obey the lp_security parameter for our domain */ /* always obey the lp_security parameter for our domain */
if (domain->primary) { if (domain->primary) {
domain->backend = &ads_methods; domain->backend = &ads_methods;
@@ -132,7 +130,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
default: default:
DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
domain->name)); 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"); 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) { if (!ret) {
smb_panic("centry_string out of memory\n"); 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 /* pull a string from a cache entry, using the supplied
talloc context 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; char *sid_string;
sid_string = centry_string(centry, NULL);
sid = TALLOC_P(mem_ctx, DOM_SID);
if (!sid)
return NULL;
sid_string = centry_string(centry, mem_ctx);
if (!string_to_sid(sid, sid_string)) { 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 */ /* 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); centry->sequence_number = centry_uint32(centry);
if (centry_expired(domain, kstr, centry)) { if (centry_expired(domain, kstr, centry)) {
extern BOOL opt_dual_daemon;
DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n", DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
kstr, domain->name )); kstr, domain->name ));
if (opt_dual_daemon) { if (opt_dual_daemon) {
extern BOOL background_process;
background_process = True; background_process = True;
DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n", DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
kstr, domain->name )); kstr, domain->name ));
@@ -654,9 +652,9 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI
return; return;
centry_put_string(centry, info->acct_name); centry_put_string(centry, info->acct_name);
centry_put_string(centry, info->full_name); centry_put_string(centry, info->full_name);
centry_put_sid(centry, info->user_sid); centry_put_sid(centry, &info->user_sid);
centry_put_sid(centry, info->group_sid); centry_put_sid(centry, &info->group_sid);
centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_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)); DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
centry_free(centry); centry_free(centry);
} }
@@ -691,8 +689,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
for (i=0; i<(*num_entries); i++) { for (i=0; i<(*num_entries); i++) {
(*info)[i].acct_name = centry_string(centry, mem_ctx); (*info)[i].acct_name = centry_string(centry, mem_ctx);
(*info)[i].full_name = centry_string(centry, mem_ctx); (*info)[i].full_name = centry_string(centry, mem_ctx);
(*info)[i].user_sid = centry_sid(centry, mem_ctx); centry_sid(centry, &(*info)[i].user_sid);
(*info)[i].group_sid = centry_sid(centry, mem_ctx); centry_sid(centry, &(*info)[i].group_sid);
} }
do_cached: do_cached:
@@ -729,10 +727,12 @@ do_query:
status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info); status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
if (!NT_STATUS_IS_OK(status)) if (!NT_STATUS_IS_OK(status))
DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status))); DEBUG(3, ("query_user_list: returned 0x%08x, "
if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) { "retrying\n", NT_STATUS_V(status)));
DEBUG(3, ("query_user_list: flushing connection cache\n")); if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
winbindd_cm_flush(); 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) && } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
@@ -747,17 +747,17 @@ do_query:
for (i=0; i<(*num_entries); i++) { for (i=0; i<(*num_entries); i++) {
centry_put_string(centry, (*info)[i].acct_name); centry_put_string(centry, (*info)[i].acct_name);
centry_put_string(centry, (*info)[i].full_name); centry_put_string(centry, (*info)[i].full_name);
centry_put_sid(centry, (*info)[i].user_sid); centry_put_sid(centry, &(*info)[i].user_sid);
centry_put_sid(centry, (*info)[i].group_sid); centry_put_sid(centry, &(*info)[i].group_sid);
if (domain->backend->consistent) { if (domain->backend->consistent) {
/* when the backend is consistent we can pre-prime some mappings */ /* when the backend is consistent we can pre-prime some mappings */
wcache_save_name_to_sid(domain, NT_STATUS_OK, wcache_save_name_to_sid(domain, NT_STATUS_OK,
domain->name, domain->name,
(*info)[i].acct_name, (*info)[i].acct_name,
(*info)[i].user_sid, &(*info)[i].user_sid,
SID_NAME_USER); SID_NAME_USER);
wcache_save_sid_to_name(domain, NT_STATUS_OK, wcache_save_sid_to_name(domain, NT_STATUS_OK,
(*info)[i].user_sid, &(*info)[i].user_sid,
domain->name, domain->name,
(*info)[i].acct_name, (*info)[i].acct_name,
SID_NAME_USER); SID_NAME_USER);
@@ -939,7 +939,6 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
struct cache_entry *centry = NULL; struct cache_entry *centry = NULL;
NTSTATUS status; NTSTATUS status;
fstring uname; fstring uname;
DOM_SID *sid2;
if (!cache->tdb) if (!cache->tdb)
goto do_query; goto do_query;
@@ -950,13 +949,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
if (!centry) if (!centry)
goto do_query; goto do_query;
*type = (enum SID_NAME_USE)centry_uint32(centry); *type = (enum SID_NAME_USE)centry_uint32(centry);
sid2 = centry_sid(centry, mem_ctx); centry_sid(centry, sid);
if (!sid2) {
ZERO_STRUCTP(sid);
} else {
sid_copy(sid, sid2);
}
status = centry->status; status = centry->status;
DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n", 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->acct_name = centry_string(centry, mem_ctx);
info->full_name = centry_string(centry, mem_ctx); info->full_name = centry_string(centry, mem_ctx);
info->user_sid = centry_sid(centry, mem_ctx); centry_sid(centry, &info->user_sid);
info->group_sid = centry_sid(centry, mem_ctx); centry_sid(centry, &info->group_sid);
status = centry->status; status = centry->status;
DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n", 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, static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid, 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 winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL; struct cache_entry *centry = NULL;
@@ -1157,11 +1150,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
if (*num_groups == 0) if (*num_groups == 0)
goto do_cached; 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)) if (! (*user_gids))
smb_panic("lookup_usergroups out of memory"); smb_panic("lookup_usergroups out of memory");
for (i=0; i<(*num_groups); i++) { for (i=0; i<(*num_groups); i++) {
(*user_gids)[i] = centry_sid(centry, mem_ctx); centry_sid(centry, &(*user_gids)[i]);
} }
do_cached: do_cached:
@@ -1194,7 +1187,7 @@ do_query:
goto skip_save; goto skip_save;
centry_put_uint32(centry, *num_groups); centry_put_uint32(centry, *num_groups);
for (i=0; i<(*num_groups); i++) { 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_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
centry_free(centry); centry_free(centry);
@@ -1205,7 +1198,7 @@ skip_save:
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
uint32 num_sids, DOM_SID **sids, uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **alias_rids) uint32 *num_aliases, uint32 **alias_rids)
{ {
struct winbind_cache *cache = get_cache(domain); 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++) { for (i=0; i<num_sids; i++) {
sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist, sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
sid_string_static(sids[i])); sid_string_static(&sids[i]));
if (sidlist == NULL) if (sidlist == NULL)
return NT_STATUS_NO_MEMORY; 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)) if (!NT_STATUS_IS_OK(domain->last_status))
return 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 )); "for domain %s\n", domain->name ));
status = domain->backend->lookup_useraliases(domain, mem_ctx, 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, static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names, const DOM_SID *group_sid, uint32 *num_names,
DOM_SID ***sid_mem, char ***names, DOM_SID **sid_mem, char ***names,
uint32 **name_types) uint32 **name_types)
{ {
struct winbind_cache *cache = get_cache(domain); struct winbind_cache *cache = get_cache(domain);
@@ -1312,7 +1305,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
if (*num_names == 0) if (*num_names == 0)
goto do_cached; 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); (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
(*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *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++) { 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); (*names)[i] = centry_string(centry, mem_ctx);
(*name_types)[i] = centry_uint32(centry); (*name_types)[i] = centry_uint32(centry);
} }
@@ -1359,7 +1352,7 @@ do_query:
goto skip_save; goto skip_save;
centry_put_uint32(centry, *num_names); centry_put_uint32(centry, *num_names);
for (i=0; i<(*num_names); i++) { 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_string(centry, (*names)[i]);
centry_put_uint32(centry, (*name_types)[i]); centry_put_uint32(centry, (*name_types)[i]);
} }
@@ -1466,3 +1459,166 @@ struct winbindd_methods cache_methods = {
trusted_domains, trusted_domains,
alternate_name 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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
Winbind background daemon Winbind background daemon
Copyright (C) Andrew Tridgell 2002 Copyright (C) Andrew Tridgell 2002
Copyright (C) Volker Lendecke 2004,2005
This program is free software; you can redistribute it and/or modify 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 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;
static struct dual_list *dual_list_end; 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 setup a select() including the dual daemon pipe
*/ */
@@ -176,7 +210,7 @@ void do_dual_daemon(void)
main_loop_talloc_free(); main_loop_talloc_free();
/* fetch a request from the main daemon */ /* fetch a request from the main daemon */
winbind_client_read(&state); dual_client_read(&state);
if (state.finished) { if (state.finished) {
/* we lost contact with our parent */ /* 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;
}
}
}

View File

@@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
enum SID_NAME_USE group_name_type, enum SID_NAME_USE group_name_type,
int *num_gr_mem, char **gr_mem, int *gr_mem_len) 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 num_names = 0;
uint32 *name_types = NULL; uint32 *name_types = NULL;
unsigned int buf_len, buf_ndx, i; unsigned int buf_len, buf_ndx, i;
@@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
if (DEBUGLEVEL >= 10) { if (DEBUGLEVEL >= 10) {
for (i = 0; i < num_names; i++) 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])); 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); 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()) ) { if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
fstrcpy(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 */ /* Get rid and name type from name */
if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid, if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
&name_type)) { name_group, &group_sid, &name_type)) {
DEBUG(1, ("group %s in domain %s does not exist\n", DEBUG(1, ("group %s in domain %s does not exist\n",
name_group, name_domain)); name_group, name_domain));
return WINBINDD_ERROR; return WINBINDD_ERROR;
@@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
return WINBINDD_ERROR; return WINBINDD_ERROR;
/* Get rid from gid */ /* 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", DEBUG(1, ("could not convert gid %lu to rid\n",
(unsigned long)state->request.data.gid)); (unsigned long)state->request.data.gid));
return WINBINDD_ERROR; return WINBINDD_ERROR;
@@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
/* Get name from sid */ /* 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")); DEBUG(1, ("could not lookup sid\n"));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* Fill in group structure */ /* Fill in group structure */
domain = find_domain_from_sid(&group_sid); domain = find_domain_from_sid_noinit(&group_sid);
if (!domain) { if (!domain) {
DEBUG(1,("Can't find domain from sid\n")); 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) ) if ( *which_domain && !strequal(which_domain, domain->name) )
continue; continue;
if ( !domain->initialized )
set_dc_type_and_flags( domain );
ZERO_STRUCT(groups); ZERO_STRUCT(groups);
@@ -856,323 +855,155 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
return WINBINDD_OK; 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 /* Get user supplementary groups. This is much quicker than trying to
invert the groups database. We merge the groups from the gids and invert the groups database. We merge the groups from the gids and
other_sids info3 fields as trusted domain, universal group other_sids info3 fields as trusted domain, universal group
memberships, and nested groups (win2k native mode only) are not memberships, and nested groups (win2k native mode only) are not
returned by the getgroups RPC call but are present in the info3. */ 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) enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
{ {
fstring name_domain, name_user; struct getgroups_state *s;
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;
/* Ensure null termination */ /* 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, DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
state->request.data.username)); 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 and username */
parse_domain_user(state->request.data.username, s = TALLOC_P(state->mem_ctx, struct getgroups_state);
name_domain, name_user); if (s == NULL) {
DEBUG(0, ("talloc failed\n"));
return WINBINDD_ERROR;
}
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 info for the domain */ /* Get info for the domain */
if ((domain = find_domain_from_name(name_domain)) == NULL) { s->domain = find_domain_from_name_noinit(s->domname);
if (s->domain == NULL) {
DEBUG(7, ("could not find domain entry for domain %s\n", DEBUG(7, ("could not find domain entry for domain %s\n",
name_domain)); s->domname));
goto done; return WINBINDD_ERROR;
} }
if ( domain->primary && lp_winbind_trusted_domains_only()) { if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
DEBUG(7,("winbindd_getgroups: My domain -- rejecting " DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
"getgroups() for %s\\%s.\n", name_domain, name_user)); "getgroups() for %s\\%s.\n", s->domname,
s->username));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* Get rid and name type from name. The following costs 1 packet */ /* Get rid and name type from name. The following costs 1 packet */
if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
&name_type)) { getgroups_usersid_recv, s);
DEBUG(4, ("user '%s' does not exist\n", name_user)); return WINBINDD_PENDING;
goto done;
}
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;
}
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);
}
SAFE_FREE(info3);
} else {
status = domain->methods->lookup_usergroups(domain, mem_ctx,
&user_sid, &num_groups,
&user_grpsids);
if (!NT_STATUS_IS_OK(status))
goto done;
if (state->response.extra_data)
goto done;
for (i = 0; i < num_groups; i++) {
add_gids_from_group_sid(user_grpsids[i],
&gid_list, &num_gids);
}
}
/* We want at least one group... */
if (gid_list == NULL)
goto done;
remove_duplicate_gids( &num_gids, gid_list );
/* Send data back to client */
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;
} }
static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid, static void getgroups_usersid_recv(void *private, BOOL success,
DOM_SID ***sids, int *num_sids) const DOM_SID *sid, enum SID_NAME_USE type)
{ {
int i; struct getgroups_state *s = private;
for (i=0; i<(*num_sids); i++) { if ((!success) ||
if (sid_compare(sid, (*sids)[i]) == 0) ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
s->state->response.result = WINBINDD_ERROR;
request_finished(s->state);
return;
}
sid_copy(&s->user_sid, sid);
winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
getgroups_tokensids_recv, s);
}
static void getgroups_tokensids_recv(void *private, BOOL success,
DOM_SID *token_sids, int num_token_sids)
{
struct getgroups_state *s = private;
/* 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;
}
s->token_sids = token_sids;
s->num_token_sids = num_token_sids;
s->i = 0;
s->token_gids = NULL;
s->num_token_gids = 0;
getgroups_sid2gid_recv(s, False, 0);
}
static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid)
{
struct getgroups_state *s = private;
if (success)
add_gid_to_array_unique(NULL, gid,
&s->token_gids,
&s->num_token_gids);
if (s->i < s->num_token_sids) {
const DOM_SID *sid = &s->token_sids[s->i];
s->i += 1;
if (sid_equal(sid, &s->user_sid)) {
getgroups_sid2gid_recv(s, False, 0);
return; return;
}
winbindd_sid2gid_async(s->state->mem_ctx, sid,
getgroups_sid2gid_recv, s);
return;
} }
*sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1); s->state->response.data.num_entries = s->num_token_gids;
s->state->response.extra_data = s->token_gids;
if (*sids == NULL) s->state->response.length += s->num_token_gids * sizeof(gid_t);
return; s->state->response.result = WINBINDD_OK;
request_finished(s->state);
(*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID);
sid_copy((*sids)[*num_sids], sid);
*num_sids += 1;
return;
}
static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
DOM_SID ***user_grpsids,
int *num_groups)
{
DOM_SID *aliases = NULL;
int i, num_aliases = 0;
if (!enum_alias_memberships(sid, &aliases, &num_aliases))
return;
if (num_aliases == 0)
return;
for (i=0; i<num_aliases; i++)
add_sid_to_parray_unique(mem_ctx, &aliases[i], user_grpsids,
num_groups);
SAFE_FREE(aliases);
return;
} }
/* Get user supplementary sids. This is equivalent to the /* 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 you pass in another type of SID then you may get unpredictable
results. 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) enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
{ {
DOM_SID user_sid; 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;
/* Ensure null termination */ /* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
if (!string_to_sid(&user_sid, state->request.data.sid)) { user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid)); if (user_sid == NULL) {
DEBUG(1, ("talloc failed\n"));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)", if (!string_to_sid(user_sid, state->request.data.sid)) {
state->request.data.username))) { DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.sid));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* Get info for the domain */ winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
if ((domain = find_domain_from_sid(&user_sid)) == NULL) { state);
DEBUG(0,("could not find domain entry for sid %s\n", return WINBINDD_PENDING;
sid_string_static(&user_sid))); }
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;
state->response.result = WINBINDD_ERROR;
if (!success)
goto done; goto done;
}
status = domain->methods->lookup_usergroups(domain, mem_ctx,
&user_sid, &num_groups,
&user_grpsids);
if (!NT_STATUS_IS_OK(status))
goto done;
if (num_groups == 0) {
goto no_groups;
}
domain = find_our_domain();
if (domain == NULL) {
DEBUG(0, ("Could not find our domain\n"));
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 */ /* work out the response size */
for (i = 0; i < num_groups; i++) { for (i = 0; i < num_sids; i++) {
const char *s = sid_string_static(user_grpsids[i]); const char *s = sid_string_static(&sids[i]);
ret_size += strlen(s) + 1; ret_size += strlen(s) + 1;
} }
@@ -1293,22 +1068,94 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
ret = SMB_MALLOC(ret_size); ret = SMB_MALLOC(ret_size);
if (!ret) goto done; if (!ret) goto done;
ofs = 0; ofs = 0;
for (i = 0; i < num_groups; i++) { for (i = 0; i < num_sids; i++) {
const char *s = sid_string_static(user_grpsids[i]); const char *s = sid_string_static(&sids[i]);
safe_strcpy(ret + ofs, s, ret_size - ofs - 1); safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
ofs += strlen(ret+ofs) + 1; ofs += strlen(ret+ofs) + 1;
} }
no_groups:
/* Send data back to client */ /* 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.extra_data = ret;
state->response.length += ret_size; state->response.length += ret_size;
result = WINBINDD_OK; state->response.result = WINBINDD_OK;
done: 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;
}

View File

@@ -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;
}

View File

@@ -30,12 +30,21 @@
/* Check the machine account password is valid */ /* Check the machine account password is valid */
enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state) 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; NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uchar trust_passwd[16];
int num_retries = 0; int num_retries = 0;
struct cli_state *cli;
uint32 sec_channel_type;
struct winbindd_domain *contact_domain; struct winbindd_domain *contact_domain;
DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid)); 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 */ /* Get trust account password */
again: 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(); 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 /* This call does a cli_nt_setup_creds() which implicitly checks
the trust account password. */ the trust account password. */
/* Don't shut this down - it belongs to the connection cache code */
invalidate_cm_connection(&contact_domain->conn);
result = cm_get_netlogon_cli(contact_domain,
trust_passwd, sec_channel_type, True, &cli); {
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)) { if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n")); 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; return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
} }
enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state)
*state)
{ {
struct winbindd_domain *domain; DEBUG(3, ("[%5lu]: list trusted domains\n",
int total_entries = 0, extra_data_len = 0; (unsigned long)state->pid));
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;
}
/* We need to refresh the trusted domain list as the domains may enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
have changed since we last looked. There may be a sequence struct winbindd_cli_state *state)
number or something we should use but I haven't found it yet. */ {
uint32 i, num_domains;
char **names, **alt_names;
DOM_SID *sids;
int extra_data_len = 0;
char *extra_data;
NTSTATUS result;
if (!init_domain_list()) { DEBUG(3, ("[%5lu]: list trusted domains\n",
DEBUG(1, ("winbindd_list_trusted_domains: could not " (unsigned long)state->pid));
"refresh trusted domain list\n"));
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;
}
return WINBINDD_OK;
}
enum winbindd_result winbindd_getdcname(struct winbindd_cli_state *state)
{
state->request.domain_name
[sizeof(state->request.domain_name)-1] = '\0';
DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
state->request.domain_name));
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_getdcname(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
fstring dcname_slash;
char *p;
struct rpc_pipe_client *cli;
NTSTATUS result;
state->request.domain_name
[sizeof(state->request.domain_name)-1] = '\0';
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);
}
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("Can't contact our the NETLOGON pipe\n"));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
for(domain = domain_list(); domain; domain = domain->next) { result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
state->request.domain_name,
dcname_slash);
/* Skip own domain */ if (!NT_STATUS_IS_OK(result)) {
DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
if (domain->primary) continue; return WINBINDD_ERROR;
/* Add domain to list */
total_entries++;
ted = SMB_REALLOC(extra_data, sizeof(fstring) *
total_entries);
if (!ted) {
DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
SAFE_FREE(extra_data);
return WINBINDD_ERROR;
} else
extra_data = ted;
memcpy(&extra_data[extra_data_len], domain->name,
strlen(domain->name));
extra_data_len += strlen(domain->name);
extra_data[extra_data_len++] = ',';
} }
if (extra_data) { p = dcname_slash;
if (extra_data_len > 1) if (*p == '\\') p+=1;
extra_data[extra_data_len - 1] = '\0'; if (*p == '\\') p+=1;
state->response.extra_data = extra_data;
state->response.length += extra_data_len; fstrcpy(state->response.data.dc_name, p);
}
return WINBINDD_OK; 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) enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
{ {
struct winbindd_domain *domain; struct sequence_state *seq;
char *extra_data = NULL;
const char *which_domain;
/* 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)); DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
/* Ensure null termination */ /* Ensure null termination */
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0'; state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
which_domain = state->request.domain_name;
extra_data = SMB_STRDUP(""); domain->methods->sequence_number(domain, &domain->sequence_number);
/* this makes for a very simple data format, and is easily parsable as well state->response.data.domain_info.sequence_number =
if that is ever needed */ domain->sequence_number;
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->response.extra_data = extra_data;
/* must add one to length to copy the 0 for string termination */
state->response.length += strlen(extra_data) + 1;
return WINBINDD_OK; 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) enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
{ {
struct winbindd_domain *domain; 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, DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
state->request.domain_name)); 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) { if (domain == NULL) {
DEBUG(3, ("Did not find domain [%s]\n", 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; return WINBINDD_ERROR;
} }
fstrcpy(state->response.data.domain_info.name, domain->name); if (!domain->initialized) {
fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name); 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, fstrcpy(state->response.data.domain_info.sid,
sid_string_static(&domain->sid)); sid_string_static(&domain->sid));
state->response.data.domain_info.native_mode = domain->native_mode; state->response.data.domain_info.native_mode =
state->response.data.domain_info.active_directory = domain->active_directory; domain->native_mode;
state->response.data.domain_info.primary = domain->primary; 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 = state->response.data.domain_info.sequence_number =
domain->sequence_number; domain->sequence_number;
return WINBINDD_OK; 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 enum winbindd_result winbindd_ping(struct winbindd_cli_state
*state) *state)
{ {

View File

@@ -34,7 +34,7 @@
/* Update this when you change the interface. */ /* Update this when you change the interface. */
#define WINBIND_INTERFACE_VERSION 10 #define WINBIND_INTERFACE_VERSION 11
/* Socket commands */ /* Socket commands */
@@ -83,6 +83,7 @@ enum winbindd_cmd {
WINBINDD_UID_TO_SID, WINBINDD_UID_TO_SID,
WINBINDD_GID_TO_SID, WINBINDD_GID_TO_SID,
WINBINDD_ALLOCATE_RID, WINBINDD_ALLOCATE_RID,
WINBINDD_ALLOCATE_RID_AND_GID,
/* Miscellaneous other stuff */ /* Miscellaneous other stuff */
@@ -93,6 +94,7 @@ enum winbindd_cmd {
WINBINDD_DOMAIN_INFO, /* Most of what we know from WINBINDD_DOMAIN_INFO, /* Most of what we know from
struct winbindd_domain */ struct winbindd_domain */
WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */ WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
@@ -110,9 +112,29 @@ enum winbindd_cmd {
WINBINDD_PRIV_PIPE_DIR, WINBINDD_PRIV_PIPE_DIR,
/* return a list of group sids for a user sid */ /* 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 WINBINDD_NUM_CMDS
}; };
@@ -148,6 +170,9 @@ typedef struct winbindd_gr {
#define WBFLAG_PAM_AFS_TOKEN 0x0100 #define WBFLAG_PAM_AFS_TOKEN 0x0100
#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200 #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 */ /* Winbind request structure */
struct winbindd_request { struct winbindd_request {
@@ -156,6 +181,7 @@ struct winbindd_request {
pid_t pid; /* pid of calling process */ pid_t pid; /* pid of calling process */
uint32 flags; /* flags relavant to a given request */ uint32 flags; /* flags relavant to a given request */
fstring domain_name; /* name of domain for which the request applies */ fstring domain_name; /* name of domain for which the request applies */
int msgid;
union { union {
fstring winsreq; /* WINS request */ fstring winsreq; /* WINS request */
@@ -197,6 +223,24 @@ struct winbindd_request {
fstring username; fstring username;
fstring groupname; fstring groupname;
} acct_mgt; } 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; } data;
char null_term; char null_term;
}; };
@@ -205,6 +249,7 @@ struct winbindd_request {
enum winbindd_result { enum winbindd_result {
WINBINDD_ERROR, WINBINDD_ERROR,
WINBINDD_PENDING,
WINBINDD_OK WINBINDD_OK
}; };
@@ -250,6 +295,7 @@ struct winbindd_response {
} info; } info;
fstring domain_name; fstring domain_name;
fstring netbios_name; fstring netbios_name;
fstring dc_name;
struct auth_reply { struct auth_reply {
uint32 nt_status; uint32 nt_status;
@@ -260,6 +306,10 @@ struct winbindd_response {
char first_8_lm_hash[8]; char first_8_lm_hash[8];
} auth; } auth;
uint32 rid; /* create user or group or allocate rid */ uint32 rid; /* create user or group or allocate rid */
struct {
uint32 rid;
gid_t gid;
} rid_and_gid;
struct { struct {
fstring name; fstring name;
fstring alt_name; fstring alt_name;
@@ -269,6 +319,11 @@ struct winbindd_response {
BOOL primary; BOOL primary;
uint32 sequence_number; uint32 sequence_number;
} domain_info; } domain_info;
struct {
fstring acct_name;
fstring full_name;
uint32 group_rid;
} user_info;
} data; } data;
/* Variable length return data */ /* Variable length return data */

View File

@@ -145,24 +145,99 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
return NT_STATUS_LOGON_FAILURE; 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 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; NTSTATUS result;
fstring name_domain, name_user; fstring name_domain, name_user;
unsigned char trust_passwd[16]; const char *srv_name_slash;
time_t last_change_time;
uint32 sec_channel_type;
NET_USER_INFO_3 info3; NET_USER_INFO_3 info3;
struct cli_state *cli = NULL; unsigned char *session_key;
struct rpc_pipe_client *pipe_cli;
uchar chal[8]; uchar chal[8];
TALLOC_CTX *mem_ctx = NULL;
DATA_BLOB lm_resp; DATA_BLOB lm_resp;
DATA_BLOB nt_resp; DATA_BLOB nt_resp;
DOM_CRED ret_creds; DOM_CRED ret_creds;
DOM_CRED *credentials;
int attempts = 0; int attempts = 0;
unsigned char local_lm_response[24]; unsigned char local_lm_response[24];
unsigned char local_nt_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, DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
state->request.data.auth.user)); 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 and username */
parse_domain_user(state->request.data.auth.user, name_domain, name_user); 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 names_blob;
DATA_BLOB nt_response; DATA_BLOB nt_response;
DATA_BLOB lm_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 /* 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 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(&names_blob);
data_blob_free(&server_chal); data_blob_free(&server_chal);
lm_resp = data_blob_talloc(mem_ctx, lm_response.data, lm_response.length); lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
nt_resp = data_blob_talloc(mem_ctx, nt_response.data, nt_response.length); 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(&lm_response);
data_blob_free(&nt_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, && SMBencrypt(state->request.data.auth.pass,
chal, chal,
local_lm_response)) { local_lm_response)) {
lm_resp = data_blob_talloc(mem_ctx, lm_resp = data_blob_talloc(state->mem_ctx,
local_lm_response, local_lm_response,
sizeof(local_lm_response)); sizeof(local_lm_response));
} else { } else {
@@ -238,7 +309,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
chal, chal,
local_nt_response); local_nt_response);
nt_resp = data_blob_talloc(mem_ctx, nt_resp = data_blob_talloc(state->mem_ctx,
local_nt_response, local_nt_response,
sizeof(local_nt_response)); sizeof(local_nt_response));
} }
@@ -261,80 +332,95 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
goto done; goto done;
} }
if (!(contact_domain = find_our_domain())) { 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;
}
} }
if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) { srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; contact_domain->dcname);
goto done; if (srv_name_slash == NULL) {
DEBUG(0, ("talloc_asprintf failed\n"));
return WINBINDD_ERROR;
} }
/* check authentication loop */ /* check authentication loop */
do { do {
DOM_CRED clnt_creds;
ZERO_STRUCT(info3); ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds); ZERO_STRUCT(ret_creds);
retry = False; retry = False;
/* Don't shut this down - it belongs to the connection cache code */ result = cm_connect_netlogon(contact_domain, state->mem_ctx,
result = cm_get_netlogon_cli(contact_domain, trust_passwd, &pipe_cli, &session_key,
sec_channel_type, False, &cli); &credentials);
if (!NT_STATUS_IS_OK(result)) { if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n")); DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
goto done; goto done;
} }
result = cli_netlogon_sam_network_logon(cli, mem_ctx, credentials->timestamp.time = time(NULL);
&ret_creds, memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
name_user, name_domain,
global_myname(), chal, /* Calculate the new credentials. */
lm_resp, nt_resp, cred_create(session_key, &credentials->challenge,
&info3); 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; 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 might not yet have noticed that the DC has killed
our connection. */ our connection. */
if ( cli->fd == -1 ) { if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
retry = True; retry = True;
continue; continue;
} }
/* if we get access denied, a possible cuase was that we had and open /* if we get access denied, a possible cause was that we had
connection to the DC, but someone changed our machine account password and open connection to the DC, but someone changed our
out from underneath us using 'net rpc changetrustpw' */ machine account password out from underneath us using 'net
rpc changetrustpw' */
if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) { if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
DEBUG(3,("winbindd_pam_auth: sam_logon returned ACCESS_DENIED. Maybe the trust account " DEBUG(3,("winbindd_pam_auth: sam_logon returned "
"password was changed and we didn't know it. Killing connections to domain %s\n", "ACCESS_DENIED. Maybe the trust account "
"password was changed and we didn't know it. "
"Killing connections to domain %s\n",
name_domain)); name_domain));
winbindd_cm_flush(); invalidate_cm_connection(&contact_domain->conn);
retry = True; retry = True;
cli = NULL;
} }
} while ( (attempts < 2) && retry ); } while ( (attempts < 2) && retry );
if (cli != NULL) { if (NT_STATUS_IS_OK(result) &&
/* We might have come out of the loop above with cli == NULL, (!clnt_deal_with_creds(session_key, credentials,
so don't dereference that. */ &ret_creds))) {
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &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)) { 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); wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
/* Check if the user is in the right group */ /* 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", 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.user,
state->request.data.auth.require_membership_of_sid)); state->request.data.auth.require_membership_of_sid));
@@ -407,9 +493,6 @@ done:
SAFE_FREE(afsname); SAFE_FREE(afsname);
} }
if (mem_ctx)
talloc_destroy(mem_ctx);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
} }
@@ -417,15 +500,79 @@ done:
Challenge Response Authentication Protocol 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;
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; NTSTATUS result;
unsigned char trust_passwd[16]; const char *srv_name_slash;
time_t last_change_time;
uint32 sec_channel_type;
NET_USER_INFO_3 info3; NET_USER_INFO_3 info3;
struct cli_state *cli = NULL; unsigned char *session_key;
TALLOC_CTX *mem_ctx = NULL; struct rpc_pipe_client *pipe_cli;
DOM_CRED *credentials;
const char *name_user = NULL; const char *name_user = NULL;
const char *name_domain = NULL; const char *name_domain = NULL;
const char *workstation; 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; DATA_BLOB lm_resp, nt_resp;
if (!state->privileged) { /* This is child-only, so no check for privileged access is needed
char *error_string = NULL; anymore */
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;
}
/* Ensure null termination */ /* Ensure null termination */
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0; 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; 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; name_user = state->request.data.auth_crap.user;
if (*state->request.data.auth_crap.domain) { 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; goto done;
} }
lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_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(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_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? */ /* what domain should we contact? */
@@ -512,26 +642,25 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
goto done; goto done;
} }
if (!(contact_domain = find_our_domain())) { 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;
} }
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 { do {
DOM_CRED clnt_creds;
ZERO_STRUCT(info3); ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds); ZERO_STRUCT(ret_creds);
retry = False; retry = False;
/* Don't shut this down - it belongs to the connection cache code */ result = cm_connect_netlogon(contact_domain, state->mem_ctx,
result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli); &pipe_cli, &session_key,
&credentials);
if (!NT_STATUS_IS_OK(result)) { if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", 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; goto done;
} }
result = cli_netlogon_sam_network_logon(cli, mem_ctx, credentials->timestamp.time = time(NULL);
&ret_creds, memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
name_user, name_domain,
workstation, /* Calculate the new credentials. */
state->request.data.auth_crap.chal, cred_create(session_key, &credentials->challenge,
lm_resp, nt_resp, clnt_creds.timestamp, &(clnt_creds.challenge));
&info3);
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; 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 might not yet have noticed that the DC has killed
our connection. */ our connection. */
if ( cli->fd == -1 ) { if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
retry = True; retry = True;
continue; continue;
} }
/* if we get access denied, a possible cause was that we had and open /* 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 connection to the DC, but someone changed our machine account password
out from underneath us using 'net rpc changetrustpw' */ out from underneath us using 'net rpc changetrustpw' */
if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) { if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
DEBUG(3,("winbindd_pam_auth_crap: sam_logon returned ACCESS_DENIED. Maybe the trust account " DEBUG(3,("winbindd_pam_auth: sam_logon returned "
"password was changed and we didn't know it. Killing connections to domain %s\n", "ACCESS_DENIED. Maybe the trust account "
contact_domain->name)); "password was changed and we didn't know it. "
winbindd_cm_flush(); "Killing connections to domain %s\n",
name_domain));
invalidate_cm_connection(&contact_domain->conn);
retry = True; retry = True;
cli = NULL;
} }
} while ( (attempts < 2) && retry ); } while ( (attempts < 2) && retry );
if (cli != NULL) { if (NT_STATUS_IS_OK(result) &&
/* We might have come out of the loop above with cli == NULL, (!clnt_deal_with_creds(session_key, credentials,
so don't dereference that. */ &ret_creds))) {
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &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)) { 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); 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", 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.user,
state->request.data.auth_crap.require_membership_of_sid)); 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) { 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) { } else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
/* ntlm_auth should return the unix username, per /* ntlm_auth should return the unix username, per
'winbind use default domain' settings and the like */ 'winbind use default domain' settings and the like */
fstring username_out; fstring username_out;
const char *nt_username, *nt_domain; 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 */ /* If the server didn't give us one, just use the one we sent them */
nt_username = name_user; 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 */ /* If the server didn't give us one, just use the one we sent them */
nt_domain = name_domain; nt_domain = name_domain;
} }
@@ -653,9 +797,6 @@ done:
state->response.data.auth.nt_status_string, state->response.data.auth.nt_status_string,
state->response.data.auth.pam_error)); state->response.data.auth.pam_error));
if (mem_ctx)
talloc_destroy(mem_ctx);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; 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; NTSTATUS result;
char *oldpass, *newpass; char *oldpass, *newpass;
fstring domain, user; fstring domain, user;
CLI_POLICY_HND *hnd; POLICY_HND dom_pol;
TALLOC_CTX *mem_ctx;
struct winbindd_domain *contact_domain; struct winbindd_domain *contact_domain;
struct rpc_pipe_client *cli;
DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid, DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
state->request.data.chauthtok.user)); 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 */ /* Setup crap */
if (state == NULL) if (state == NULL)
@@ -701,12 +835,15 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
/* Get sam handle */ /* 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)); DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
goto done; 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: done:
state->response.data.auth.nt_status = NT_STATUS_V(result); 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.nt_status_string,
state->response.data.auth.pam_error)); state->response.data.auth.pam_error));
if (mem_ctx)
talloc_destroy(mem_ctx);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
} }

View File

@@ -57,7 +57,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
enum SID_NAME_USE type; enum SID_NAME_USE type;
uint32 num_names; uint32 num_names;
DOM_SID **sid_mem; DOM_SID *sid_mem;
char **names; char **names;
uint32 *types; 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++) { for (i=0; i<num_names; i++) {
DEBUG(10, ("Adding group member SID %s\n", 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) { if (types[i] != SID_NAME_USER) {
DEBUG(1, ("Hmmm. Member %s of group %s is no 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, static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid, 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; return NT_STATUS_NO_SUCH_USER;
} }
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
uint32 num_sids, DOM_SID **sids, uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **aliases) 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. */ /* Lookup group membership given a rid. */
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names, const DOM_SID *group_sid, uint32 *num_names,
DOM_SID ***sid_mem, char ***names, DOM_SID **sid_mem, char ***names,
uint32 **name_types) uint32 **name_types)
{ {
return NT_STATUS_OK; return NT_STATUS_OK;

View File

@@ -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
};

File diff suppressed because it is too large Load Diff

View File

@@ -28,12 +28,13 @@
/* Convert a string */ /* 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 winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
{ {
enum SID_NAME_USE type;
DOM_SID sid; DOM_SID sid;
fstring name;
fstring dom_name;
/* Ensure null termination */ /* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; 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, DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
state->request.data.sid)); state->request.data.sid));
/* Lookup sid from PDC using lsa_lookup_sids() */
if (!string_to_sid(&sid, state->request.data.sid)) { if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(5, ("%s not a SID\n", state->request.data.sid)); DEBUG(5, ("%s not a SID\n", state->request.data.sid));
return WINBINDD_ERROR; 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)) { static void lookupsid_recv(void *private, BOOL success,
return WINBINDD_ERROR; 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.dom_name, dom_name);
fstrcpy(state->response.data.name.name, name); fstrcpy(state->response.data.name.name, name);
state->response.data.name.type = type; state->response.data.name.type = type;
state->response.result = WINBINDD_OK;
return WINBINDD_OK; request_finished(state);
} }
/** /**
* Look up the SID for a qualified name. * 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 winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
{ {
enum SID_NAME_USE type;
fstring sid_str;
char *name_domain, *name_user; char *name_domain, *name_user;
DOM_SID sid;
struct winbindd_domain *domain;
char *p; char *p;
/* Ensure null termination */ /* 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, DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
name_domain, lp_winbind_separator(), name_user)); name_domain, lp_winbind_separator(), name_user));
if ((domain = find_lookup_domain_from_name(name_domain)) == NULL) { winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
DEBUG(0, ("could not find domain entry for domain %s\n", lookupname_recv, state);
name_domain)); return WINBINDD_PENDING;
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;
} }
/* Lookup name from PDC using lsa_lookup_names() */ sid_to_string(state->response.data.sid.sid, sid);
if (!winbindd_lookup_sid_by_name(domain, name_domain, name_user, &sid, &type)) {
return WINBINDD_ERROR;
}
sid_to_string(sid_str, &sid);
fstrcpy(state->response.data.sid.sid, sid_str);
state->response.data.sid.type = type; 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 /* Convert a sid to a uid. We assume we only have one rid attached to the
sid. */ sid. */
static void sid2uid_recv(void *private, BOOL success, uid_t uid);
enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
{ {
DOM_SID sid; 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, DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.sid)); state->request.data.sid));
if (!string_to_sid(&sid, state->request.data.sid)) { if (idmap_proxyonly()) {
DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid)); DEBUG(8, ("IDMAP proxy only\n"));
return WINBINDD_ERROR; 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), 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; 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;
if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))
return WINBINDD_ERROR;
} }
result = idmap_sid_to_uid(&sid, &(state->response.data.uid), 0);
if (NT_STATUS_IS_OK(result)) winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
return WINBINDD_OK; return WINBINDD_PENDING;
}
DEBUG(4, ("Could not get uid for sid %s\n", state->request.data.sid)); static void sid2uid_recv(void *private, BOOL success, uid_t uid)
return WINBINDD_ERROR; {
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;
}
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 /* Convert a sid to a gid. We assume we only have one rid attached to the
sid.*/ sid.*/
static void sid2gid_recv(void *private, BOOL success, gid_t gid);
enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
{ {
DOM_SID sid; DOM_SID sid;
@@ -234,253 +212,301 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
/* Ensure null termination */ /* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; 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)); state->request.data.sid));
if (!string_to_sid(&sid, state->request.data.sid)) { if (idmap_proxyonly()) {
DEBUG(1, ("Could not cvt string to sid %s\n", state->request.data.sid)); DEBUG(8, ("IDMAP proxy only\n"));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* This gets a little tricky. If we assume that usernames are syncd between if (!string_to_sid(&sid, state->request.data.sid)) {
/etc/passwd and the windows domain (such as a member of a Samba domain), DEBUG(1, ("Could not get convert sid %s from string\n",
the we need to get the uid from the OS and not alocate one ourselves */ state->request.data.sid));
return WINBINDD_ERROR;
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;
}
} }
/* 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), 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; return WINBINDD_OK;
if (state->request.flags & WBFLAG_QUERY_ONLY)
return WINBINDD_ERROR;
/* 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;
} }
result = idmap_sid_to_gid(&sid, &(state->response.data.gid), 0);
if (NT_STATUS_IS_OK(result)) winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
return WINBINDD_OK; return WINBINDD_PENDING;
}
DEBUG(4, ("Could not get gid for sid %s\n", state->request.data.sid)); static void sid2gid_recv(void *private, BOOL success, gid_t gid)
return WINBINDD_ERROR; {
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;
}
state->response.result = WINBINDD_OK;
state->response.data.gid = gid;
request_finished(state);
} }
/* Convert a uid to a sid */ /* 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) enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
{ {
DOM_SID sid; DOM_SID sid;
NTSTATUS status;
struct uid2sid_state *uid2sid_state;
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid)); (unsigned long)state->request.data.uid));
if ( (state->request.data.uid < server_state.uid_low ) if (idmap_proxyonly()) {
|| (state->request.data.uid > server_state.uid_high) ) DEBUG(8, ("IDMAP proxy only\n"));
{
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;
}
/* 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));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
done: status = idmap_uid_to_sid(&sid, state->request.data.uid,
sid_to_string(state->response.data.sid.sid, &sid); ID_QUERY_ONLY | ID_CACHE_ONLY);
state->response.data.sid.type = SID_NAME_USER;
return WINBINDD_OK; 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;
}
/* The only chance that this is correct is that winbind trusted
* domains only = yes, and the user exists in nss and the domain. */
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 */ /* 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) enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
{ {
DOM_SID sid; 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)); (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 (idmap_proxyonly()) {
DEBUG(8, ("IDMAP proxy only\n"));
/* 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;
}
/* 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));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
done: status = idmap_gid_to_sid(&sid, state->request.data.gid,
/* Construct sid and return it */ ID_QUERY_ONLY | ID_CACHE_ONLY);
sid_to_string(state->response.data.sid.sid, &sid);
state->response.data.sid.type = SID_NAME_DOM_GRP;
return WINBINDD_OK; 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;
}
/* The only chance that this is correct is that winbind trusted
* domains only = yes, and the user exists in nss and the domain. */
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) 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; 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 /* 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 * reason to keep RID allocation for users to even and groups to
* odd. This needs discussion I think. For now only allocate user * 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; 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;
}

View File

@@ -106,100 +106,274 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
return True; return True;
} }
/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID sid;
WINBIND_USERINFO user_info;
NTSTATUS status;
/* 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));
if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(5, ("%s not a SID\n", state->request.data.sid));
return WINBINDD_ERROR;
}
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;
}
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;
}
return WINBINDD_OK;
}
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;
}
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;
}
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);
}
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;
}
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);
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)
{
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;
}
s->uid = uid;
winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
getpwsid_sid2gid_recv, s);
}
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;
s->state->response.result = 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. */
/* The substitution of %U and %D in the 'template homedir' is done
by alloc_sub_specified() below. */
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);
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);
}
/* Return a password structure from a username. */ /* Return a password structure from a username. */
enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) 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)
{ {
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; struct winbindd_domain *domain;
TALLOC_CTX *mem_ctx; fstring domname, username;
/* Ensure null termination */ /* 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]: getpwnam %s\n", (unsigned long)state->pid, DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
state->request.data.username)); state->request.data.username));
/* Parse domain and username */
parse_domain_user(state->request.data.username, if (!parse_domain_user(state->request.data.username, domname,
name_domain, name_user); username)) {
DEBUG(0, ("Could not parse domain user: %s\n",
/* should we deal with users for our domain? */ state->request.data.username));
if ((domain = find_domain_from_name(name_domain)) == NULL) {
DEBUG(5, ("no such domain: %s\n", name_domain));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* Get info for the domain */
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;
}
if ( domain->primary && lp_winbind_trusted_domains_only()) { if ( domain->primary && lp_winbind_trusted_domains_only()) {
DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n", DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
name_domain, name_user)); "getgroups() for %s\\%s.\n", domname, username));
return WINBINDD_ERROR; 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)) { /* Get rid and name type from name. The following costs 1 packet */
DEBUG(1, ("user '%s' does not exist\n", name_user));
return WINBINDD_ERROR; 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 (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) { if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, DEBUG(5, ("%s is not a user\n", state->request.data.username));
name_type)); state->response.result = WINBINDD_ERROR;
return WINBINDD_ERROR; request_finished(state);
} return;
/* Get some user info. */
if (!(mem_ctx = talloc_init("winbindd_getpwnam([%s]\\[%s])",
name_domain, name_user))) {
DEBUG(1, ("out of memory\n"));
return WINBINDD_ERROR;
} }
status = domain->methods->query_user(domain, mem_ctx, &user_sid, winbindd_getpwsid(state, sid);
&user_info); }
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;
}
/* 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;
}
talloc_destroy(mem_ctx);
return WINBINDD_OK;
}
/* Return a password structure given a uid number */ /* Return a password structure given a uid number */
enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
{ {
DOM_SID user_sid; 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; NTSTATUS status;
gid_t gid;
/* Bug out if the uid isn't in the winbind range */ /* Bug out if the uid isn't in the winbind range */
@@ -210,70 +384,17 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid, DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid)); (unsigned long)state->request.data.uid));
/* Get rid from uid */ status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
ID_QUERY_ONLY | ID_CACHE_ONLY);
if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&user_sid, state->request.data.uid))) { if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("could not convert uid %lu to SID\n", DEBUG(5, ("Could not find SID for uid %lu\n",
(unsigned long)state->request.data.uid)); (unsigned long)state->request.data.uid));
return WINBINDD_ERROR; return WINBINDD_ERROR;
} }
/* Get name and name type from rid */
if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) { winbindd_getpwsid(state, &user_sid);
fstring temp; return WINBINDD_PENDING;
sid_to_string(temp, &user_sid);
DEBUG(1, ("could not lookup sid %s\n", temp));
return WINBINDD_ERROR;
}
domain = find_domain_from_sid(&user_sid);
if (!domain) {
DEBUG(1,("Can't find domain from sid\n"));
return WINBINDD_ERROR;
}
/* Get some user info */
if (!(mem_ctx = talloc_init("winbind_getpwuid(%lu)",
(unsigned long)state->request.data.uid))) {
DEBUG(1, ("out of memory\n"));
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);
return WINBINDD_ERROR;
}
/* Check group has a gid number */
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);
return WINBINDD_ERROR;
}
/* Fill in password structure */
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);
return WINBINDD_ERROR;
}
talloc_destroy(mem_ctx);
return WINBINDD_OK;
} }
/* /*
@@ -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 field is incremented to the index of the next user to fetch. Return True if
some users were returned, False otherwise. */ 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; NTSTATUS status;
uint32 num_entries; uint32 num_entries;
WINBIND_USERINFO *info; WINBIND_USERINFO *info;
struct getpwent_user *name_list = NULL; struct getpwent_user *name_list = NULL;
BOOL result = False; BOOL result = False;
TALLOC_CTX *mem_ctx;
struct winbindd_domain *domain; struct winbindd_domain *domain;
struct winbindd_methods *methods; struct winbindd_methods *methods;
unsigned int i; unsigned int i;
@@ -380,10 +500,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
if (ent->num_sam_entries) if (ent->num_sam_entries)
return False; 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))) { if (!(domain = find_domain_from_name(ent->domain_name))) {
DEBUG(3, ("no such domain %s in get_sam_user_entries\n", DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
ent->domain_name)); ent->domain_name));
@@ -433,8 +549,10 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
} }
/* User and group ids */ /* 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].user_sid,
sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_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; ent->num_sam_entries += num_entries;
@@ -447,8 +565,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
done: done:
talloc_destroy(mem_ctx);
return result; 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) { 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; struct getent_state *next_ent;
/* Free state information for this domain */ /* 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; uint32 num_entries = 0, total_entries = 0;
char *ted, *extra_data = NULL; char *ted, *extra_data = NULL;
int extra_data_len = 0; int extra_data_len = 0;
TALLOC_CTX *mem_ctx;
enum winbindd_result rv = WINBINDD_ERROR; enum winbindd_result rv = WINBINDD_ERROR;
DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid)); DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
if (!(mem_ctx = talloc_init("winbindd_list_users")))
return WINBINDD_ERROR;
/* Ensure null termination */ /* Ensure null termination */
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0'; state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
which_domain = state->request.domain_name; 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) ) if ( *which_domain && !strequal(which_domain, domain->name) )
continue; continue;
if ( !domain->initialized )
set_dc_type_and_flags( domain );
methods = domain->methods; methods = domain->methods;
/* Query display info */ /* Query display info */
status = methods->query_user_list(domain, mem_ctx, status = methods->query_user_list(domain, state->mem_ctx,
&num_entries, &info); &num_entries, &info);
if (num_entries == 0) if (num_entries == 0)
@@ -646,7 +756,5 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
done: done:
talloc_destroy(mem_ctx);
return rv; return rv;
} }

View File

@@ -24,9 +24,6 @@
#include "includes.h" #include "includes.h"
#include "winbindd.h" #include "winbindd.h"
extern struct winbindd_methods cache_methods;
extern struct winbindd_methods passdb_methods;
#undef DBGC_CLASS #undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND #define DBGC_CLASS DBGC_WINBIND
@@ -65,8 +62,7 @@ struct winbindd_domain *domain_list(void)
/* Initialise list */ /* Initialise list */
if (!_domain_list) if (!_domain_list)
if (!init_domain_list()) init_domain_list();
return NULL;
return _domain_list; return _domain_list;
} }
@@ -91,12 +87,7 @@ static BOOL is_internal_domain(const DOM_SID *sid)
if (sid == NULL) if (sid == NULL)
return False; return False;
if ( sid_compare_domain( sid, get_global_sam_sid() ) == 0 ) return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
return True;
if ( sid_compare_domain( sid, &global_sid_Builtin ) == 0 )
return True;
return False;
} }
@@ -181,80 +172,115 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
rescan our domains looking for new trusted domains 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 ) static void add_trusted_domains( struct winbindd_domain *domain )
{ {
TALLOC_CTX *mem_ctx; TALLOC_CTX *mem_ctx;
NTSTATUS result; struct winbindd_request *request;
time_t t; struct winbindd_response *response;
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 */ struct trustdom_state *state;
if (!lp_allow_trusted_domains()) {
mem_ctx = talloc_init("add_trusted_domains");
if (mem_ctx == NULL) {
DEBUG(0, ("talloc_init failed\n"));
return; 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; return;
}
ZERO_STRUCTP(&null_sid);
t = time(NULL); state->mem_ctx = mem_ctx;
state->response = response;
/* 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) ) {
/* Add each domain to the trusted domain list */ request->length = sizeof(*request);
request->cmd = WINBINDD_LIST_TRUSTDOM;
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, async_domain_request(mem_ctx, domain, request, response,
mem_ctx, trustdom_recv, state);
new_domain->name, }
NULL,
&new_domain->sid, static void trustdom_recv(void *private, BOOL success)
&type); {
extern struct winbindd_methods cache_methods;
if ( NT_STATUS_IS_OK(result) ) struct trustdom_state *state =
sid_copy( &dom_sids[i], &new_domain->sid ); talloc_get_type_abort(private, struct trustdom_state);
} struct winbindd_response *response = state->response;
char *p;
/* store trusted domain in the cache */
trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL, if ((!success) || (response->result != WINBINDD_OK)) {
&dom_sids[i], t + WINBINDD_RESCAN_FREQ); 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;
/* 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 ) void rescan_trusted_domains( void )
{ {
time_t now = time(NULL); time_t now = time(NULL);
struct winbindd_domain *mydomain = NULL;
/* see if the time has come... */ /* 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; 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 */ /* 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; last_trustdom_scan = now;
return; return;
} }
/* Look up global info for the winbind daemon */ struct init_child_state {
BOOL init_domain_list(void) 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 */
void init_domain_list(void)
{
extern struct winbindd_methods cache_methods;
extern struct winbindd_methods passdb_methods;
struct winbindd_domain *domain; struct winbindd_domain *domain;
/* Free existing list */ /* Free existing list */
@@ -297,50 +497,35 @@ BOOL init_domain_list(void)
if (IS_DC) { if (IS_DC) {
domain = add_trusted_domain(get_global_sam_name(), NULL, domain = add_trusted_domain(get_global_sam_name(), NULL,
&passdb_methods, get_global_sam_sid()); &passdb_methods,
get_global_sam_sid());
} else { } else {
DOM_SID our_sid;
if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
DEBUG(0, ("Could not fetch our SID - did we join?\n"));
}
domain = add_trusted_domain( lp_workgroup(), lp_realm(), domain = add_trusted_domain( lp_workgroup(), lp_realm(),
&cache_methods, NULL); &cache_methods, &our_sid);
/* set flags about native_mode, active_directory */
set_dc_type_and_flags(domain);
} }
domain->primary = True; domain->primary = True;
setup_domain_child(domain, &domain->child, NULL);
/* get any alternate name for the primary domain */
cache_methods.alternate_name(domain);
/* now we have the correct netbios (short) domain name */
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;
}
/* do an initial scan for trusted domains */
add_trusted_domains(domain);
/* Add our local SAM domains */ /* Add our local SAM domains */
add_trusted_domain("BUILTIN", NULL, &passdb_methods, domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
&global_sid_Builtin); &global_sid_Builtin);
setup_domain_child(domain, &domain->child, NULL);
if (!IS_DC) { if (!IS_DC) {
add_trusted_domain(get_global_sam_name(), NULL, domain = add_trusted_domain(get_global_sam_name(), NULL,
&passdb_methods, get_global_sam_sid()); &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. * @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; 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) { for (domain = domain_list(); domain != NULL; domain = domain->next) {
if (strequal(domain_name, domain->name) || if (strequal(domain_name, domain->name) ||
(domain->alt_name[0] && strequal(domain_name, domain->alt_name))) { (domain->alt_name[0] &&
if (!domain->initialized) strequal(domain_name, domain->alt_name))) {
set_dc_type_and_flags(domain);
return domain; return domain;
} }
} }
@@ -376,29 +559,56 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
return NULL; 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_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)
return domain;
}
/* Not found */
return NULL;
}
/* Given a domain sid, return the struct winbindd domain info for it */ /* 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(const DOM_SID *sid)
{ {
struct winbindd_domain *domain; struct winbindd_domain *domain;
/* Search through list */ domain = find_domain_from_sid_noinit(sid);
for (domain = domain_list(); domain != NULL; domain = domain->next) { if (domain == NULL)
if (sid_compare_domain(sid, &domain->sid) == 0) { return NULL;
if (!domain->initialized)
set_dc_type_and_flags(domain);
return domain;
}
}
/* Not found */ if (!domain->initialized)
set_dc_type_and_flags(domain);
return NULL; return domain;
} }
/* Given a domain sid, return the struct winbindd domain info for it */
struct winbindd_domain *find_our_domain(void) struct winbindd_domain *find_our_domain(void)
{ {
struct winbindd_domain *domain; struct winbindd_domain *domain;
@@ -410,11 +620,24 @@ struct winbindd_domain *find_our_domain(void)
return domain; return domain;
} }
/* Not found */ smb_panic("Could not find our domain\n");
return NULL; 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 */ /* Find the appropriate domain to lookup a name or SID */
struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *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") || if (IS_DC || strequal(domain_name, "BUILTIN") ||
strequal(domain_name, get_global_sam_name())) 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(); return find_our_domain();
} }
/* Lookup a sid in a domain from a name */ /* 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 *domain_name,
const char *name, DOM_SID *sid, const char *name, DOM_SID *sid,
enum SID_NAME_USE *type) enum SID_NAME_USE *type)
{ {
NTSTATUS result; 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 */ /* Lookup name */
result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type); 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 */ /* Return rid and type if lookup successful */
if (!NT_STATUS_IS_OK(result)) { if (!NT_STATUS_IS_OK(result)) {
*type = SID_NAME_UNKNOWN; *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 * @retval True if the name exists, in which case @p name and @p type
* are set, otherwise False. * 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 dom_name,
fstring name, fstring name,
enum SID_NAME_USE *type) enum SID_NAME_USE *type)
@@ -488,7 +705,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
char *names; char *names;
char *dom_names; char *dom_names;
NTSTATUS result; NTSTATUS result;
TALLOC_CTX *mem_ctx;
BOOL rv = False; BOOL rv = False;
struct winbindd_domain *domain; struct winbindd_domain *domain;
@@ -501,9 +717,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
/* Lookup name */ /* 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); result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
/* Return name and type if successful */ /* Return name and type if successful */
@@ -516,12 +729,9 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
fstrcpy(name, name_deadbeef); fstrcpy(name, name_deadbeef);
} }
talloc_destroy(mem_ctx);
return rv; return rv;
} }
/* Free state information held for {set,get,end}{pw,gr}ent() functions */ /* Free state information held for {set,get,end}{pw,gr}ent() functions */
void free_getent_state(struct getent_state *state) void free_getent_state(struct getent_state *state)
@@ -553,31 +763,30 @@ BOOL winbindd_param_init(void)
/* Parse winbind uid and winbind_gid parameters */ /* Parse winbind uid and winbind_gid parameters */
if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) { 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; return False;
} }
if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) { 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 False;
} }
return True; return True;
} }
/* Check if a domain is present in a comma-separated list of domains */ BOOL is_in_uid_range(uid_t uid)
BOOL check_domain_env(char *domain_env, char *domain)
{ {
fstring name; return ((uid >= server_state.uid_low) &&
const char *tmp = domain_env; (uid <= server_state.uid_high));
}
while(next_token(&tmp, name, ",", sizeof(fstring))) { BOOL is_in_gid_range(gid_t gid)
if (strequal(name, domain)) {
return True; return ((gid >= server_state.gid_low) &&
} (gid <= server_state.gid_high));
return False;
} }
/* Is this a domain which we may assume no DOMAIN\ prefix? */ /* 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; 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 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
'winbind separator' options. '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) 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)) { if (assume_domain(domain)) {
strlcpy(name, user, sizeof(fstring)); strlcpy(name, user, sizeof(fstring));
} else { } else {
slprintf(name, sizeof(fstring) - 1, "%s%c%s", slprintf(name, sizeof(fstring) - 1, "%s%c%s",
domain, *lp_winbind_separator(), domain, *lp_winbind_separator(),
user); tmp_user);
} }
} }
@@ -764,22 +985,6 @@ int winbindd_num_clients(void)
return _num_clients; 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 For idmap conversion: convert one record to new format
Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid 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); 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 */
}

View File

@@ -225,6 +225,7 @@ typedef struct
int min_passwd_length; int min_passwd_length;
int oplock_break_wait_time; int oplock_break_wait_time;
int winbind_cache_time; int winbind_cache_time;
int winbind_max_idle_children;
int iLockSpinCount; int iLockSpinCount;
int iLockSpinTime; int iLockSpinTime;
char *szLdapMachineSuffix; 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 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 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 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} {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
}; };
@@ -1567,6 +1569,7 @@ static void init_globals(void)
Globals.bWinbindUseDefaultDomain = False; Globals.bWinbindUseDefaultDomain = False;
Globals.bWinbindTrustedDomainsOnly = False; Globals.bWinbindTrustedDomainsOnly = False;
Globals.bWinbindNestedGroups = False; Globals.bWinbindNestedGroups = False;
Globals.winbind_max_idle_children = 3;
Globals.bEnableRidAlgorithm = True; 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_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size);
FN_LOCAL_CHAR(lp_magicchar, magic_char) FN_LOCAL_CHAR(lp_magicchar, magic_char)
FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time) 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_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout) FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing) FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)

View File

@@ -112,6 +112,44 @@ BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAM
return True; 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 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) { if (sid_compare(&pc->sid, psid) == 0) {
fstring sid; fstring sid;
*pgid = pc->gid; *pgid = pc->gid;
DEBUG(3,("fetch uid from cache %u -> %s\n", DEBUG(3,("fetch gid from cache %u -> %s\n",
(unsigned int)*pgid, sid_to_string(sid, psid))); (unsigned int)*pgid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc); DLIST_PROMOTE(gid_sid_cache_head, pc);
return True; return True;
} }

View 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 ) 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 ) static BOOL printing_store_value( char *key, REGVAL_CTR *val )
{ {
return False; return True;
} }
/* /*

View File

@@ -26,8 +26,9 @@
Get information about the server and directory services Get information about the server and directory services
********************************************************************/ ********************************************************************/
NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_ds_getprimarydominfo(struct rpc_pipe_client *cli,
uint16 level, DS_DOMINFO_CTR *ctr) TALLOC_CTX *mem_ctx,
uint16 level, DS_DOMINFO_CTR *ctr)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
DS_Q_GETPRIMDOMINFO q; DS_Q_GETPRIMDOMINFO q;
@@ -50,7 +51,7 @@ NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
q.level = level; q.level = level;
if (!ds_io_q_getprimdominfo("", &qbuf, 0, &q) 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -81,13 +82,23 @@ done:
return result; 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 Enumerate trusted domains in an AD forest
********************************************************************/ ********************************************************************/
NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_ds_enum_domain_trusts(struct rpc_pipe_client *cli,
const char *server, uint32 flags, TALLOC_CTX *mem_ctx,
struct ds_domain_trust **trusts, uint32 *num_domains) const char *server, uint32 flags,
struct ds_domain_trust **trusts,
uint32 *num_domains)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
DS_Q_ENUM_DOM_TRUSTS q; 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 ); init_q_ds_enum_domain_trusts( &q, server, flags );
if (!ds_io_q_enum_domain_trusts("", &qbuf, 0, &q) 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -163,3 +174,13 @@ done:
return result; 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);
}

View File

@@ -43,8 +43,10 @@
* *
* @param cli Handle on an initialised SMB connection */ * @param cli Handle on an initialised SMB connection */
NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
BOOL sec_qos, uint32 des_access, POLICY_HND *pol) TALLOC_CTX *mem_ctx,
BOOL sec_qos, uint32 des_access,
POLICY_HND *pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_OPEN_POL q; 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; LSA_SEC_QOS qos;
NTSTATUS result; NTSTATUS result;
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
ZERO_STRUCT(q); ZERO_STRUCT(q);
ZERO_STRUCT(r); 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 */ /* Marshall data and send request */
if (!lsa_io_q_open_pol("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -100,13 +104,21 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 /** Open a LSA policy handle
* *
* @param cli Handle on an initialised SMB connection * @param cli Handle on an initialised SMB connection
*/ */
NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
BOOL sec_qos, uint32 des_access, POLICY_HND *pol) TALLOC_CTX *mem_ctx, BOOL sec_qos,
uint32 des_access, POLICY_HND *pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_OPEN_POL2 q; 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) { if (sec_qos) {
init_lsa_sec_qos(&qos, 2, 1, 0); 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); &qos);
} else { } 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); NULL);
} }
/* Marshall data and send request */ /* Marshall data and send request */
if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -164,16 +176,26 @@ NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /** Close a LSA policy handle */
NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol) POLICY_HND *pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_CLOSE q; LSA_Q_CLOSE q;
LSA_R_CLOSE r; LSA_R_CLOSE r;
NTSTATUS result; NTSTATUS result;
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
ZERO_STRUCT(q); ZERO_STRUCT(q);
ZERO_STRUCT(r); 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); init_lsa_q_close(&q, pol);
if (!lsa_io_q_close("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -215,11 +237,19 @@ NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /** Lookup a list of sids */
NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
POLICY_HND *pol, int num_sids, const DOM_SID *sids, TALLOC_CTX *mem_ctx,
char ***domains, char ***names, uint32 **types) POLICY_HND *pol, int num_sids,
const DOM_SID *sids,
char ***domains, char ***names, uint32 **types)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_LOOKUP_SIDS q; 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); init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -332,12 +362,23 @@ NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /** Lookup a list of names */
NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
POLICY_HND *pol, int num_names, TALLOC_CTX *mem_ctx,
const char **names, DOM_SID **sids, POLICY_HND *pol, int num_names,
uint32 **types) const char **names, DOM_SID **sids,
uint32 **types)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_LOOKUP_NAMES q; 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); init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -433,19 +474,31 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 /** Query info policy
* *
* @param domain_sid - returned remote server's domain sid */ * @param domain_sid - returned remote server's domain sid */
NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_query_info_policy(struct rpc_pipe_client *cli,
POLICY_HND *pol, uint16 info_class, TALLOC_CTX *mem_ctx,
char **domain_name, DOM_SID **domain_sid) POLICY_HND *pol, uint16 info_class,
char **domain_name, DOM_SID **domain_sid)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_QUERY_INFO q; LSA_Q_QUERY_INFO q;
LSA_R_QUERY_INFO r; LSA_R_QUERY_INFO r;
NTSTATUS result; NTSTATUS result;
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
ZERO_STRUCT(q); ZERO_STRUCT(q);
ZERO_STRUCT(r); 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); init_q_query(&q, pol, info_class);
if (!lsa_io_q_query("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -523,6 +576,15 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 /** Query info policy2
* *
* @param domain_name - returned remote server's domain name * @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_guid - returned remote server's domain guid
* @param domain_sid - returned remote server's domain sid */ * @param domain_sid - returned remote server's domain sid */
NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_query_info_policy2(struct rpc_pipe_client *cli,
POLICY_HND *pol, uint16 info_class, TALLOC_CTX *mem_ctx,
char **domain_name, char **dns_name, POLICY_HND *pol, uint16 info_class,
char **forest_name, struct uuid **domain_guid, char **domain_name, char **dns_name,
DOM_SID **domain_sid) char **forest_name,
struct uuid **domain_guid,
DOM_SID **domain_sid)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_QUERY_INFO2 q; 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); init_q_query2(&q, pol, info_class);
if (!lsa_io_q_query_info2("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -616,6 +680,19 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 * 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 * @return nt status code of response
**/ **/
NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_lsa_enum_trust_dom(struct rpc_pipe_client *cli,
POLICY_HND *pol, uint32 *enum_ctx, TALLOC_CTX *mem_ctx,
uint32 *num_domains, POLICY_HND *pol, uint32 *enum_ctx,
char ***domain_names, DOM_SID **domain_sids) uint32 *num_domains,
char ***domain_names, DOM_SID **domain_sids)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
LSA_Q_ENUM_TRUST_DOM in; 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); 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, in, out,
qbuf, rbuf, qbuf, rbuf,
lsa_io_q_enum_trust_dom, 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; 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*/ /** Enumerate privileges*/

View File

@@ -75,6 +75,55 @@ NTSTATUS cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
return result; 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 LSA Authenticate 2
@@ -158,6 +207,61 @@ password ?).\n", cli->desthost ));
return result; 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 LSA Authenticate 3
@@ -340,8 +444,9 @@ NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* GetDCName */ /* GetDCName */
NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_netlogon_getdcname(struct rpc_pipe_client *cli,
const char *domainname, fstring dcname) TALLOC_CTX *mem_ctx, const char *mydcname,
const char *domainname, fstring newdcname)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
NET_Q_GETDCNAME q; NET_Q_GETDCNAME q;
@@ -358,12 +463,12 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Initialise input parameters */ /* 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 */ /* Marshall data and send request */
if (!net_io_q_getdcname("", &q, &qbuf, 0) || 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; result = NT_STATUS_UNSUCCESSFUL;
goto done; goto done;
} }
@@ -378,7 +483,7 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
result = r.status; result = r.status;
if (NT_STATUS_IS_OK(result)) if (NT_STATUS_IS_OK(result))
rpcstr_pull_unistr2_fstring(dcname, &r.uni_dcname); rpcstr_pull_unistr2_fstring(newdcname, &r.uni_dcname);
done: done:
prs_mem_free(&qbuf); prs_mem_free(&qbuf);
@@ -387,6 +492,14 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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. 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. * @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, NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
DOM_CRED *ret_creds, TALLOC_CTX *mem_ctx,
const char *username, const char *domain, const char *workstation, const char *server_name_slash,
const uint8 chal[8], DOM_CRED *clnt_creds,
DATA_BLOB lm_response, DATA_BLOB nt_response, DOM_CRED *ret_creds,
NET_USER_INFO_3 *info3) 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; prs_struct qbuf, rbuf;
NET_Q_SAM_LOGON q; NET_Q_SAM_LOGON q;
NET_R_SAM_LOGON r; NET_R_SAM_LOGON r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
DOM_CRED clnt_creds, dummy_rtn_creds; DOM_CRED dummy_rtn_creds;
NET_ID_INFO_CTR ctr; NET_ID_INFO_CTR ctr;
int validation_level = 3; int validation_level = 3;
char *workstation_name_slash; 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); ZERO_STRUCT(dummy_rtn_creds);
workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
if (!workstation_name_slash) { if (!workstation_name_slash) {
DEBUG(0, ("talloc_asprintf failed!\n")); DEBUG(0, ("talloc_asprintf failed!\n"));
return NT_STATUS_NO_MEMORY; 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 */ /* Initialise input parameters */
gen_next_creds(cli, &clnt_creds);
q.validation_level = validation_level; q.validation_level = validation_level;
if (ret_creds == NULL) 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, username, workstation_name_slash, (const uchar*)chal,
lm_response.data, lm_response.length, nt_response.data, nt_response.length); lm_response.data, lm_response.length, nt_response.data, nt_response.length);
init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(), init_sam_info(&q.sam_id, server_name_slash, global_myname(),
&clnt_creds, ret_creds, NET_LOGON_TYPE, clnt_creds, ret_creds, NET_LOGON_TYPE,
&ctr); &ctr);
/* Marshall data and send request */ /* Marshall data and send request */
if (!net_io_q_sam_logon("", &q, &qbuf, 0) || 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; 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); 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) { if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16); 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; 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. LSA Server Password Set.
****************************************************************************/ ****************************************************************************/

View 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. 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; size_t size = (size_t)cli->max_recv_frag;
int stream_offset = 0; 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) if (size > (size_t)data_to_read)
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", DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
num_read, stream_offset, data_to_read)); num_read, stream_offset, data_to_read));
if (cli_is_dos_error(cli)) { if (cli_is_dos_error(cli->cli)) {
cli_dos_error(cli, &eclass, &ecode); cli_dos_error(cli->cli, &eclass, &ecode);
if (eclass != ERRDOS && ecode != ERRmoredata) { if (eclass != ERRDOS && ecode != ERRmoredata) {
DEBUG(0,("rpc_read: Error %d/%u in cli_read\n", DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
eclass, (unsigned int)ecode)); eclass, (unsigned int)ecode));
@@ -168,7 +170,7 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
Never on bind requests/responses. 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, uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
int *pauth_padding_len) 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")); DEBUG(10,("rpc_auth_pipe: packet:\n"));
dump_data(100, dp, auth_len); 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. */ /* The endinness must be preserved. JRA. */
prs_set_endian_data( &auth_verf, rdata->bigendian_data); 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) uint8 expected_pkt_type)
{ {
uint32 len; 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. */ /* Create setup parameters - must be in native byte order. */
setup[0] = TRANSACT_DCERPCCMD; 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 /* Send the RPC request and receive a response. For short RPC
calls (about 1024 bytes or so) the RPC request and response calls (about 1024 bytes or so) the RPC request and response
appears in a SMBtrans request and response. Larger RPC appears in a SMBtrans request and response. Larger RPC
responses are received further on. */ responses are received further on. */
if (!cli_api_pipe(cli, "\\PIPE\\", if (!cli_api_pipe(cli->cli, "\\PIPE\\",
setup, 2, 0, /* Setup, length, max */ setup, 2, 0, /* Setup, length, max */
NULL, 0, 0, /* Params, length, max */ NULL, 0, 0, /* Params, length, max */
pdata, data_len, max_data, /* data, length, max */ pdata, data_len, max_data, /* data, length, max */
&rparam, &rparam_len, /* return params, len */ &rparam, &rparam_len, /* return params, len */
&prdata, &rdata_len)) /* return data, 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; return False;
} }
@@ -442,7 +445,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
if (prdata == NULL) { if (prdata == NULL) {
DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n", DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
(int)cli->nt_pipe_fnum[pipe_idx])); (int)cli->fnum));
return False; 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) { 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); prs_mem_free(rdata);
return False; 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) { 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); prs_mem_free(rdata);
return False; 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 */ /* 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); prs_mem_free(rdata);
return False; 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. * 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); 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); num_read = cli_read(cli->cli, cli->fnum, hdr_data, 0,
if (cli_is_dos_error(cli)) { RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
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) { if (eclass != ERRDOS && ecode != ERRmoredata) {
DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode)); DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
return False; 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. * 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); prs_mem_free(rdata);
return False; 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, uint32 rpc_call_id,
RPC_IFACE *abstract, RPC_IFACE *transfer, RPC_IFACE *abstract, RPC_IFACE *transfer,
const char *my_name, const char *domain) 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. 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, uint32 rpc_call_id,
prs_struct *rpc_out) prs_struct *rpc_out)
{ {
@@ -916,8 +923,8 @@ static BOOL create_auth_hdr(prs_struct *outgoing_packet,
* @param rdata Unparsed NDR response data. * @param rdata Unparsed NDR response data.
**/ **/
BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num, BOOL rpc_api_pipe_req_int(struct rpc_pipe_client *cli, uint8 op_num,
prs_struct *data, prs_struct *rdata) prs_struct *data, prs_struct *rdata)
{ {
uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent; uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
NTSTATUS nt_status; 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); send_size = MIN(data_left, max_data);
if (!prs_init(&sec_blob, send_size, /* will need at least this much */ 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", DEBUG(0,("Could not malloc %u bytes",
send_size+auth_padding)); send_size+auth_padding));
return False; 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). * Malloc parse struct to hold it (and enough for alignments).
*/ */
if(!prs_init(&outgoing_packet, data_len + 8, 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 )); DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
return False; 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))); prs_offset(&outgoing_packet)));
if (flags & RPC_FLG_LAST) if (flags & RPC_FLG_LAST)
ret = rpc_api_pipe(cli, pipe_idx, &outgoing_packet, ret = rpc_api_pipe(cli, &outgoing_packet,
rdata, RPC_RESPONSE); rdata, RPC_RESPONSE);
else { else {
cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x0008, cli_write(cli->cli, cli->fnum, 0x0008,
prs_data_p(&outgoing_packet), prs_data_p(&outgoing_packet),
data_sent, data_len); 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 */ /* Also capture received data */
slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s", 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); prs_dump(dump_name, op_num, rdata);
return ret; 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. 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; BOOL state_set = False;
char param[2]; 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; return False;
DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n", 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 */ /* create parameters: device state */
SSVAL(param, 0, device_state); SSVAL(param, 0, device_state);
/* create setup parameters. */ /* create setup parameters. */
setup[0] = 0x0001; 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\ */ /* send the data on \PIPE\ */
if (cli_api_pipe(cli, "\\PIPE\\", if (cli_api_pipe(cli->cli, "\\PIPE\\",
setup, 2, 0, /* setup, length, max */ setup, 2, 0, /* setup, length, max */
param, 2, 0, /* param, length, max */ param, 2, 0, /* param, length, max */
NULL, 0, 1024, /* data, 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. 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; prs_struct rpc_out;
ssize_t ret; ssize_t ret;
prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */ 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, if (!NT_STATUS_IS_OK(create_rpc_bind_resp(cli, rpc_call_id,
&rpc_out))) { &rpc_out))) {
return False; 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)) { 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)); DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
prs_mem_free(&rpc_out); 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. 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 abstract;
RPC_IFACE transfer; 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; uint32 rpc_call_id;
char buffer[MAX_PDU_FRAG_LEN]; 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; 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; 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. * 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); global_myname(), cli->domain);
/* Initialize the incoming data struct. */ /* 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 */ /* 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; RPC_HDR_BA hdr_ba;
DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n")); 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; 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")); DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
prs_mem_free(&rdata); prs_mem_free(&rdata);
return False; 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) 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")); DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
prs_mem_free(&rdata); prs_mem_free(&rdata);
return False; 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) BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
{ {
int fnum; int fnum;
struct rpc_pipe_client *cli_pipe;
/* At the moment we can't have more than one pipe open over SMB_ASSERT(cli->pipes[pipe_idx].fnum == 0);
a cli connection. )-: */
SMB_ASSERT(cli->nt_pipe_fnum[pipe_idx] == 0);
/* The pipe index must fall within our array */ /* 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; return False;
} }
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum; cli->pipes[pipe_idx].fnum = (uint16)fnum;
} else { } else {
if ((fnum = cli_open(cli, pipe_names[pipe_idx].client_pipe, O_CREAT|O_RDWR, DENY_NONE)) == -1) { 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", 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; return False;
} }
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum; cli->pipes[pipe_idx].fnum = (uint16)fnum;
/**************** Set Named Pipe State ***************/ /**************** 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", DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
cli_errstr(cli))); cli_errstr(cli)));
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]); cli_close(cli, cli->pipes[pipe_idx].fnum);
cli->nt_pipe_fnum[pipe_idx] = 0; cli->pipes[pipe_idx].fnum = 0;
return False; 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 *****************/ /******************* 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", DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
get_pipe_name_from_index(pipe_idx))); get_pipe_name_from_index(pipe_idx)));
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]); cli_close(cli, cli->pipes[pipe_idx].fnum);
cli->nt_pipe_fnum[pipe_idx] = 0; cli->pipes[pipe_idx].fnum = 0;
return False; return False;
} }
@@ -1523,7 +1546,6 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
{ {
NTSTATUS result; NTSTATUS result;
uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS; uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
int fnum;
cli_nt_netlogon_netsec_session_close(cli); cli_nt_netlogon_netsec_session_close(cli);
@@ -1554,60 +1576,20 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
} }
cli->netlogon_pipe = cli->pipes[PI_NETLOGON];
ZERO_STRUCT(cli->pipes[PI_NETLOGON]);
/* Server offered schannel, so try it. */ /* Server offered schannel, so try it. */
memcpy(cli->auth_info.sess_key, cli->sess_key, memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->sess_key,
sizeof(cli->auth_info.sess_key)); sizeof(cli->pipes[PI_NETLOGON].auth_info.sess_key));
cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum[PI_NETLOGON];
cli->pipe_auth_flags = AUTH_PIPE_NETSEC; cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
cli->pipe_auth_flags |= AUTH_PIPE_SIGN; cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
cli->pipe_auth_flags |= AUTH_PIPE_SEAL; cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
if (cli->capabilities & CAP_NT_SMBS) { return cli_nt_session_open(cli, PI_NETLOGON) ?
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
/* 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;
} }
@@ -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)) { 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); ZERO_STRUCT(cli->sess_key);
cli->pipe_auth_flags = 0; cli->pipe_auth_flags = 0;
cli_nt_session_close(cli); cli_nt_session_close(cli);
return result; return result;
} }
memcpy(cli->auth_info.sess_key, cli->sess_key, memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->sess_key,
sizeof(cli->auth_info.sess_key)); sizeof(cli->pipes[PI_NETLOGON].auth_info.sess_key));
cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum[PI_NETLOGON];
cli->nt_pipe_fnum[PI_NETLOGON] = 0;
cli_close(cli, cli->pipes[PI_NETLOGON].fnum);
cli->pipes[PI_NETLOGON].fnum = 0;
cli->pipe_idx = -1;
/* doing schannel, not per-user auth */ /* doing schannel, not per-user auth */
cli->pipe_auth_flags = auth_flags; cli->pipe_auth_flags = auth_flags;
@@ -1664,4 +1647,124 @@ const char *cli_pipe_get_name(struct cli_state *cli)
return cli->pipe_name; 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);
}

View File

@@ -27,15 +27,15 @@
/* Connect to SAMR database */ /* Connect to SAMR database */
NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
uint32 access_mask, POLICY_HND *connect_pol) uint32 access_mask, POLICY_HND *connect_pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_CONNECT q; SAMR_Q_CONNECT q;
SAMR_R_CONNECT r; SAMR_R_CONNECT r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL; 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(q);
ZERO_STRUCT(r); ZERO_STRUCT(r);
@@ -47,10 +47,10 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Marshall data and send request */ /* 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) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -74,6 +74,12 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Connect to SAMR database */
NTSTATUS cli_samr_connect4(struct cli_state *cli, TALLOC_CTX *mem_ctx, 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 */ /* Close SAMR handle */
NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *connect_pol) POLICY_HND *connect_pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_CLOSE_HND q; 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); init_samr_q_close_hnd(&q, connect_pol);
if (!samr_io_q_close_hnd("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -172,11 +178,18 @@ NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Open handle on a domain */
NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_open_domain(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *connect_pol, uint32 access_mask, POLICY_HND *connect_pol, uint32 access_mask,
const DOM_SID *domain_sid, POLICY_HND *domain_pol) const DOM_SID *domain_sid,
POLICY_HND *domain_pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_OPEN_DOMAIN q; 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); init_samr_q_open_domain(&q, connect_pol, access_mask, domain_sid);
if (!samr_io_q_open_domain("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -224,9 +237,21 @@ NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Open handle on a user */ /* Open handle on a user */
NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *domain_pol, uint32 access_mask, POLICY_HND *connect_pol, uint32 access_mask,
uint32 user_rid, POLICY_HND *user_pol) 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; prs_struct qbuf, rbuf;
SAMR_Q_OPEN_USER q; 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); init_samr_q_open_user(&q, domain_pol, access_mask, user_rid);
if (!samr_io_q_open_user("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -272,11 +297,21 @@ NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Open handle on a group */
NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_open_group(struct rpc_pipe_client *cli,
POLICY_HND *domain_pol, uint32 access_mask, TALLOC_CTX *mem_ctx,
uint32 group_rid, POLICY_HND *group_pol) POLICY_HND *domain_pol, uint32 access_mask,
uint32 group_rid, POLICY_HND *group_pol)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_OPEN_GROUP q; 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); init_samr_q_open_group(&q, domain_pol, access_mask, group_rid);
if (!samr_io_q_open_group("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -322,6 +357,15 @@ NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Create domain group */
NTSTATUS cli_samr_create_dom_group(struct cli_state *cli, TALLOC_CTX *mem_ctx, 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 */ /* Query user info */
NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_userinfo(struct rpc_pipe_client *cli,
POLICY_HND *user_pol, uint16 switch_value, TALLOC_CTX *mem_ctx,
SAM_USERINFO_CTR **ctr) POLICY_HND *user_pol, uint16 switch_value,
SAM_USERINFO_CTR **ctr)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_USERINFO q; 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); init_samr_q_query_userinfo(&q, user_pol, switch_value);
if (!samr_io_q_query_userinfo("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -505,6 +550,14 @@ NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Set group info */
NTSTATUS cli_samr_set_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 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 */ /* Query user groups */
NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_usergroups(struct rpc_pipe_client *cli,
POLICY_HND *user_pol, uint32 *num_groups, TALLOC_CTX *mem_ctx,
DOM_GID **gid) POLICY_HND *user_pol,
uint32 *num_groups,
DOM_GID **gid)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_USERGROUPS q; 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); init_samr_q_query_usergroups(&q, user_pol);
if (!samr_io_q_query_usergroups("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -644,6 +699,14 @@ NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Set alias info */
NTSTATUS cli_samr_set_aliasinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 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 */ /* Query user aliases */
NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_useraliases(struct rpc_pipe_client *cli,
POLICY_HND *dom_pol, uint32 num_sids, DOM_SID2 *sid, TALLOC_CTX *mem_ctx,
uint32 *num_aliases, uint32 **als_rids) POLICY_HND *dom_pol, uint32 num_sids,
DOM_SID2 *sid,
uint32 *num_aliases, uint32 **als_rids)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_USERALIASES q; 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); init_samr_q_query_useraliases(&q, dom_pol, num_sids, sid_ptrs, sid);
if (!samr_io_q_query_useraliases("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -745,11 +810,24 @@ NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Query user groups */
NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_groupmem(struct rpc_pipe_client *cli,
POLICY_HND *group_pol, uint32 *num_mem, TALLOC_CTX *mem_ctx,
uint32 **rid, uint32 **attr) POLICY_HND *group_pol, uint32 *num_mem,
uint32 **rid, uint32 **attr)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_GROUPMEM q; 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); init_samr_q_query_groupmem(&q, group_pol);
if (!samr_io_q_query_groupmem("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -794,6 +872,15 @@ NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 * Enumerate domain users
* *
@@ -892,10 +979,11 @@ done:
/* Enumerate domain groups */ /* Enumerate domain groups */
NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_enum_dom_groups(struct rpc_pipe_client *cli,
POLICY_HND *pol, uint32 *start_idx, TALLOC_CTX *mem_ctx,
uint32 size, struct acct_info **dom_groups, POLICY_HND *pol, uint32 *start_idx,
uint32 *num_dom_groups) uint32 size, struct acct_info **dom_groups,
uint32 *num_dom_groups)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_ENUM_DOM_GROUPS q; 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); init_samr_q_enum_dom_groups(&q, pol, *start_idx, size);
if (!samr_io_q_enum_dom_groups("", &q, &qbuf, 0) || 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; goto done;
/* Unmarshall response */ /* Unmarshall response */
@@ -969,12 +1057,23 @@ NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Enumerate domain groups */
NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_enum_als_groups(struct rpc_pipe_client *cli,
POLICY_HND *pol, uint32 *start_idx, TALLOC_CTX *mem_ctx,
uint32 size, struct acct_info **dom_aliases, POLICY_HND *pol, uint32 *start_idx,
uint32 *num_dom_aliases) uint32 size, struct acct_info **dom_aliases,
uint32 *num_dom_aliases)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_ENUM_DOM_ALIASES q; 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); init_samr_q_enum_dom_aliases(&q, pol, *start_idx, size);
if (!samr_io_q_enum_dom_aliases("", &q, &qbuf, 0) || 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; goto done;
} }
@@ -1051,6 +1150,16 @@ NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Query alias members */
NTSTATUS cli_samr_query_aliasmem(struct cli_state *cli, TALLOC_CTX *mem_ctx, 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; SAMR_R_QUERY_ALIASINFO r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL; 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(q);
ZERO_STRUCT(r); ZERO_STRUCT(r);
@@ -1368,9 +1477,11 @@ NTSTATUS cli_samr_query_alias_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Query domain info */ /* Query domain info */
NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_dom_info(struct rpc_pipe_client *cli,
POLICY_HND *domain_pol, uint16 switch_value, TALLOC_CTX *mem_ctx,
SAM_UNK_CTR *ctr) POLICY_HND *domain_pol,
uint16 switch_value,
SAM_UNK_CTR *ctr)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_DOMAIN_INFO q; 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); init_samr_q_query_dom_info(&q, domain_pol, switch_value);
if (!samr_io_q_query_dom_info("", &q, &qbuf, 0) || 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; goto done;
} }
@@ -1417,12 +1528,21 @@ NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* User change password */
NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
const char *username, TALLOC_CTX *mem_ctx,
const char *newpassword, const char *username,
const char *oldpassword ) const char *newpassword,
const char *oldpassword )
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_CHGPASSWD_USER q; 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 */ /* 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, new_nt_password,
old_nt_hash_enc, old_nt_hash_enc,
new_lm_password, new_lm_password,
old_lanman_hash_enc); old_lanman_hash_enc);
if (!samr_io_q_chgpasswd_user("", &q, &qbuf, 0) || 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; goto done;
} }
@@ -1507,6 +1627,15 @@ NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 /* This function returns the bizzare set of (max_entries, max_size) required
for the QueryDisplayInfo RPC to actually work against a domain controller for the QueryDisplayInfo RPC to actually work against a domain controller
with large (10k and higher) numbers of users. These values were 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 */ /* Query display info */
NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_query_dispinfo(struct rpc_pipe_client *cli,
POLICY_HND *domain_pol, uint32 *start_idx, TALLOC_CTX *mem_ctx,
uint16 switch_value, uint32 *num_entries, POLICY_HND *domain_pol, uint32 *start_idx,
uint32 max_entries, uint32 max_size, uint16 switch_value, uint32 *num_entries,
SAM_DISPINFO_CTR *ctr) uint32 max_entries, uint32 max_size,
SAM_DISPINFO_CTR *ctr)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_QUERY_DISPINFO q; 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); *start_idx, max_entries, max_size);
if (!samr_io_q_query_dispinfo("", &q, &qbuf, 0) || 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; goto done;
} }
@@ -1601,14 +1731,26 @@ NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 /* Lookup rids. Note that NT4 seems to crash if more than ~1000 rids are
looked up in one packet. */ looked up in one packet. */
NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS rpccli_samr_lookup_rids(struct rpc_pipe_client *cli,
POLICY_HND *domain_pol, TALLOC_CTX *mem_ctx,
uint32 num_rids, uint32 *rids, POLICY_HND *domain_pol,
uint32 *num_names, char ***names, uint32 num_rids, uint32 *rids,
uint32 **name_types) uint32 *num_names, char ***names,
uint32 **name_types)
{ {
prs_struct qbuf, rbuf; prs_struct qbuf, rbuf;
SAMR_Q_LOOKUP_RIDS q; 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); init_samr_q_lookup_rids(mem_ctx, &q, domain_pol, 1000, num_rids, rids);
if (!samr_io_q_lookup_rids("", &q, &qbuf, 0) || 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; goto done;
} }
@@ -1679,6 +1821,17 @@ NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result; 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 */ /* Lookup names */
NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,

View File

@@ -1240,6 +1240,32 @@ BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_
return True; 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 prs_uint16 wrapper. Call this and it sets up a pointer to where the
uint16 should be stored, or gets the size if reading. uint16 should be stored, or gets the size if reading.

View 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 */ /* still have session, just need to use it again */
cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP; cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
cli->pipe_auth_flags |= AUTH_PIPE_SIGN; 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); 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_NTLMSSP;
cli->pipe_auth_flags |= AUTH_PIPE_SIGN; cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
cli->pipe_auth_flags |= AUTH_PIPE_SEAL; 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); cli_nt_session_close(cli);
} }
return NT_STATUS_OK; return NT_STATUS_OK;
@@ -346,7 +346,7 @@ static NTSTATUS cmd_none(struct cli_state *cli, TALLOC_CTX *mem_ctx,
} else { } else {
/* still have session, just need to use it again */ /* still have session, just need to use it again */
cli->pipe_auth_flags = 0; 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_nt_session_close(cli);
} }
cli->pipe_auth_flags = 0; 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]; uchar trust_password[16];
uint32 sec_channel_type; uint32 sec_channel_type;
if (argc == 2) { if (argc == 2) {
strhex_to_str((char *)cli->auth_info.sess_key, strhex_to_str(cli->sess_key, strlen(argv[1]), argv[1]);
strlen(argv[1]),
argv[1]);
memcpy(cli->sess_key, cli->auth_info.sess_key, sizeof(cli->sess_key));
cli->pipe_auth_flags = pipe_auth_flags; cli->pipe_auth_flags = pipe_auth_flags;
return NT_STATUS_OK; return NT_STATUS_OK;
} }
/* Cleanup */ /* Cleanup */
if ((memcmp(cli->auth_info.sess_key, zeros, sizeof(cli->auth_info.sess_key)) != 0)) { if ((memcmp(cli->sess_key, zeros, sizeof(cli->sess_key)) != 0) &&
if (cli->pipe_auth_flags == pipe_auth_flags) { (cli->pipe_auth_flags == pipe_auth_flags)) {
/* already in this mode nothing to do */ /* already in this mode nothing to do */
return NT_STATUS_OK; 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(), if (!secrets_fetch_trust_account_password(lp_workgroup(),
trust_password, trust_password,
NULL, &sec_channel_type)) { 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); ret = cli_nt_setup_netsec(cli, sec_channel_type, pipe_auth_flags, trust_password);
if (NT_STATUS_IS_OK(ret)) { if (NT_STATUS_IS_OK(ret)) {
char *hex_session_key; char *hex_session_key;
hex_encode(cli->auth_info.sess_key, hex_encode(cli->pipes[cli->pipe_idx].auth_info.sess_key,
sizeof(cli->auth_info.sess_key), sizeof(cli->pipes[cli->pipe_idx].auth_info.sess_key),
&hex_session_key); &hex_session_key);
printf("Got Session key: %s\n", hex_session_key); printf("Got Session key: %s\n", hex_session_key);
SAFE_FREE(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 if (cmd_entry->pipe_idx != -1
&& cmd_entry->pipe_idx != cli->pipe_idx) { && 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); cli_nt_session_close(cli);
if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) { if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
@@ -549,7 +534,7 @@ static NTSTATUS do_cmd(struct cli_state *cli,
trust_password, trust_password,
&neg_flags, 2); &neg_flags, 2);
if (!NT_STATUS_IS_OK(ntresult)) { 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)); printf("nt_setup_creds failed with %s\n", nt_errstr(ntresult));
return ntresult; return ntresult;
} }

View 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. 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; proxyonly = True;
} }
BOOL idmap_proxyonly(void)
{
return proxyonly;
}
/************************************************************************** /**************************************************************************
This is a rare operation, designed to allow an explicit mapping to be This is a rare operation, designed to allow an explicit mapping to be
set up for a sid to a POSIX id. 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; return NT_STATUS_OK;
} }
if (remote_map == NULL) { if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY)) {
return ret; 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)) if (NT_STATUS_IS_OK(ret))
return ret; return ret;
if (remote_map == NULL) if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY))
return ret; return ret;
/* We have a second chance, ask our authoritative backend */ /* We have a second chance, ask our authoritative backend */

View File

@@ -71,7 +71,8 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
else else
fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) ); 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 ); 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 ); type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
pstrcpy( suffix, lp_ldap_idmap_suffix() ); 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, 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 ); attr_list = get_attr_list( sidmap_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
@@ -700,8 +701,8 @@ static NTSTATUS verify_idpool( void )
return NT_STATUS_UNSUCCESSFUL; return NT_STATUS_UNSUCCESSFUL;
} }
fstr_sprintf( uid_str, "%d", luid ); fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
fstr_sprintf( gid_str, "%d", lgid ); 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, "objectClass", LDAP_OBJ_IDPOOL );
smbldap_set_mod( &mods, LDAP_MOD_ADD, smbldap_set_mod( &mods, LDAP_MOD_ADD,

View File

@@ -100,14 +100,13 @@ BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
Returns SID pointer. 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; unid_t id;
int flags;
DEBUG(10,("idmap_uid_to_sid: uid = [%lu]\n", (unsigned long)uid)); DEBUG(10,("idmap_uid_to_sid: uid = [%lu]\n", (unsigned long)uid));
flags = ID_USERID; flags |= ID_USERID;
id.uid = uid; id.uid = uid;
return idmap_get_sid_from_id(sid, id, flags); 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. 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; unid_t id;
int flags;
DEBUG(10,("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid)); DEBUG(10,("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid));
flags = ID_GROUPID; flags |= ID_GROUPID;
#if 0 /* JERRY */
if (!idmap_check_ugid_is_in_free_range(gid)) {
flags |= ID_QUERY_ONLY;
}
#endif
id.gid = gid; id.gid = gid;
return idmap_get_sid_from_id(sid, id, flags); return idmap_get_sid_from_id(sid, id, flags);
} }

View File

@@ -288,7 +288,7 @@ enum client_action
{ {
int i; int i;
for (i=0; i<PI_MAX_PIPES; 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); setup_logging(pname, True);

View 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 (!(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); cli_nt_session_close(cli);
} }
@@ -663,11 +663,11 @@ static NTSTATUS rpc_user_del_internals(const DOM_SID *domain_sid,
} }
/* Display results */ /* 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)); d_printf("Failed to delete user account - %s\n", nt_errstr(result));
} else { } else {
d_printf("Deleted user account\n"); d_printf("Deleted user account\n");
} }
done: done:
return result; return result;
@@ -4452,6 +4452,7 @@ static int rpc_trustdom_add(int argc, const char **argv)
} }
} }
/** /**
* Remove interdomain trust account from the RPC server. * Remove interdomain trust account from the RPC server.
* All parameters (except for argc and argv) are passed by run_rpc_command * 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; return -1;
} }
} }
/** /**
* Establish trust relationship to a trusting domain. * Establish trust relationship to a trusting domain.
@@ -4676,7 +4678,7 @@ static int rpc_trustdom_establish(int argc, const char **argv)
cli_shutdown(cli); cli_shutdown(cli);
return -1; return -1;
} }
/* /*
* Call LsaOpenPolicy and LsaQueryInfo * Call LsaOpenPolicy and LsaQueryInfo
*/ */
@@ -4739,7 +4741,7 @@ static int rpc_trustdom_establish(int argc, const char **argv)
return -1; return -1;
} }
if (cli->nt_pipe_fnum[cli->pipe_idx]) if (cli->pipes[cli->pipe_idx].fnum)
cli_nt_session_close(cli); cli_nt_session_close(cli);
cli_shutdown(cli); cli_shutdown(cli);

View File

@@ -77,7 +77,7 @@ static int net_rpc_join_ok(const char *domain)
done: done:
/* Close down pipe - this will clean up open policy handles */ /* 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_nt_session_close(cli);
cli_shutdown(cli); cli_shutdown(cli);
@@ -346,7 +346,7 @@ int net_rpc_join_newstyle(int argc, const char **argv)
done: done:
/* Close down pipe - this will clean up open policy handles */ /* 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_nt_session_close(cli);
/* Display success or failure */ /* Display success or failure */

View File

@@ -428,8 +428,7 @@ static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
return False; return False;
} }
notify_printer_byname(argv[2], attribute, notify_printer_byname(argv[2], attribute, argv[4]);
CONST_DISCARD(char *, argv[4]));
goto send; 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); 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 */ /* A list of message type supported */
static const struct { static const struct {
@@ -597,6 +643,7 @@ static const struct {
{ "shutdown", do_shutdown, "Shut down daemon" }, { "shutdown", do_shutdown, "Shut down daemon" },
{ "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
{ "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"}, { "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" }, { "noop", do_noop, "Do nothing" },
{ NULL } { NULL }
}; };