mirror of
https://github.com/samba-team/samba.git
synced 2025-11-27 08:23:49 +03:00
r7415: * big change -- volker's new async winbindd from trunk
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
0d303ab2f3
commit
a0ac9a8ffd
@@ -328,7 +328,6 @@ GROUPDB_OBJ = groupdb/mapping.o
|
||||
|
||||
PROFILE_OBJ = profile/profile.o
|
||||
PROFILES_OBJ = utils/profiles.o
|
||||
EDITREG_OBJ = utils/editreg.o
|
||||
|
||||
OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
|
||||
|
||||
@@ -655,9 +654,11 @@ WINBINDD_OBJ1 = \
|
||||
nsswitch/winbindd_cm.o \
|
||||
nsswitch/winbindd_wins.o \
|
||||
nsswitch/winbindd_rpc.o \
|
||||
nsswitch/winbindd_reconnect.o \
|
||||
nsswitch/winbindd_ads.o \
|
||||
nsswitch/winbindd_passdb.o \
|
||||
nsswitch/winbindd_dual.o
|
||||
nsswitch/winbindd_dual.o \
|
||||
nsswitch/winbindd_async.o
|
||||
|
||||
WINBINDD_OBJ = \
|
||||
$(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
|
||||
@@ -689,8 +690,8 @@ NTLM_AUTH_OBJ1 = utils/ntlm_auth.o utils/ntlm_auth_diagnostics.o
|
||||
NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
|
||||
libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \
|
||||
libads/kerberos_verify.o $(SECRETS_OBJ) $(SERVER_MUTEX_OBJ) \
|
||||
libads/authdata.o $(RPC_PARSE_OBJ0) \
|
||||
$(DOSERR_OBJ)
|
||||
libads/authdata.o $(RPC_PARSE_OBJ0) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
|
||||
$(SMBLDAP_OBJ) $(DOSERR_OBJ)
|
||||
|
||||
######################################################################
|
||||
# now the rules...
|
||||
@@ -852,10 +853,6 @@ bin/profiles@EXEEXT@: $(PROFILES_OBJ) @BUILD_POPT@ bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ @SOCKWRAP@
|
||||
|
||||
bin/editreg@EXEEXT@: $(EDITREG_OBJ) @BUILD_POPT@ bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(EDITREG_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@
|
||||
|
||||
bin/smbspool@EXEEXT@: $(CUPS_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
|
||||
@@ -1056,6 +1053,11 @@ bin/librpc_spoolss.@SHLIBEXT@: $(RPC_SPOOLSS_OBJ)
|
||||
@$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_SPOOLSS_OBJ) -lc \
|
||||
@SONAMEFLAG@`basename $@`
|
||||
|
||||
bin/librpc_eventlog.@SHLIBEXT@: $(RPC_EVENTLOG_OBJ)
|
||||
@echo "Linking $@"
|
||||
@$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_EVENTLOG_OBJ) -lc \
|
||||
@SONAMEFLAG@`basename $@`
|
||||
|
||||
bin/librpc_netdfs.@SHLIBEXT@: $(RPC_DFS_OBJ)
|
||||
@echo "Linking $@"
|
||||
@$(SHLD) $(LDSHFLAGS) -o $@ $(RPC_DFS_OBJ) -lc \
|
||||
@@ -1496,7 +1498,8 @@ headers:
|
||||
$(MAKE) nsswitch/winbindd_proto.h; \
|
||||
$(MAKE) web/swat_proto.h; \
|
||||
$(MAKE) client/client_proto.h; \
|
||||
$(MAKE) utils/net_proto.h
|
||||
$(MAKE) utils/ntlm_auth_proto.h; \
|
||||
$(MAKE) utils/net_proto.h;
|
||||
|
||||
proto: headers
|
||||
|
||||
|
||||
@@ -57,6 +57,27 @@ struct print_job_info
|
||||
time_t t;
|
||||
};
|
||||
|
||||
struct rpc_pipe_client {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
struct cli_state *cli;
|
||||
|
||||
int pipe_idx;
|
||||
uint16 fnum;
|
||||
|
||||
int pipe_auth_flags;
|
||||
|
||||
NTLMSSP_STATE *ntlmssp_pipe_state;
|
||||
const char *user_name;
|
||||
const char *domain;
|
||||
struct pwd_info pwd;
|
||||
|
||||
struct netsec_auth_struct auth_info;
|
||||
|
||||
uint16 max_xmit_frag;
|
||||
uint16 max_recv_frag;
|
||||
};
|
||||
|
||||
struct cli_state {
|
||||
int port;
|
||||
int fd;
|
||||
@@ -124,25 +145,19 @@ struct cli_state {
|
||||
of the pipe we're talking to,
|
||||
if any */
|
||||
|
||||
uint16 nt_pipe_fnum[PI_MAX_PIPES]; /* Pipe handle. */
|
||||
struct rpc_pipe_client pipes[PI_MAX_PIPES];
|
||||
|
||||
/* Secure pipe parameters */
|
||||
int pipe_auth_flags;
|
||||
|
||||
uint16 saved_netlogon_pipe_fnum; /* The "first" pipe to get
|
||||
the session key for the
|
||||
schannel. */
|
||||
struct netsec_auth_struct auth_info;
|
||||
|
||||
NTLMSSP_STATE *ntlmssp_pipe_state;
|
||||
|
||||
struct rpc_pipe_client netlogon_pipe; /* The "first" pipe to get
|
||||
the session key for the
|
||||
schannel. */
|
||||
unsigned char sess_key[16]; /* Current session key. */
|
||||
DOM_CRED clnt_cred; /* Client credential. */
|
||||
fstring mach_acct; /* MYNAME$. */
|
||||
fstring srv_name_slash; /* \\remote server. */
|
||||
fstring clnt_name_slash; /* \\local client. */
|
||||
uint16 max_xmit_frag;
|
||||
uint16 max_recv_frag;
|
||||
|
||||
BOOL use_kerberos;
|
||||
BOOL fallback_after_kerberos;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define ID_TYPEMASK 0x0f
|
||||
|
||||
#define ID_QUERY_ONLY 0x10
|
||||
#define ID_CACHE_ONLY 0x20
|
||||
|
||||
/* Filled out by IDMAP backends */
|
||||
struct idmap_methods {
|
||||
|
||||
@@ -804,7 +804,12 @@ extern int errno;
|
||||
#include "tdb/tdb.h"
|
||||
#include "tdb/spinlock.h"
|
||||
#include "tdb/tdbutil.h"
|
||||
|
||||
#include "talloc.h"
|
||||
/* And a little extension. Abort on type mismatch */
|
||||
#define talloc_get_type_abort(ptr, type) \
|
||||
(type *)talloc_check_name_abort(ptr, #type)
|
||||
|
||||
#include "nt_status.h"
|
||||
#include "ads.h"
|
||||
#include "interfaces.h"
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
/* nmbd messages */
|
||||
#define MSG_FORCE_ELECTION 1001
|
||||
#define MSG_WINS_NEW_ENTRY 1002
|
||||
#define MSG_SEND_PACKET 1003
|
||||
|
||||
/* printing messages */
|
||||
/* #define MSG_PRINTER_NOTIFY 2001*/ /* Obsolete */
|
||||
@@ -63,6 +64,10 @@
|
||||
#define MSG_SMB_SAM_REPL 3004
|
||||
#define MSG_SMB_UNLOCK 3005
|
||||
|
||||
/* winbind messages */
|
||||
#define MSG_WINBIND_FINISHED 4001
|
||||
#define MSG_WINBIND_FORGET_STATE 4002
|
||||
|
||||
/* Flags to classify messages - used in message_send_all() */
|
||||
/* Sender will filter by flag. */
|
||||
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
#ifndef _RPC_CLIENT_H
|
||||
#define _RPC_CLIENT_H
|
||||
|
||||
/* macro to expand cookie-cutter code in cli_xxx() */
|
||||
/* macro to expand cookie-cutter code in cli_xxx() using rpc_api_pipe_req() */
|
||||
|
||||
#define CLI_DO_RPC( pcli, ctx, pipe_num, opnum, q_in, r_out, q_ps, r_ps, q_io_fn, r_io_fn, default_error) \
|
||||
#define CLI_DO_RPC( pcli, ctx, pipe_num, opnum, q_in, r_out, \
|
||||
q_ps, r_ps, q_io_fn, r_io_fn, default_error ) \
|
||||
{ r_out.status = default_error;\
|
||||
prs_init( &q_ps, MAX_PDU_FRAG_LEN, ctx, MARSHALL ); \
|
||||
prs_init( &r_ps, 0, ctx, UNMARSHALL );\
|
||||
@@ -38,4 +39,22 @@
|
||||
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 */
|
||||
|
||||
@@ -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__
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
@@ -342,6 +342,12 @@ BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
|
||||
return False;
|
||||
}
|
||||
|
||||
BOOL sid_compose(DOM_SID *dst, const DOM_SID *domain_sid, uint32 rid)
|
||||
{
|
||||
sid_copy(dst, domain_sid);
|
||||
return sid_append_rid(dst, rid);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Removes the last rid from the end of a sid
|
||||
*****************************************************************/
|
||||
|
||||
@@ -2128,3 +2128,69 @@ BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
|
||||
*num += 1;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Append an sprintf'ed string. Double buffer size on demand. Usable without
|
||||
* error checking in between. The indiation that something weird happened is
|
||||
* string==NULL */
|
||||
|
||||
void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
|
||||
size_t *bufsize, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *newstr;
|
||||
int ret;
|
||||
BOOL increased;
|
||||
|
||||
/* len<0 is an internal marker that something failed */
|
||||
if (*len < 0)
|
||||
goto error;
|
||||
|
||||
if (*string == NULL) {
|
||||
if (*bufsize == 0)
|
||||
*bufsize = 128;
|
||||
|
||||
if (mem_ctx != NULL)
|
||||
*string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
|
||||
else
|
||||
*string = SMB_MALLOC_ARRAY(char, *bufsize);
|
||||
|
||||
if (*string == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vasprintf(&newstr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
increased = False;
|
||||
|
||||
while ((*len)+ret >= *bufsize) {
|
||||
increased = True;
|
||||
*bufsize *= 2;
|
||||
if (*bufsize >= (1024*1024*256))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (increased) {
|
||||
if (mem_ctx != NULL)
|
||||
*string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
|
||||
*bufsize);
|
||||
else
|
||||
*string = SMB_REALLOC_ARRAY(*string, char, *bufsize);
|
||||
|
||||
if (*string == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
StrnCpy((*string)+(*len), newstr, ret);
|
||||
(*len) += ret;
|
||||
free(newstr);
|
||||
return;
|
||||
|
||||
error:
|
||||
*len = -1;
|
||||
*string = NULL;
|
||||
}
|
||||
|
||||
@@ -88,8 +88,7 @@ int kerberos_kinit_password(const char *principal,
|
||||
return code;
|
||||
}
|
||||
|
||||
if ((code = krb5_get_init_creds_password(ctx, &my_creds, me,
|
||||
CONST_DISCARD(char *, password),
|
||||
if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password,
|
||||
kerb_prompter,
|
||||
NULL, 0, NULL, NULL))) {
|
||||
krb5_free_principal(ctx, me);
|
||||
|
||||
@@ -26,105 +26,101 @@
|
||||
* cli_send_mailslot, send a mailslot for client code ...
|
||||
*/
|
||||
|
||||
int cli_send_mailslot(int dgram_sock, BOOL unique, const char *mailslot,
|
||||
char *buf, int len,
|
||||
const char *srcname, int src_type,
|
||||
const char *dstname, int dest_type,
|
||||
struct in_addr dest_ip, struct in_addr src_ip,
|
||||
int dest_port, int src_port)
|
||||
BOOL cli_send_mailslot(BOOL unique, const char *mailslot,
|
||||
uint16 priority,
|
||||
char *buf, int len,
|
||||
const char *srcname, int src_type,
|
||||
const char *dstname, int dest_type,
|
||||
struct in_addr dest_ip)
|
||||
{
|
||||
struct packet_struct p;
|
||||
struct dgram_packet *dgram = &p.packet.dgram;
|
||||
char *ptr, *p2;
|
||||
char tmp[4];
|
||||
struct packet_struct p;
|
||||
struct dgram_packet *dgram = &p.packet.dgram;
|
||||
char *ptr, *p2;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, build the DGRAM ...
|
||||
*/
|
||||
if (!message_init())
|
||||
return False;
|
||||
|
||||
/* DIRECT GROUP or UNIQUE datagram. */
|
||||
dgram->header.msg_type = unique ? 0x10 : 0x11;
|
||||
dgram->header.flags.node_type = M_NODE;
|
||||
dgram->header.flags.first = True;
|
||||
dgram->header.flags.more = False;
|
||||
dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
|
||||
dgram->header.source_ip.s_addr = src_ip.s_addr;
|
||||
dgram->header.source_port = ntohs(src_port);
|
||||
dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
|
||||
dgram->header.packet_offset = 0;
|
||||
memset((char *)&p, '\0', sizeof(p));
|
||||
|
||||
make_nmb_name(&dgram->source_name,srcname,src_type);
|
||||
make_nmb_name(&dgram->dest_name,dstname,dest_type);
|
||||
/*
|
||||
* Next, build the DGRAM ...
|
||||
*/
|
||||
|
||||
ptr = &dgram->data[0];
|
||||
/* DIRECT GROUP or UNIQUE datagram. */
|
||||
dgram->header.msg_type = unique ? 0x10 : 0x11;
|
||||
dgram->header.flags.node_type = M_NODE;
|
||||
dgram->header.flags.first = True;
|
||||
dgram->header.flags.more = False;
|
||||
dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
|
||||
((unsigned)sys_getpid()%(unsigned)100);
|
||||
/* source ip is filled by nmbd */
|
||||
dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
|
||||
dgram->header.packet_offset = 0;
|
||||
|
||||
/* Setup the smb part. */
|
||||
ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
|
||||
memcpy(tmp,ptr,4);
|
||||
set_message(ptr,17,strlen(mailslot) + 1 + len,True);
|
||||
memcpy(ptr,tmp,4);
|
||||
make_nmb_name(&dgram->source_name,srcname,src_type);
|
||||
make_nmb_name(&dgram->dest_name,dstname,dest_type);
|
||||
|
||||
SCVAL(ptr,smb_com,SMBtrans);
|
||||
SSVAL(ptr,smb_vwv1,len);
|
||||
SSVAL(ptr,smb_vwv11,len);
|
||||
SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
|
||||
SSVAL(ptr,smb_vwv13,3);
|
||||
SSVAL(ptr,smb_vwv14,1);
|
||||
SSVAL(ptr,smb_vwv15,1);
|
||||
SSVAL(ptr,smb_vwv16,2);
|
||||
p2 = smb_buf(ptr);
|
||||
fstrcpy(p2,mailslot);
|
||||
p2 = skip_string(p2,1);
|
||||
ptr = &dgram->data[0];
|
||||
|
||||
memcpy(p2,buf,len);
|
||||
p2 += len;
|
||||
/* Setup the smb part. */
|
||||
ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
|
||||
memcpy(tmp,ptr,4);
|
||||
set_message(ptr,17,strlen(mailslot) + 1 + len,True);
|
||||
memcpy(ptr,tmp,4);
|
||||
|
||||
dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
|
||||
SCVAL(ptr,smb_com,SMBtrans);
|
||||
SSVAL(ptr,smb_vwv1,len);
|
||||
SSVAL(ptr,smb_vwv11,len);
|
||||
SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
|
||||
SSVAL(ptr,smb_vwv13,3);
|
||||
SSVAL(ptr,smb_vwv14,1);
|
||||
SSVAL(ptr,smb_vwv15,priority);
|
||||
SSVAL(ptr,smb_vwv16,2);
|
||||
p2 = smb_buf(ptr);
|
||||
fstrcpy(p2,mailslot);
|
||||
p2 = skip_string(p2,1);
|
||||
|
||||
p.ip = dest_ip;
|
||||
p.port = dest_port;
|
||||
p.fd = dgram_sock;
|
||||
p.timestamp = time(NULL);
|
||||
p.packet_type = DGRAM_PACKET;
|
||||
memcpy(p2,buf,len);
|
||||
p2 += len;
|
||||
|
||||
DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
|
||||
nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
|
||||
DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
|
||||
dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
|
||||
|
||||
return send_packet(&p);
|
||||
p.packet_type = DGRAM_PACKET;
|
||||
p.ip = dest_ip;
|
||||
p.timestamp = time(NULL);
|
||||
|
||||
DEBUG(4,("send_mailslot: Sending to mailslot %s from %s ",
|
||||
mailslot, nmb_namestr(&dgram->source_name)));
|
||||
DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name),
|
||||
inet_ntoa(dest_ip)));
|
||||
|
||||
return message_send_pid(nmbd_pid, MSG_SEND_PACKET, &p, sizeof(p),
|
||||
False);
|
||||
}
|
||||
|
||||
/*
|
||||
* cli_get_response: Get a response ...
|
||||
*/
|
||||
int cli_get_response(int dgram_sock, BOOL unique, const char *mailslot, char *buf, int bufsiz)
|
||||
BOOL cli_get_response(const char *mailslot, char *buf, int bufsiz)
|
||||
{
|
||||
struct packet_struct *packet;
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
memcpy(buf, &p->packet.dgram.data[92],
|
||||
MIN(bufsiz, p->packet.dgram.datasize-92));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,108 +131,43 @@ static char cli_backup_list[1024];
|
||||
|
||||
int cli_get_backup_list(const char *myname, const char *send_to_name)
|
||||
{
|
||||
pstring outbuf;
|
||||
char *p;
|
||||
struct in_addr sendto_ip, my_ip;
|
||||
int dgram_sock;
|
||||
struct sockaddr_in sock_out;
|
||||
socklen_t name_size;
|
||||
pstring outbuf;
|
||||
char *p;
|
||||
struct in_addr sendto_ip;
|
||||
|
||||
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));
|
||||
return False;
|
||||
DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
|
||||
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 */
|
||||
p = outbuf;
|
||||
|
||||
DEBUG(0, ("Could not resolve name: %s<00>\n", myname));
|
||||
SCVAL(p, 0, ANN_GetBackupListReq);
|
||||
p++;
|
||||
|
||||
}
|
||||
SCVAL(p, 0, 1); /* Count pointer ... */
|
||||
p++;
|
||||
|
||||
if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) {
|
||||
SIVAL(p, 0, 1); /* The sender's token ... */
|
||||
p += 4;
|
||||
|
||||
DEBUG(4, ("open_sock_out failed ..."));
|
||||
return False;
|
||||
cli_send_mailslot(True, "\\MAILSLOT\\BROWSE", 1, outbuf,
|
||||
PTR_DIFF(p, outbuf), myname, 0, send_to_name,
|
||||
0x1d, sendto_ip);
|
||||
|
||||
}
|
||||
/* We should check the error and return if we got one */
|
||||
|
||||
/* Make it a broadcast socket ... */
|
||||
/* Now, get the response ... */
|
||||
|
||||
set_socket_options(dgram_sock, "SO_BROADCAST");
|
||||
cli_get_response("\\MAILSLOT\\BROWSE",
|
||||
cli_backup_list, sizeof(cli_backup_list));
|
||||
|
||||
/* Make it non-blocking??? */
|
||||
|
||||
if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
|
||||
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;
|
||||
return True;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern int smb_read_error;
|
||||
|
||||
/****************************************************************************
|
||||
Change the timeout (in milliseconds).
|
||||
****************************************************************************/
|
||||
@@ -83,6 +81,7 @@ static BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
|
||||
|
||||
BOOL cli_receive_smb(struct cli_state *cli)
|
||||
{
|
||||
extern int smb_read_error;
|
||||
BOOL ret;
|
||||
|
||||
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
|
||||
@@ -321,9 +320,9 @@ struct cli_state *cli_initialise(struct cli_state *cli)
|
||||
cli_null_set_signing(cli);
|
||||
|
||||
for (i=0; i<PI_MAX_PIPES; i++)
|
||||
cli->nt_pipe_fnum[i] = 0;
|
||||
cli->pipes[i].fnum = 0;
|
||||
|
||||
cli->saved_netlogon_pipe_fnum = 0;
|
||||
cli->netlogon_pipe.fnum = 0;
|
||||
|
||||
cli->initialised = 1;
|
||||
cli->allocated = alloced_cli;
|
||||
@@ -353,14 +352,14 @@ void cli_nt_session_close(struct cli_state *cli)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cli->ntlmssp_pipe_state) {
|
||||
ntlmssp_end(&cli->ntlmssp_pipe_state);
|
||||
}
|
||||
|
||||
for (i=0; i<PI_MAX_PIPES; i++) {
|
||||
if (cli->nt_pipe_fnum[i] != 0)
|
||||
cli_close(cli, cli->nt_pipe_fnum[i]);
|
||||
cli->nt_pipe_fnum[i] = 0;
|
||||
if (cli->pipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
|
||||
ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state);
|
||||
}
|
||||
|
||||
if (cli->pipes[i].fnum != 0)
|
||||
cli_close(cli, cli->pipes[i].fnum);
|
||||
cli->pipes[i].fnum = 0;
|
||||
}
|
||||
cli->pipe_idx = -1;
|
||||
}
|
||||
@@ -371,9 +370,9 @@ close the NETLOGON session holding the session key for NETSEC
|
||||
|
||||
void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
|
||||
{
|
||||
if (cli->saved_netlogon_pipe_fnum != 0) {
|
||||
cli_close(cli, cli->saved_netlogon_pipe_fnum);
|
||||
cli->saved_netlogon_pipe_fnum = 0;
|
||||
if (cli->netlogon_pipe.fnum != 0) {
|
||||
cli_close(cli, cli->netlogon_pipe.fnum);
|
||||
cli->netlogon_pipe.fnum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,8 +407,8 @@ void cli_close_connection(struct cli_state *cli)
|
||||
data_blob_free(&cli->secblob);
|
||||
data_blob_free(&cli->user_session_key);
|
||||
|
||||
if (cli->ntlmssp_pipe_state)
|
||||
ntlmssp_end(&cli->ntlmssp_pipe_state);
|
||||
if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP)
|
||||
ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state);
|
||||
|
||||
if (cli->mem_ctx) {
|
||||
talloc_destroy(cli->mem_ctx);
|
||||
|
||||
@@ -505,7 +505,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
|
||||
*/
|
||||
if (cli_is_dos_error(cli)) {
|
||||
cli_dos_error(cli, &eclass, &ecode);
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
|
||||
if (cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
|
||||
cli_signing_trans_stop(cli);
|
||||
return(False);
|
||||
}
|
||||
@@ -639,7 +639,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
|
||||
}
|
||||
if (cli_is_dos_error(cli)) {
|
||||
cli_dos_error(cli, &eclass, &ecode);
|
||||
if(cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
|
||||
if(cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
|
||||
cli_signing_trans_stop(cli);
|
||||
return(False);
|
||||
}
|
||||
|
||||
@@ -323,6 +323,56 @@ static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t
|
||||
}
|
||||
}
|
||||
|
||||
static void msg_nmbd_send_packet(int msg_type, pid_t src,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct packet_struct *p = (struct packet_struct *)buf;
|
||||
struct subnet_record *subrec;
|
||||
struct in_addr *local_ip;
|
||||
|
||||
DEBUG(10, ("Received send_packet from %d\n", src));
|
||||
|
||||
if (len != sizeof(struct packet_struct)) {
|
||||
DEBUG(2, ("Discarding invalid packet length from %d\n", src));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((p->packet_type != NMB_PACKET) &&
|
||||
(p->packet_type != DGRAM_PACKET)) {
|
||||
DEBUG(2, ("Discarding invalid packet type from %d: %d\n",
|
||||
src, p->packet_type));
|
||||
return;
|
||||
}
|
||||
|
||||
local_ip = iface_ip(p->ip);
|
||||
|
||||
if (local_ip == NULL) {
|
||||
DEBUG(2, ("Could not find ip for packet from %d\n", src));
|
||||
return;
|
||||
}
|
||||
|
||||
subrec = FIRST_SUBNET;
|
||||
|
||||
p->fd = (p->packet_type == NMB_PACKET) ?
|
||||
subrec->nmb_sock : subrec->dgram_sock;
|
||||
|
||||
for (subrec = FIRST_SUBNET; subrec != NULL;
|
||||
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
|
||||
if (ip_equal(*local_ip, subrec->myip)) {
|
||||
p->fd = (p->packet_type == NMB_PACKET) ?
|
||||
subrec->nmb_sock : subrec->dgram_sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->packet_type == DGRAM_PACKET) {
|
||||
p->port = 138;
|
||||
p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
|
||||
p->packet.dgram.header.source_port = 138;
|
||||
}
|
||||
|
||||
send_packet(p);
|
||||
}
|
||||
|
||||
/**************************************************************************** **
|
||||
The main select loop.
|
||||
@@ -720,6 +770,7 @@ static BOOL open_sockets(BOOL isdaemon, int port)
|
||||
message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
|
||||
message_register(MSG_SHUTDOWN, nmbd_terminate);
|
||||
message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
|
||||
message_register(MSG_SEND_PACKET, msg_nmbd_send_packet);
|
||||
|
||||
DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
|
||||
|
||||
|
||||
@@ -257,6 +257,32 @@ BOOL winbind_allocate_rid(uint32 *rid)
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
int result;
|
||||
|
||||
/* Initialise request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
/* Make request */
|
||||
|
||||
result = winbindd_request(WINBINDD_ALLOCATE_RID_AND_GID, &request,
|
||||
&response);
|
||||
|
||||
if (result != NSS_STATUS_SUCCESS)
|
||||
return False;
|
||||
|
||||
/* Copy out result */
|
||||
*rid = response.data.rid_and_gid.rid;
|
||||
*gid = response.data.rid_and_gid.gid;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Fetch the list of groups a user is a member of from winbindd. This is
|
||||
used by winbind_getgroups. */
|
||||
|
||||
|
||||
@@ -167,6 +167,32 @@ static BOOL wbinfo_get_usersids(char *user_sid)
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL wbinfo_get_userdomgroups(const char *user_sid)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
/* Send request */
|
||||
fstrcpy(request.data.sid, user_sid);
|
||||
|
||||
result = winbindd_request(WINBINDD_GETUSERDOMGROUPS, &request,
|
||||
&response);
|
||||
|
||||
if (result != NSS_STATUS_SUCCESS)
|
||||
return False;
|
||||
|
||||
if (response.data.num_entries != 0)
|
||||
printf("%s", (char *)response.extra_data);
|
||||
|
||||
SAFE_FREE(response.extra_data);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/* Convert NetBIOS name to IP */
|
||||
|
||||
static BOOL wbinfo_wins_byname(char *name)
|
||||
@@ -224,7 +250,6 @@ static BOOL wbinfo_wins_byip(char *ip)
|
||||
static BOOL wbinfo_list_domains(void)
|
||||
{
|
||||
struct winbindd_response response;
|
||||
fstring name;
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
@@ -238,9 +263,19 @@ static BOOL wbinfo_list_domains(void)
|
||||
|
||||
if (response.extra_data) {
|
||||
const char *extra_data = (char *)response.extra_data;
|
||||
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);
|
||||
}
|
||||
|
||||
SAFE_FREE(response.extra_data);
|
||||
}
|
||||
@@ -316,6 +351,32 @@ static BOOL wbinfo_domain_info(const char *domain_name)
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Get a foreign DC's name */
|
||||
static BOOL wbinfo_getdcname(const char *domain_name)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.domain_name, domain_name);
|
||||
|
||||
/* Send request */
|
||||
|
||||
if (winbindd_request(WINBINDD_GETDCNAME, &request, &response) !=
|
||||
NSS_STATUS_SUCCESS) {
|
||||
d_printf("Could not get dc name for %s\n", domain_name);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Display response */
|
||||
|
||||
d_printf("%s\n", response.data.dc_name);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Check trust account password */
|
||||
|
||||
static BOOL wbinfo_check_secret(void)
|
||||
@@ -889,6 +950,8 @@ enum {
|
||||
OPT_GET_AUTH_USER,
|
||||
OPT_DOMAIN_NAME,
|
||||
OPT_SEQUENCE,
|
||||
OPT_GETDCNAME,
|
||||
OPT_USERDOMGROUPS,
|
||||
OPT_USERSIDS
|
||||
};
|
||||
|
||||
@@ -924,9 +987,13 @@ int main(int argc, char **argv)
|
||||
{ "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
|
||||
{ "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
|
||||
{ "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
|
||||
{ "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
|
||||
OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
|
||||
{ "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
|
||||
{ "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
|
||||
{ "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
|
||||
{ "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
|
||||
"Get a DC name for a foreign domain", "domainname" },
|
||||
{ "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
|
||||
{ "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
|
||||
{ "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
|
||||
@@ -1079,6 +1146,13 @@ int main(int argc, char **argv)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case OPT_USERDOMGROUPS:
|
||||
if (!wbinfo_get_userdomgroups(string_arg)) {
|
||||
d_printf("Could not get user's domain groups "
|
||||
"for user SID %s\n", string_arg);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 'a': {
|
||||
BOOL got_error = False;
|
||||
|
||||
@@ -1116,6 +1190,9 @@ int main(int argc, char **argv)
|
||||
case OPT_GET_AUTH_USER:
|
||||
wbinfo_get_auth_user();
|
||||
break;
|
||||
case OPT_GETDCNAME:
|
||||
wbinfo_getdcname(string_arg);
|
||||
break;
|
||||
/* generic configuration options */
|
||||
case OPT_DOMAIN_NAME:
|
||||
break;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
Copyright (C) by Tim Potter 2000-2002
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
Copyright (C) Jelmer Vernooij 2003
|
||||
Copyright (C) Volker Lendecke 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -27,6 +28,7 @@
|
||||
|
||||
BOOL opt_nocache = False;
|
||||
BOOL opt_dual_daemon = True;
|
||||
static BOOL interactive = False;
|
||||
|
||||
extern BOOL override_logfile;
|
||||
|
||||
@@ -131,7 +133,6 @@ static void winbindd_status(void)
|
||||
static void print_winbindd_status(void)
|
||||
{
|
||||
winbindd_status();
|
||||
winbindd_cm_status();
|
||||
}
|
||||
|
||||
/* Flush client cache */
|
||||
@@ -163,6 +164,17 @@ static void terminate(void)
|
||||
pstr_sprintf(path, "%s/%s",
|
||||
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
|
||||
unlink(path);
|
||||
|
||||
#if 0
|
||||
if (interactive) {
|
||||
TALLOC_CTX *mem_ctx = talloc_init("end_description");
|
||||
char *description = talloc_describe_all(mem_ctx);
|
||||
|
||||
DEBUG(3, ("tallocs left:\n%s\n", description));
|
||||
talloc_destroy(mem_ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -190,14 +202,11 @@ static void sighup_handler(int signum)
|
||||
sys_select_signal();
|
||||
}
|
||||
|
||||
static BOOL do_sigchld;
|
||||
|
||||
static void sigchld_handler(int signum)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
while ((pid = wait(&status)) != -1 || errno == EINTR) {
|
||||
continue; /* Reap children */
|
||||
}
|
||||
do_sigchld = True;
|
||||
sys_select_signal();
|
||||
}
|
||||
|
||||
@@ -215,13 +224,7 @@ static void msg_shutdown(int msg_type, pid_t src, void *buf, size_t len)
|
||||
terminate();
|
||||
}
|
||||
|
||||
struct dispatch_table {
|
||||
enum winbindd_cmd cmd;
|
||||
enum winbindd_result (*fn)(struct winbindd_cli_state *state);
|
||||
const char *winbindd_cmd_name;
|
||||
};
|
||||
|
||||
static struct dispatch_table dispatch_table[] = {
|
||||
static struct winbindd_dispatch_table dispatch_table[] = {
|
||||
|
||||
/* User functions */
|
||||
|
||||
@@ -234,6 +237,8 @@ static struct dispatch_table dispatch_table[] = {
|
||||
|
||||
{ WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
|
||||
{ WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
|
||||
{ WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
|
||||
"GETUSERDOMGROUPS" },
|
||||
|
||||
/* Group functions */
|
||||
|
||||
@@ -247,14 +252,15 @@ static struct dispatch_table dispatch_table[] = {
|
||||
/* PAM auth functions */
|
||||
|
||||
{ WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
|
||||
{ WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
|
||||
{ WINBINDD_PAM_AUTH_CRAP, winbindd_crap_auth, "AUTH_CRAP" },
|
||||
{ WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
|
||||
|
||||
/* Enumeration functions */
|
||||
|
||||
{ WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
|
||||
{ WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
|
||||
{ WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
|
||||
{ WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
|
||||
"LIST_TRUSTDOM" },
|
||||
{ WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
|
||||
|
||||
/* SID related functions */
|
||||
@@ -266,20 +272,25 @@ static struct dispatch_table dispatch_table[] = {
|
||||
|
||||
{ WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
|
||||
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
|
||||
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
|
||||
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
|
||||
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
|
||||
{ WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
|
||||
{ WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid,
|
||||
"ALLOCATE_RID_AND_GID" },
|
||||
|
||||
/* Miscellaneous */
|
||||
|
||||
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
|
||||
{ WINBINDD_PING, winbindd_ping, "PING" },
|
||||
{ WINBINDD_INFO, winbindd_info, "INFO" },
|
||||
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
|
||||
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
|
||||
"INTERFACE_VERSION" },
|
||||
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
|
||||
{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
|
||||
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
|
||||
{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" },
|
||||
{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
|
||||
"WINBINDD_PRIV_PIPE_DIR" },
|
||||
{ WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
|
||||
|
||||
/* WINS functions */
|
||||
|
||||
@@ -293,7 +304,7 @@ static struct dispatch_table dispatch_table[] = {
|
||||
|
||||
static void process_request(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct dispatch_table *table = dispatch_table;
|
||||
struct winbindd_dispatch_table *table = dispatch_table;
|
||||
|
||||
/* Free response data - we may be interrupted and receive another
|
||||
command before being able to send this data off. */
|
||||
@@ -302,26 +313,255 @@ static void process_request(struct winbindd_cli_state *state)
|
||||
|
||||
ZERO_STRUCT(state->response);
|
||||
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
state->response.result = WINBINDD_PENDING;
|
||||
state->response.length = sizeof(struct winbindd_response);
|
||||
|
||||
state->mem_ctx = talloc_init("winbind request");
|
||||
if (state->mem_ctx == NULL)
|
||||
return;
|
||||
|
||||
/* Process command */
|
||||
|
||||
for (table = dispatch_table; table->fn; table++) {
|
||||
if (state->request.cmd == table->cmd) {
|
||||
DEBUG(10,("process_request: request fn %s\n", table->winbindd_cmd_name ));
|
||||
DEBUG(10,("process_request: request fn %s\n",
|
||||
table->winbindd_cmd_name ));
|
||||
state->response.result = table->fn(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!table->fn)
|
||||
DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd ));
|
||||
if (!table->fn) {
|
||||
DEBUG(10,("process_request: unknown request fn number %d\n",
|
||||
(int)state->request.cmd ));
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
state->response.length = sizeof(struct winbindd_response);
|
||||
static struct fd_event *fd_events = NULL;
|
||||
|
||||
void add_fd_event(struct fd_event *ev)
|
||||
{
|
||||
struct fd_event *match;
|
||||
|
||||
/* only add unique fd_event structs */
|
||||
|
||||
for (match=fd_events; match; match=match->next ) {
|
||||
#ifdef DEVELOPER
|
||||
SMB_ASSERT( match != ev );
|
||||
#else
|
||||
if ( match == ev )
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
DLIST_ADD(fd_events, ev);
|
||||
}
|
||||
|
||||
void remove_fd_event(struct fd_event *ev)
|
||||
{
|
||||
DLIST_REMOVE(fd_events, ev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for fd_events to complete a read/write request, set up by
|
||||
* setup_async_read/setup_async_write.
|
||||
*/
|
||||
|
||||
static void rw_callback(struct fd_event *event, int flags)
|
||||
{
|
||||
size_t todo;
|
||||
ssize_t done = 0;
|
||||
|
||||
todo = event->length - event->done;
|
||||
|
||||
if (event->flags & EVENT_FD_WRITE) {
|
||||
SMB_ASSERT(flags == EVENT_FD_WRITE);
|
||||
done = sys_write(event->fd,
|
||||
&((char *)event->data)[event->done],
|
||||
todo);
|
||||
|
||||
if (done <= 0) {
|
||||
event->flags = 0;
|
||||
event->finished(event->private, False);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->flags & EVENT_FD_READ) {
|
||||
SMB_ASSERT(flags == EVENT_FD_READ);
|
||||
done = sys_read(event->fd, &((char *)event->data)[event->done],
|
||||
todo);
|
||||
|
||||
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 */
|
||||
@@ -348,16 +588,22 @@ static void new_connection(int listen_sock, BOOL privileged)
|
||||
|
||||
/* Create new connection structure */
|
||||
|
||||
if ((state = SMB_MALLOC_P(struct winbindd_cli_state)) == NULL)
|
||||
if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL)
|
||||
return;
|
||||
|
||||
ZERO_STRUCTP(state);
|
||||
state->sock = sock;
|
||||
|
||||
state->last_access = time(NULL);
|
||||
|
||||
state->privileged = privileged;
|
||||
|
||||
state->fd_event.fd = state->sock;
|
||||
state->fd_event.flags = 0;
|
||||
add_fd_event(&state->fd_event);
|
||||
|
||||
setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
|
||||
request_len_recv, state);
|
||||
|
||||
/* Add to connection list */
|
||||
|
||||
winbindd_add_client(state);
|
||||
@@ -385,10 +631,17 @@ static void remove_client(struct winbindd_cli_state *state)
|
||||
|
||||
SAFE_FREE(state->response.extra_data);
|
||||
|
||||
if (state->mem_ctx != NULL) {
|
||||
talloc_destroy(state->mem_ctx);
|
||||
state->mem_ctx = NULL;
|
||||
}
|
||||
|
||||
remove_fd_event(&state->fd_event);
|
||||
|
||||
/* Remove from list and free */
|
||||
|
||||
winbindd_remove_client(state);
|
||||
SAFE_FREE(state);
|
||||
talloc_free(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +656,8 @@ static BOOL remove_idle_client(void)
|
||||
|
||||
for (state = winbindd_client_list(); state; state = state->next) {
|
||||
if (state->read_buf_len == 0 && state->write_buf_len == 0 &&
|
||||
!state->getpwent_state && !state->getgrent_state) {
|
||||
state->response.result != WINBINDD_PENDING &&
|
||||
!state->getpwent_state && !state->getgrent_state) {
|
||||
nidle++;
|
||||
if (!last_access || state->last_access < last_access) {
|
||||
last_access = state->last_access;
|
||||
@@ -446,124 +700,6 @@ void winbind_process_packet(struct winbindd_cli_state *state)
|
||||
}
|
||||
}
|
||||
|
||||
/* Read some data from a client connection */
|
||||
|
||||
void winbind_client_read(struct winbindd_cli_state *state)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Read data */
|
||||
|
||||
n = sys_read(state->sock, state->read_buf_len +
|
||||
(char *)&state->request,
|
||||
sizeof(state->request) - state->read_buf_len);
|
||||
|
||||
DEBUG(10,("client_read: read %d bytes. Need %ld more for a full request.\n", n, (unsigned long)(sizeof(state->request) - n - state->read_buf_len) ));
|
||||
|
||||
/* Read failed, kill client */
|
||||
|
||||
if (n == -1 || n == 0) {
|
||||
DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
|
||||
state->sock, (unsigned long)state->pid,
|
||||
(n == -1) ? strerror(errno) : "EOF"));
|
||||
|
||||
state->finished = True;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->read_buf_len += n;
|
||||
state->last_access = time(NULL);
|
||||
}
|
||||
|
||||
/* Write some data to a client connection */
|
||||
|
||||
static void client_write(struct winbindd_cli_state *state)
|
||||
{
|
||||
char *data;
|
||||
int num_written;
|
||||
|
||||
/* Write some data */
|
||||
/*
|
||||
* The fancy calculation of data below allows us to handle the
|
||||
* case where write (sys_write) does not write all the data we
|
||||
* gave it. In that case, we will come back through here again
|
||||
* because of the loop above us, and we want to pick up where
|
||||
* we left off.
|
||||
*/
|
||||
|
||||
if (!state->write_extra_data) {
|
||||
|
||||
/* Write response structure */
|
||||
|
||||
data = (char *)&state->response + sizeof(state->response) -
|
||||
state->write_buf_len;
|
||||
|
||||
} else {
|
||||
|
||||
/* Write extra data */
|
||||
|
||||
data = (char *)state->response.extra_data +
|
||||
state->response.length -
|
||||
sizeof(struct winbindd_response) -
|
||||
state->write_buf_len;
|
||||
}
|
||||
|
||||
num_written = sys_write(state->sock, data, state->write_buf_len);
|
||||
|
||||
DEBUG(10,("client_write: wrote %d bytes.\n", num_written ));
|
||||
|
||||
/* Write failed, kill cilent */
|
||||
|
||||
if (num_written == -1 || num_written == 0) {
|
||||
|
||||
DEBUG(3,("write failed on sock %d, pid %lu: %s\n",
|
||||
state->sock, (unsigned long)state->pid,
|
||||
(num_written == -1) ? strerror(errno) : "EOF"));
|
||||
|
||||
state->finished = True;
|
||||
|
||||
SAFE_FREE(state->response.extra_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->write_buf_len -= num_written;
|
||||
state->last_access = time(NULL);
|
||||
|
||||
/* Have we written all data? */
|
||||
|
||||
if (state->write_buf_len == 0) {
|
||||
|
||||
/* Take care of extra data */
|
||||
|
||||
if (state->write_extra_data) {
|
||||
|
||||
SAFE_FREE(state->response.extra_data);
|
||||
|
||||
state->write_extra_data = False;
|
||||
|
||||
DEBUG(10,("client_write: client_write: complete response written.\n"));
|
||||
|
||||
} else if (state->response.length >
|
||||
sizeof(struct winbindd_response)) {
|
||||
|
||||
/* Start writing extra data */
|
||||
|
||||
state->write_buf_len =
|
||||
state->response.length -
|
||||
sizeof(struct winbindd_response);
|
||||
|
||||
DEBUG(10,("client_write: need to write %d extra data bytes.\n", (int)state->write_buf_len));
|
||||
|
||||
state->write_extra_data = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process incoming clients on listen_sock. We use a tricky non-blocking,
|
||||
non-forking, non-threaded model which allows us to handle many
|
||||
simultaneous connections while remaining impervious to many denial of
|
||||
@@ -571,211 +707,182 @@ static void client_write(struct winbindd_cli_state *state)
|
||||
|
||||
static void process_loop(void)
|
||||
{
|
||||
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 */
|
||||
|
||||
while (1) {
|
||||
struct winbindd_cli_state *state;
|
||||
fd_set r_fds, w_fds;
|
||||
int maxfd, listen_sock, listen_priv_sock, selret;
|
||||
struct timeval timeout;
|
||||
/* Handle messages */
|
||||
|
||||
again:
|
||||
/* Handle messages */
|
||||
message_dispatch();
|
||||
|
||||
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();
|
||||
main_loop_talloc_free();
|
||||
|
||||
lp_talloc_free();
|
||||
main_loop_talloc_free();
|
||||
/* Initialise fd lists for select() */
|
||||
|
||||
/* Initialise fd lists for select() */
|
||||
listen_sock = open_winbindd_socket();
|
||||
listen_priv_sock = open_winbindd_priv_socket();
|
||||
|
||||
listen_sock = open_winbindd_socket();
|
||||
listen_priv_sock = open_winbindd_priv_socket();
|
||||
if (listen_sock == -1 || listen_priv_sock == -1) {
|
||||
perror("open_winbind_socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen_sock == -1 || listen_priv_sock == -1) {
|
||||
perror("open_winbind_socket");
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (ev->flags & EVENT_FD_WRITE) {
|
||||
FD_SET(ev->fd, &w_fds);
|
||||
maxfd = MAX(ev->fd, maxfd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up client readers and writers */
|
||||
/* Call select */
|
||||
|
||||
state = winbindd_client_list();
|
||||
selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
|
||||
|
||||
while (state) {
|
||||
if (selret == 0)
|
||||
goto no_fds_ready;
|
||||
|
||||
/* Dispose of client connection if it is marked as
|
||||
finished */
|
||||
if ((selret == -1 && errno != EINTR) || selret == 0) {
|
||||
|
||||
if (state->finished) {
|
||||
struct winbindd_cli_state *next = state->next;
|
||||
/* Select error, something is badly wrong */
|
||||
|
||||
remove_client(state);
|
||||
state = next;
|
||||
continue;
|
||||
}
|
||||
perror("select");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Select requires we know the highest fd used */
|
||||
/* Create a new connection if listen_sock readable */
|
||||
|
||||
if (state->sock > maxfd)
|
||||
maxfd = state->sock;
|
||||
if (opt_dual_daemon) {
|
||||
dual_select(&w_fds);
|
||||
}
|
||||
|
||||
/* Add fd for reading */
|
||||
ev = fd_events;
|
||||
while (ev != NULL) {
|
||||
struct fd_event *next = ev->next;
|
||||
int flags = 0;
|
||||
if (FD_ISSET(ev->fd, &r_fds))
|
||||
flags |= EVENT_FD_READ;
|
||||
if (FD_ISSET(ev->fd, &w_fds))
|
||||
flags |= EVENT_FD_WRITE;
|
||||
if (flags)
|
||||
ev->handler(ev, flags);
|
||||
ev = next;
|
||||
}
|
||||
|
||||
if (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);
|
||||
|
||||
if (selret == 0)
|
||||
continue;
|
||||
|
||||
if ((selret == -1 && errno != EINTR) || selret == 0) {
|
||||
|
||||
/* Select error, something is badly wrong */
|
||||
|
||||
perror("select");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Create a new connection if listen_sock readable */
|
||||
|
||||
if (selret > 0) {
|
||||
|
||||
if (opt_dual_daemon) {
|
||||
dual_select(&w_fds);
|
||||
}
|
||||
|
||||
if (FD_ISSET(listen_sock, &r_fds)) {
|
||||
while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
|
||||
DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
if (!remove_idle_client()) {
|
||||
DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new, non-privileged connection */
|
||||
new_connection(listen_sock, False);
|
||||
}
|
||||
|
||||
if (FD_ISSET(listen_priv_sock, &r_fds)) {
|
||||
while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
|
||||
DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
if (!remove_idle_client()) {
|
||||
DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new, privileged connection */
|
||||
new_connection(listen_priv_sock, True);
|
||||
}
|
||||
|
||||
/* Process activity on client connections */
|
||||
|
||||
for (state = winbindd_client_list(); state;
|
||||
state = state->next) {
|
||||
|
||||
/* Data available for writing */
|
||||
|
||||
if (FD_ISSET(state->sock, &w_fds))
|
||||
client_write(state);
|
||||
}
|
||||
|
||||
for (state = winbindd_client_list(); state;
|
||||
state = state->next) {
|
||||
|
||||
/* Data available for reading */
|
||||
|
||||
if (FD_ISSET(state->sock, &r_fds)) {
|
||||
|
||||
/* Read data */
|
||||
|
||||
winbind_client_read(state);
|
||||
|
||||
/*
|
||||
* If we have the start of a
|
||||
* packet, then check the
|
||||
* length field to make sure
|
||||
* the client's not talking
|
||||
* Mock Swedish.
|
||||
*/
|
||||
|
||||
if (state->read_buf_len >= sizeof(uint32)
|
||||
&& *(uint32 *) &state->request != sizeof(state->request)) {
|
||||
DEBUG(0,("process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld\n",
|
||||
(unsigned long)state->request.pid, *(uint32 *) &state->request, (unsigned long)sizeof(state->request)));
|
||||
DEBUGADD(0, ("This usually means that you are running old wbinfo, pam_winbind or libnss_winbind clients\n"));
|
||||
|
||||
remove_client(state);
|
||||
break;
|
||||
}
|
||||
|
||||
/* A request packet might be
|
||||
complete */
|
||||
|
||||
if (state->read_buf_len ==
|
||||
sizeof(state->request)) {
|
||||
winbind_process_packet(state);
|
||||
winbindd_demote_client(state);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(listen_sock, &r_fds)) {
|
||||
while (winbindd_num_clients() >
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
|
||||
DEBUG(5,("winbindd: Exceeding %d client "
|
||||
"connections, removing idle "
|
||||
"connection.\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
if (!remove_idle_client()) {
|
||||
DEBUG(0,("winbindd: Exceeding %d "
|
||||
"client connections, no idle "
|
||||
"connection found\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new, non-privileged connection */
|
||||
new_connection(listen_sock, False);
|
||||
}
|
||||
|
||||
if (FD_ISSET(listen_priv_sock, &r_fds)) {
|
||||
while (winbindd_num_clients() >
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
|
||||
DEBUG(5,("winbindd: Exceeding %d client "
|
||||
"connections, removing idle "
|
||||
"connection.\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
if (!remove_idle_client()) {
|
||||
DEBUG(0,("winbindd: Exceeding %d "
|
||||
"client connections, no idle "
|
||||
"connection found\n",
|
||||
WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new, privileged connection */
|
||||
new_connection(listen_priv_sock, True);
|
||||
}
|
||||
|
||||
no_fds_ready:
|
||||
|
||||
#if 0
|
||||
winbindd_check_cache_size(time(NULL));
|
||||
winbindd_check_cache_size(time(NULL));
|
||||
#endif
|
||||
|
||||
/* Check signal handling things */
|
||||
/* Check signal handling things */
|
||||
|
||||
if (do_sigterm)
|
||||
terminate();
|
||||
if (do_sigterm)
|
||||
terminate();
|
||||
|
||||
if (do_sighup) {
|
||||
if (do_sighup) {
|
||||
|
||||
DEBUG(3, ("got SIGHUP\n"));
|
||||
DEBUG(3, ("got SIGHUP\n"));
|
||||
|
||||
msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
|
||||
do_sighup = False;
|
||||
}
|
||||
msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0);
|
||||
do_sighup = False;
|
||||
}
|
||||
|
||||
if (do_sigusr2) {
|
||||
print_winbindd_status();
|
||||
do_sigusr2 = False;
|
||||
if (do_sigusr2) {
|
||||
print_winbindd_status();
|
||||
do_sigusr2 = False;
|
||||
}
|
||||
|
||||
if (do_sigchld) {
|
||||
pid_t pid;
|
||||
|
||||
do_sigchld = False;
|
||||
|
||||
while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
|
||||
winbind_child_died(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -787,7 +894,6 @@ struct winbindd_state server_state; /* Server state information */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pstring logfile;
|
||||
static BOOL interactive = False;
|
||||
static BOOL Fork = True;
|
||||
static BOOL log_stdout = False;
|
||||
struct poptOption long_options[] = {
|
||||
@@ -886,7 +992,7 @@ int main(int argc, char **argv)
|
||||
if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
|
||||
(!idmap_init(lp_idmap_backend())) ) {
|
||||
DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
|
||||
idmap_proxyonly();
|
||||
idmap_set_proxyonly();
|
||||
}
|
||||
|
||||
/* Unblock all signals we are interested in as they may have been
|
||||
@@ -948,9 +1054,12 @@ int main(int argc, char **argv)
|
||||
|
||||
init_domain_list();
|
||||
|
||||
init_idmap_child();
|
||||
|
||||
/* Loop waiting for requests */
|
||||
|
||||
process_loop();
|
||||
while (1)
|
||||
process_loop();
|
||||
|
||||
trustdom_cache_shutdown();
|
||||
|
||||
|
||||
@@ -32,11 +32,25 @@
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
|
||||
/* Client state structure */
|
||||
/* bits for fd_event.flags */
|
||||
#define EVENT_FD_READ 1
|
||||
#define EVENT_FD_WRITE 2
|
||||
|
||||
struct fd_event {
|
||||
struct fd_event *next, *prev;
|
||||
int fd;
|
||||
int flags; /* see EVENT_FD_* flags */
|
||||
void (*handler)(struct fd_event *fde, int flags);
|
||||
void *data;
|
||||
size_t length, done;
|
||||
void (*finished)(void *private, BOOL success);
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct winbindd_cli_state {
|
||||
struct winbindd_cli_state *prev, *next; /* Linked list pointers */
|
||||
int sock; /* Open socket from client */
|
||||
struct fd_event fd_event;
|
||||
pid_t pid; /* pid of client */
|
||||
int read_buf_len, write_buf_len; /* Indexes in request/response */
|
||||
BOOL finished; /* Can delete from list */
|
||||
@@ -44,10 +58,13 @@ struct winbindd_cli_state {
|
||||
time_t last_access; /* Time of last access (read or write) */
|
||||
BOOL privileged; /* Is the client 'privileged' */
|
||||
|
||||
TALLOC_CTX *mem_ctx; /* memory per request */
|
||||
struct winbindd_request request; /* Request from client */
|
||||
struct winbindd_response response; /* Respose to client */
|
||||
BOOL getpwent_initialized; /* Has getpwent_state been initialized? */
|
||||
BOOL getgrent_initialized; /* Has getgrent_state been initialized? */
|
||||
BOOL getpwent_initialized; /* Has getpwent_state been
|
||||
* initialized? */
|
||||
BOOL getgrent_initialized; /* Has getgrent_state been
|
||||
* initialized? */
|
||||
struct getent_state *getpwent_state; /* State for getpwent() */
|
||||
struct getent_state *getgrent_state; /* State for getgrent() */
|
||||
};
|
||||
@@ -81,15 +98,56 @@ struct winbindd_state {
|
||||
gid_t gid_low, gid_high; /* Range of gids to allocate */
|
||||
};
|
||||
|
||||
struct winbindd_dispatch_table {
|
||||
enum winbindd_cmd cmd;
|
||||
enum winbindd_result (*fn)(struct winbindd_cli_state *state);
|
||||
const char *winbindd_cmd_name;
|
||||
};
|
||||
|
||||
extern struct winbindd_state server_state; /* Server information */
|
||||
|
||||
typedef struct {
|
||||
char *acct_name;
|
||||
char *full_name;
|
||||
DOM_SID *user_sid; /* NT user and primary group SIDs */
|
||||
DOM_SID *group_sid;
|
||||
DOM_SID user_sid; /* NT user and primary group SIDs */
|
||||
DOM_SID group_sid;
|
||||
} WINBIND_USERINFO;
|
||||
|
||||
/* Our connection to the DC */
|
||||
|
||||
struct winbindd_cm_conn {
|
||||
struct cli_state *cli;
|
||||
|
||||
struct rpc_pipe_client *samr_pipe;
|
||||
POLICY_HND sam_connect_handle, sam_domain_handle;
|
||||
|
||||
struct rpc_pipe_client *lsa_pipe;
|
||||
POLICY_HND lsa_policy;
|
||||
|
||||
/* Auth2 pipe is the pipe used to setup the netlogon schannel key
|
||||
* using rpccli_net_auth2. It needs to be kept open. */
|
||||
|
||||
struct rpc_pipe_client *netlogon_auth2_pipe;
|
||||
unsigned char sess_key[16]; /* Current session key. */
|
||||
DOM_CRED clnt_cred; /* Client NETLOGON credential. */
|
||||
struct rpc_pipe_client *netlogon_pipe;
|
||||
};
|
||||
|
||||
struct winbindd_async_request;
|
||||
|
||||
/* Async child */
|
||||
|
||||
struct winbindd_child {
|
||||
struct winbindd_child *next, *prev;
|
||||
|
||||
pid_t pid;
|
||||
struct winbindd_domain *domain;
|
||||
pstring logfilename;
|
||||
|
||||
struct fd_event event;
|
||||
struct winbindd_async_request *requests;
|
||||
};
|
||||
|
||||
/* Structures to hold per domain information */
|
||||
|
||||
struct winbindd_domain {
|
||||
@@ -123,6 +181,14 @@ struct winbindd_domain {
|
||||
uint32 sequence_number;
|
||||
NTSTATUS last_status;
|
||||
|
||||
/* The smb connection */
|
||||
|
||||
struct winbindd_cm_conn conn;
|
||||
|
||||
/* The child pid we're talking to */
|
||||
|
||||
struct winbindd_child child;
|
||||
|
||||
/* Linked list info */
|
||||
|
||||
struct winbindd_domain *prev, *next;
|
||||
@@ -181,13 +247,14 @@ struct winbindd_methods {
|
||||
NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *user_sid,
|
||||
uint32 *num_groups, DOM_SID ***user_gids);
|
||||
uint32 *num_groups, DOM_SID **user_gids);
|
||||
|
||||
/* Lookup all aliases that the sids delivered are member of. This is
|
||||
* to implement 'domain local groups' correctly */
|
||||
NTSTATUS (*lookup_useraliases)(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32 num_sids, DOM_SID **sids,
|
||||
uint32 num_sids,
|
||||
const DOM_SID *sids,
|
||||
uint32 *num_aliases,
|
||||
uint32 **alias_rids);
|
||||
|
||||
@@ -196,7 +263,7 @@ struct winbindd_methods {
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *group_sid,
|
||||
uint32 *num_names,
|
||||
DOM_SID ***sid_mem, char ***names,
|
||||
DOM_SID **sid_mem, char ***names,
|
||||
uint32 **name_types);
|
||||
|
||||
/* return the current global sequence number */
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
#ifdef HAVE_ADS
|
||||
|
||||
extern struct winbindd_methods msrpc_methods, cache_methods;
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
|
||||
@@ -78,6 +76,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
|
||||
|
||||
status = ads_connect(ads);
|
||||
if (!ADS_ERR_OK(status) || !ads->config.realm) {
|
||||
extern struct winbindd_methods msrpc_methods, cache_methods;
|
||||
DEBUG(1,("ads_connect for domain %s failed: %s\n",
|
||||
domain->name, ads_errstr(status)));
|
||||
ads_destroy(&ads);
|
||||
@@ -157,9 +156,6 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
|
||||
|
||||
for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
|
||||
char *name, *gecos;
|
||||
DOM_SID sid;
|
||||
DOM_SID *sid2;
|
||||
DOM_SID *group_sid;
|
||||
uint32 group;
|
||||
uint32 atype;
|
||||
|
||||
@@ -171,7 +167,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
|
||||
|
||||
name = ads_pull_username(ads, mem_ctx, msg);
|
||||
gecos = ads_pull_string(ads, mem_ctx, msg, "name");
|
||||
if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
|
||||
if (!ads_pull_sid(ads, msg, "objectSid",
|
||||
&(*info)[i].user_sid)) {
|
||||
DEBUG(1,("No sid for %s !?\n", name));
|
||||
continue;
|
||||
}
|
||||
@@ -180,20 +177,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
|
||||
continue;
|
||||
}
|
||||
|
||||
sid2 = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!sid2) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sid_copy(sid2, &sid);
|
||||
|
||||
group_sid = rid_to_talloced_sid(domain, mem_ctx, group);
|
||||
|
||||
(*info)[i].acct_name = name;
|
||||
(*info)[i].full_name = gecos;
|
||||
(*info)[i].user_sid = sid2;
|
||||
(*info)[i].group_sid = group_sid;
|
||||
sid_compose(&(*info)[i].group_sid, &domain->sid, group);
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -386,8 +372,6 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
|
||||
char *sidstr;
|
||||
uint32 group_rid;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
DOM_SID *sid2;
|
||||
fstring sid_string;
|
||||
|
||||
DEBUG(3,("ads: query_user\n"));
|
||||
|
||||
@@ -404,13 +388,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
|
||||
free(ldap_exp);
|
||||
free(sidstr);
|
||||
if (!ADS_ERR_OK(rc) || !msg) {
|
||||
DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc)));
|
||||
DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
|
||||
sid_string_static(sid), ads_errstr(rc)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
count = ads_count_replies(ads, msg);
|
||||
if (count != 1) {
|
||||
DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid)));
|
||||
DEBUG(1,("query_user(sid=%s): Not found\n",
|
||||
sid_string_static(sid)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -418,20 +404,13 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
|
||||
info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
|
||||
|
||||
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
|
||||
DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid)));
|
||||
DEBUG(1,("No primary group for %s !?\n",
|
||||
sid_string_static(sid)));
|
||||
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;
|
||||
|
||||
@@ -449,7 +428,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *user_dn,
|
||||
DOM_SID *primary_group,
|
||||
uint32 *num_groups, DOM_SID ***user_gids)
|
||||
uint32 *num_groups, DOM_SID **user_sids)
|
||||
{
|
||||
ADS_STATUS rc;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
@@ -502,12 +481,13 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
|
||||
goto done;
|
||||
}
|
||||
|
||||
(*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
|
||||
(*user_gids)[0] = primary_group;
|
||||
*user_sids = NULL;
|
||||
*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;
|
||||
|
||||
if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
|
||||
@@ -515,21 +495,10 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sid_equal(&group_sid, primary_group)) continue;
|
||||
|
||||
(*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!(*user_gids)[*num_groups]) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sid_copy((*user_gids)[*num_groups], &group_sid);
|
||||
|
||||
(*num_groups)++;
|
||||
|
||||
add_sid_to_array(mem_ctx, &group_sid, user_sids, num_groups);
|
||||
}
|
||||
|
||||
status = NT_STATUS_OK;
|
||||
status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
|
||||
|
||||
DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn));
|
||||
done:
|
||||
@@ -543,7 +512,7 @@ done:
|
||||
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *sid,
|
||||
uint32 *num_groups, DOM_SID ***user_gids)
|
||||
uint32 *num_groups, DOM_SID **user_sids)
|
||||
{
|
||||
ADS_STRUCT *ads = NULL;
|
||||
const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
|
||||
@@ -553,7 +522,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
char *user_dn;
|
||||
DOM_SID *sids;
|
||||
int i;
|
||||
DOM_SID *primary_group;
|
||||
DOM_SID primary_group;
|
||||
uint32 primary_group_rid;
|
||||
fstring sid_string;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
@@ -596,7 +565,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
goto done;
|
||||
}
|
||||
|
||||
primary_group = rid_to_talloced_sid(domain, mem_ctx, primary_group_rid);
|
||||
sid_copy(&primary_group, &domain->sid);
|
||||
sid_append_rid(&primary_group, primary_group_rid);
|
||||
|
||||
count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
|
||||
|
||||
@@ -607,30 +577,23 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
unless we are talking to a buggy Win2k server */
|
||||
if (count == 0) {
|
||||
return lookup_usergroups_alt(domain, mem_ctx, user_dn,
|
||||
primary_group,
|
||||
num_groups, user_gids);
|
||||
&primary_group,
|
||||
num_groups, user_sids);
|
||||
}
|
||||
|
||||
(*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1);
|
||||
(*user_gids)[0] = primary_group;
|
||||
*user_sids = NULL;
|
||||
*num_groups = 0;
|
||||
|
||||
*num_groups = 1;
|
||||
add_sid_to_array(mem_ctx, &primary_group, user_sids, num_groups);
|
||||
|
||||
for (i=0;i<count;i++) {
|
||||
if (sid_equal(&sids[i], primary_group)) continue;
|
||||
for (i=0;i<count;i++)
|
||||
add_sid_to_array_unique(mem_ctx, &sids[i],
|
||||
user_sids, num_groups);
|
||||
|
||||
(*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!(*user_gids)[*num_groups]) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
|
||||
|
||||
sid_copy((*user_gids)[*num_groups], &sids[i]);
|
||||
(*num_groups)++;
|
||||
}
|
||||
|
||||
status = NT_STATUS_OK;
|
||||
DEBUG(3,("ads lookup_usergroups for sid=%s\n", sid_to_string(sid_string, sid)));
|
||||
DEBUG(3,("ads lookup_usergroups for sid=%s\n",
|
||||
sid_to_string(sid_string, sid)));
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
@@ -641,7 +604,7 @@ done:
|
||||
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *group_sid, uint32 *num_names,
|
||||
DOM_SID ***sid_mem, char ***names,
|
||||
DOM_SID **sid_mem, char ***names,
|
||||
uint32 **name_types)
|
||||
{
|
||||
ADS_STATUS rc;
|
||||
@@ -652,8 +615,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
char *sidstr;
|
||||
char **members;
|
||||
int i;
|
||||
size_t num_members;
|
||||
int i, num_members;
|
||||
fstring sid_string;
|
||||
BOOL more_values;
|
||||
const char **attrs;
|
||||
@@ -753,7 +715,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
the problem is that the members are in the form of distinguised names
|
||||
*/
|
||||
|
||||
(*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, num_members);
|
||||
(*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
|
||||
(*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
|
||||
(*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
|
||||
|
||||
@@ -765,12 +727,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) {
|
||||
(*names)[*num_names] = name;
|
||||
(*name_types)[*num_names] = name_type;
|
||||
(*sid_mem)[*num_names] = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!(*sid_mem)[*num_names]) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
sid_copy((*sid_mem)[*num_names], &sid);
|
||||
sid_copy(&(*sid_mem)[*num_names], &sid);
|
||||
(*num_names)++;
|
||||
}
|
||||
}
|
||||
@@ -827,9 +784,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
|
||||
struct ds_domain_trust *domains = NULL;
|
||||
int count = 0;
|
||||
int i;
|
||||
struct cli_state *cli = NULL;
|
||||
/* i think we only need our forest and downlevel trusted domains */
|
||||
uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
|
||||
struct rpc_pipe_client *cli;
|
||||
|
||||
DEBUG(3,("ads: trusted_domains\n"));
|
||||
|
||||
@@ -838,15 +795,26 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
|
||||
*names = NULL;
|
||||
*dom_sids = NULL;
|
||||
|
||||
if ( !NT_STATUS_IS_OK(result = cm_fresh_connection(domain, PI_NETLOGON, &cli)) ) {
|
||||
DEBUG(5, ("trusted_domains: Could not open a connection to %s for PIPE_NETLOGON (%s)\n",
|
||||
{
|
||||
unsigned char *session_key;
|
||||
DOM_CRED *creds;
|
||||
|
||||
result = cm_connect_netlogon(domain, mem_ctx, &cli,
|
||||
&session_key, &creds);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(5, ("trusted_domains: Could not open a connection to %s "
|
||||
"for PIPE_NETLOGON (%s)\n",
|
||||
domain->name, nt_errstr(result)));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if ( NT_STATUS_IS_OK(result) )
|
||||
result = cli_ds_enum_domain_trusts( cli, mem_ctx, cli->desthost,
|
||||
flags, &domains, (unsigned int *)&count );
|
||||
result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
|
||||
cli->cli->desthost,
|
||||
flags, &domains,
|
||||
(unsigned int *)&count);
|
||||
|
||||
if ( NT_STATUS_IS_OK(result) && count) {
|
||||
|
||||
@@ -854,20 +822,17 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
|
||||
|
||||
if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
|
||||
DEBUG(0, ("trusted_domains: out of memory\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
|
||||
DEBUG(0, ("trusted_domains: out of memory\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
|
||||
DEBUG(0, ("trusted_domains: out of memory\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Copy across names and sids */
|
||||
@@ -882,13 +847,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
|
||||
*num_domains = count;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* remove connection; This is a special case to the \NETLOGON pipe */
|
||||
|
||||
if ( cli )
|
||||
cli_shutdown( cli );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
1403
source/nsswitch/winbindd_async.c
Normal file
1403
source/nsswitch/winbindd_async.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -26,12 +26,6 @@
|
||||
#include "includes.h"
|
||||
#include "winbindd.h"
|
||||
|
||||
extern BOOL opt_nocache;
|
||||
extern struct winbindd_methods msrpc_methods;
|
||||
extern struct winbindd_methods ads_methods;
|
||||
extern BOOL opt_dual_daemon;
|
||||
extern BOOL background_process;
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
|
||||
@@ -53,6 +47,8 @@ static struct winbind_cache *wcache;
|
||||
/* flush the cache */
|
||||
void wcache_flush_cache(void)
|
||||
{
|
||||
extern BOOL opt_nocache;
|
||||
|
||||
if (!wcache)
|
||||
return;
|
||||
if (wcache->tdb) {
|
||||
@@ -106,9 +102,11 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
|
||||
struct winbind_cache *ret = wcache;
|
||||
|
||||
if (!domain->backend) {
|
||||
extern struct winbindd_methods reconnect_methods;
|
||||
switch (lp_security()) {
|
||||
#ifdef HAVE_ADS
|
||||
case SEC_ADS: {
|
||||
extern struct winbindd_methods ads_methods;
|
||||
/* always obey the lp_security parameter for our domain */
|
||||
if (domain->primary) {
|
||||
domain->backend = &ads_methods;
|
||||
@@ -132,7 +130,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
|
||||
default:
|
||||
DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
|
||||
domain->name));
|
||||
domain->backend = &msrpc_methods;
|
||||
domain->backend = &reconnect_methods;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +210,10 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
|
||||
smb_panic("centry_string");
|
||||
}
|
||||
|
||||
ret = TALLOC(mem_ctx, len+1);
|
||||
if (mem_ctx != NULL)
|
||||
ret = TALLOC(mem_ctx, len+1);
|
||||
else
|
||||
ret = SMB_MALLOC(len+1);
|
||||
if (!ret) {
|
||||
smb_panic("centry_string out of memory\n");
|
||||
}
|
||||
@@ -225,20 +226,15 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
|
||||
/* pull a string from a cache entry, using the supplied
|
||||
talloc context
|
||||
*/
|
||||
static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
|
||||
static BOOL centry_sid(struct cache_entry *centry, DOM_SID *sid)
|
||||
{
|
||||
DOM_SID *sid;
|
||||
char *sid_string;
|
||||
|
||||
sid = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!sid)
|
||||
return NULL;
|
||||
|
||||
sid_string = centry_string(centry, mem_ctx);
|
||||
sid_string = centry_string(centry, NULL);
|
||||
if (!string_to_sid(sid, sid_string)) {
|
||||
return NULL;
|
||||
return False;
|
||||
}
|
||||
return sid;
|
||||
SAFE_FREE(sid_string);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* the server is considered down if it can't give us a sequence number */
|
||||
@@ -471,11 +467,13 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
|
||||
centry->sequence_number = centry_uint32(centry);
|
||||
|
||||
if (centry_expired(domain, kstr, centry)) {
|
||||
extern BOOL opt_dual_daemon;
|
||||
|
||||
DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
|
||||
kstr, domain->name ));
|
||||
|
||||
if (opt_dual_daemon) {
|
||||
extern BOOL background_process;
|
||||
background_process = True;
|
||||
DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
|
||||
kstr, domain->name ));
|
||||
@@ -654,9 +652,9 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI
|
||||
return;
|
||||
centry_put_string(centry, info->acct_name);
|
||||
centry_put_string(centry, info->full_name);
|
||||
centry_put_sid(centry, info->user_sid);
|
||||
centry_put_sid(centry, info->group_sid);
|
||||
centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid));
|
||||
centry_put_sid(centry, &info->user_sid);
|
||||
centry_put_sid(centry, &info->group_sid);
|
||||
centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
|
||||
DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
|
||||
centry_free(centry);
|
||||
}
|
||||
@@ -691,8 +689,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
|
||||
for (i=0; i<(*num_entries); i++) {
|
||||
(*info)[i].acct_name = centry_string(centry, mem_ctx);
|
||||
(*info)[i].full_name = centry_string(centry, mem_ctx);
|
||||
(*info)[i].user_sid = centry_sid(centry, mem_ctx);
|
||||
(*info)[i].group_sid = centry_sid(centry, mem_ctx);
|
||||
centry_sid(centry, &(*info)[i].user_sid);
|
||||
centry_sid(centry, &(*info)[i].group_sid);
|
||||
}
|
||||
|
||||
do_cached:
|
||||
@@ -729,10 +727,12 @@ do_query:
|
||||
|
||||
status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
|
||||
if (!NT_STATUS_IS_OK(status))
|
||||
DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status)));
|
||||
if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) {
|
||||
DEBUG(3, ("query_user_list: flushing connection cache\n"));
|
||||
winbindd_cm_flush();
|
||||
DEBUG(3, ("query_user_list: returned 0x%08x, "
|
||||
"retrying\n", NT_STATUS_V(status)));
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
|
||||
DEBUG(3, ("query_user_list: flushing "
|
||||
"connection cache\n"));
|
||||
invalidate_cm_connection(&domain->conn);
|
||||
}
|
||||
|
||||
} while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
|
||||
@@ -747,17 +747,17 @@ do_query:
|
||||
for (i=0; i<(*num_entries); i++) {
|
||||
centry_put_string(centry, (*info)[i].acct_name);
|
||||
centry_put_string(centry, (*info)[i].full_name);
|
||||
centry_put_sid(centry, (*info)[i].user_sid);
|
||||
centry_put_sid(centry, (*info)[i].group_sid);
|
||||
centry_put_sid(centry, &(*info)[i].user_sid);
|
||||
centry_put_sid(centry, &(*info)[i].group_sid);
|
||||
if (domain->backend->consistent) {
|
||||
/* when the backend is consistent we can pre-prime some mappings */
|
||||
wcache_save_name_to_sid(domain, NT_STATUS_OK,
|
||||
domain->name,
|
||||
(*info)[i].acct_name,
|
||||
(*info)[i].user_sid,
|
||||
&(*info)[i].user_sid,
|
||||
SID_NAME_USER);
|
||||
wcache_save_sid_to_name(domain, NT_STATUS_OK,
|
||||
(*info)[i].user_sid,
|
||||
&(*info)[i].user_sid,
|
||||
domain->name,
|
||||
(*info)[i].acct_name,
|
||||
SID_NAME_USER);
|
||||
@@ -939,7 +939,6 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
|
||||
struct cache_entry *centry = NULL;
|
||||
NTSTATUS status;
|
||||
fstring uname;
|
||||
DOM_SID *sid2;
|
||||
|
||||
if (!cache->tdb)
|
||||
goto do_query;
|
||||
@@ -950,13 +949,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
|
||||
if (!centry)
|
||||
goto do_query;
|
||||
*type = (enum SID_NAME_USE)centry_uint32(centry);
|
||||
sid2 = centry_sid(centry, mem_ctx);
|
||||
if (!sid2) {
|
||||
ZERO_STRUCTP(sid);
|
||||
} else {
|
||||
sid_copy(sid, sid2);
|
||||
}
|
||||
|
||||
centry_sid(centry, sid);
|
||||
status = centry->status;
|
||||
|
||||
DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
|
||||
@@ -1089,8 +1082,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
|
||||
|
||||
info->acct_name = centry_string(centry, mem_ctx);
|
||||
info->full_name = centry_string(centry, mem_ctx);
|
||||
info->user_sid = centry_sid(centry, mem_ctx);
|
||||
info->group_sid = centry_sid(centry, mem_ctx);
|
||||
centry_sid(centry, &info->user_sid);
|
||||
centry_sid(centry, &info->group_sid);
|
||||
status = centry->status;
|
||||
|
||||
DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
|
||||
@@ -1124,7 +1117,7 @@ do_query:
|
||||
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *user_sid,
|
||||
uint32 *num_groups, DOM_SID ***user_gids)
|
||||
uint32 *num_groups, DOM_SID **user_gids)
|
||||
{
|
||||
struct winbind_cache *cache = get_cache(domain);
|
||||
struct cache_entry *centry = NULL;
|
||||
@@ -1157,11 +1150,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
if (*num_groups == 0)
|
||||
goto do_cached;
|
||||
|
||||
(*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
|
||||
(*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
|
||||
if (! (*user_gids))
|
||||
smb_panic("lookup_usergroups out of memory");
|
||||
for (i=0; i<(*num_groups); i++) {
|
||||
(*user_gids)[i] = centry_sid(centry, mem_ctx);
|
||||
centry_sid(centry, &(*user_gids)[i]);
|
||||
}
|
||||
|
||||
do_cached:
|
||||
@@ -1194,7 +1187,7 @@ do_query:
|
||||
goto skip_save;
|
||||
centry_put_uint32(centry, *num_groups);
|
||||
for (i=0; i<(*num_groups); i++) {
|
||||
centry_put_sid(centry, (*user_gids)[i]);
|
||||
centry_put_sid(centry, &(*user_gids)[i]);
|
||||
}
|
||||
centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
|
||||
centry_free(centry);
|
||||
@@ -1205,7 +1198,7 @@ skip_save:
|
||||
|
||||
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32 num_sids, DOM_SID **sids,
|
||||
uint32 num_sids, const DOM_SID *sids,
|
||||
uint32 *num_aliases, uint32 **alias_rids)
|
||||
{
|
||||
struct winbind_cache *cache = get_cache(domain);
|
||||
@@ -1228,7 +1221,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
|
||||
|
||||
for (i=0; i<num_sids; i++) {
|
||||
sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
|
||||
sid_string_static(sids[i]));
|
||||
sid_string_static(&sids[i]));
|
||||
if (sidlist == NULL)
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
@@ -1265,7 +1258,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
|
||||
if (!NT_STATUS_IS_OK(domain->last_status))
|
||||
return domain->last_status;
|
||||
|
||||
DEBUG(10,("lookup_useraliases: [Cached] - doing backend query for info "
|
||||
DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
|
||||
"for domain %s\n", domain->name ));
|
||||
|
||||
status = domain->backend->lookup_useraliases(domain, mem_ctx,
|
||||
@@ -1291,7 +1284,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
|
||||
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *group_sid, uint32 *num_names,
|
||||
DOM_SID ***sid_mem, char ***names,
|
||||
DOM_SID **sid_mem, char ***names,
|
||||
uint32 **name_types)
|
||||
{
|
||||
struct winbind_cache *cache = get_cache(domain);
|
||||
@@ -1312,7 +1305,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
if (*num_names == 0)
|
||||
goto do_cached;
|
||||
|
||||
(*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_names);
|
||||
(*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
|
||||
(*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
|
||||
(*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
|
||||
|
||||
@@ -1321,7 +1314,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
}
|
||||
|
||||
for (i=0; i<(*num_names); i++) {
|
||||
(*sid_mem)[i] = centry_sid(centry, mem_ctx);
|
||||
centry_sid(centry, &(*sid_mem)[i]);
|
||||
(*names)[i] = centry_string(centry, mem_ctx);
|
||||
(*name_types)[i] = centry_uint32(centry);
|
||||
}
|
||||
@@ -1359,7 +1352,7 @@ do_query:
|
||||
goto skip_save;
|
||||
centry_put_uint32(centry, *num_names);
|
||||
for (i=0; i<(*num_names); i++) {
|
||||
centry_put_sid(centry, (*sid_mem)[i]);
|
||||
centry_put_sid(centry, &(*sid_mem)[i]);
|
||||
centry_put_string(centry, (*names)[i]);
|
||||
centry_put_uint32(centry, (*name_types)[i]);
|
||||
}
|
||||
@@ -1466,3 +1459,166 @@ struct winbindd_methods cache_methods = {
|
||||
trusted_domains,
|
||||
alternate_name
|
||||
};
|
||||
|
||||
static BOOL init_wcache(void)
|
||||
{
|
||||
if (wcache == NULL) {
|
||||
wcache = SMB_XMALLOC_P(struct winbind_cache);
|
||||
ZERO_STRUCTP(wcache);
|
||||
}
|
||||
|
||||
if (wcache->tdb != NULL)
|
||||
return True;
|
||||
|
||||
wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
|
||||
TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
|
||||
|
||||
if (wcache->tdb == NULL) {
|
||||
DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void cache_store_response(pid_t pid, struct winbindd_response *response)
|
||||
{
|
||||
fstring key_str;
|
||||
|
||||
if (!init_wcache())
|
||||
return;
|
||||
|
||||
DEBUG(10, ("Storing response for pid %d, len %d\n",
|
||||
pid, response->length));
|
||||
|
||||
fstr_sprintf(key_str, "DR/%d", pid);
|
||||
if (tdb_store(wcache->tdb, string_tdb_data(key_str),
|
||||
make_tdb_data((void *)response, sizeof(*response)),
|
||||
TDB_REPLACE) == -1)
|
||||
return;
|
||||
|
||||
if (response->length == sizeof(*response))
|
||||
return;
|
||||
|
||||
/* There's extra data */
|
||||
|
||||
DEBUG(10, ("Storing extra data: len=%d\n",
|
||||
response->length - sizeof(*response)));
|
||||
|
||||
fstr_sprintf(key_str, "DE/%d", pid);
|
||||
if (tdb_store(wcache->tdb, string_tdb_data(key_str),
|
||||
make_tdb_data(response->extra_data,
|
||||
response->length - sizeof(*response)),
|
||||
TDB_REPLACE) == 0)
|
||||
return;
|
||||
|
||||
/* We could not store the extra data, make sure the tdb does not
|
||||
* contain a main record with wrong dangling extra data */
|
||||
|
||||
fstr_sprintf(key_str, "DR/%d", pid);
|
||||
tdb_delete(wcache->tdb, string_tdb_data(key_str));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
|
||||
{
|
||||
TDB_DATA data;
|
||||
fstring key_str;
|
||||
|
||||
if (!init_wcache())
|
||||
return False;
|
||||
|
||||
DEBUG(10, ("Retrieving response for pid %d\n", pid));
|
||||
|
||||
fstr_sprintf(key_str, "DR/%d", pid);
|
||||
data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
|
||||
|
||||
if (data.dptr == NULL)
|
||||
return False;
|
||||
|
||||
if (data.dsize != sizeof(*response))
|
||||
return False;
|
||||
|
||||
memcpy(response, data.dptr, data.dsize);
|
||||
SAFE_FREE(data.dptr);
|
||||
|
||||
if (response->length == sizeof(*response)) {
|
||||
response->extra_data = NULL;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* There's extra data */
|
||||
|
||||
DEBUG(10, ("Retrieving extra data length=%d\n",
|
||||
response->length - sizeof(*response)));
|
||||
|
||||
fstr_sprintf(key_str, "DE/%d", pid);
|
||||
data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
|
||||
|
||||
if (data.dptr == NULL) {
|
||||
DEBUG(0, ("Did not find extra data\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (data.dsize != (response->length - sizeof(*response))) {
|
||||
DEBUG(0, ("Invalid extra data length: %d\n", data.dsize));
|
||||
SAFE_FREE(data.dptr);
|
||||
return False;
|
||||
}
|
||||
|
||||
response->extra_data = data.dptr;
|
||||
return True;
|
||||
}
|
||||
|
||||
char *cache_store_request_data(TALLOC_CTX *mem_ctx, char *request_string)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!init_wcache())
|
||||
return NULL;
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
char *key = talloc_strdup(mem_ctx, generate_random_str(16));
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
DEBUG(10, ("Storing request key %s\n", key));
|
||||
if (tdb_store_bystring(wcache->tdb, key,
|
||||
string_tdb_data(request_string),
|
||||
TDB_INSERT) == 0)
|
||||
return key;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *cache_retrieve_request_data(TALLOC_CTX *mem_ctx, char *key)
|
||||
{
|
||||
TDB_DATA data;
|
||||
char *result = NULL;
|
||||
|
||||
if (!init_wcache())
|
||||
return NULL;
|
||||
|
||||
DEBUG(10, ("Retrieving key %s\n", key));
|
||||
|
||||
data = tdb_fetch_bystring(wcache->tdb, key);
|
||||
if (data.dptr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (strnlen(data.dptr, data.dsize) != (data.dsize)) {
|
||||
DEBUG(0, ("Received invalid request string\n"));
|
||||
goto done;
|
||||
}
|
||||
result = TALLOC_ARRAY(mem_ctx, char, data.dsize+1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, data.dptr, data.dsize);
|
||||
result[data.dsize] = '\0';
|
||||
}
|
||||
if (tdb_delete_bystring(wcache->tdb, key) != 0) {
|
||||
DEBUG(0, ("Could not delete key %s\n", key));
|
||||
result = NULL;
|
||||
}
|
||||
done:
|
||||
SAFE_FREE(data.dptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
||||
Winbind background daemon
|
||||
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
Copyright (C) Volker Lendecke 2004,2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -51,6 +52,39 @@ struct dual_list {
|
||||
static struct dual_list *dual_list;
|
||||
static struct dual_list *dual_list_end;
|
||||
|
||||
/* Read some data from a client connection */
|
||||
|
||||
static void dual_client_read(struct winbindd_cli_state *state)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Read data */
|
||||
|
||||
n = sys_read(state->sock, state->read_buf_len +
|
||||
(char *)&state->request,
|
||||
sizeof(state->request) - state->read_buf_len);
|
||||
|
||||
DEBUG(10,("client_read: read %d bytes. Need %ld more for a full "
|
||||
"request.\n", n, (unsigned long)(sizeof(state->request) - n -
|
||||
state->read_buf_len) ));
|
||||
|
||||
/* Read failed, kill client */
|
||||
|
||||
if (n == -1 || n == 0) {
|
||||
DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
|
||||
state->sock, (unsigned long)state->pid,
|
||||
(n == -1) ? strerror(errno) : "EOF"));
|
||||
|
||||
state->finished = True;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->read_buf_len += n;
|
||||
state->last_access = time(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
setup a select() including the dual daemon pipe
|
||||
*/
|
||||
@@ -176,7 +210,7 @@ void do_dual_daemon(void)
|
||||
main_loop_talloc_free();
|
||||
|
||||
/* fetch a request from the main daemon */
|
||||
winbind_client_read(&state);
|
||||
dual_client_read(&state);
|
||||
|
||||
if (state.finished) {
|
||||
/* we lost contact with our parent */
|
||||
@@ -212,3 +246,412 @@ void do_dual_daemon(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Machinery for async requests sent to children. You set up a
|
||||
* winbindd_request, select a child to query, and issue a async_request
|
||||
* call. When the request is completed, the callback function you specified is
|
||||
* called back with the private pointer you gave to async_request.
|
||||
*/
|
||||
|
||||
struct winbindd_async_request {
|
||||
struct winbindd_async_request *next, *prev;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_child *child;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
void (*continuation)(void *private, BOOL success);
|
||||
void *private;
|
||||
};
|
||||
|
||||
static void async_request_sent(void *private, BOOL success);
|
||||
static void async_reply_recv(void *private, BOOL success);
|
||||
static void schedule_async_request(struct winbindd_child *child);
|
||||
|
||||
void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
|
||||
struct winbindd_request *request,
|
||||
struct winbindd_response *response,
|
||||
void (*continuation)(void *private, BOOL success),
|
||||
void *private)
|
||||
{
|
||||
struct winbindd_async_request *state, *tmp;
|
||||
|
||||
SMB_ASSERT(continuation != NULL);
|
||||
|
||||
state = TALLOC_P(mem_ctx, struct winbindd_async_request);
|
||||
|
||||
if (state == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
continuation(private, False);
|
||||
return;
|
||||
}
|
||||
|
||||
state->mem_ctx = mem_ctx;
|
||||
state->child = child;
|
||||
state->request = request;
|
||||
state->response = response;
|
||||
state->continuation = continuation;
|
||||
state->private = private;
|
||||
|
||||
DLIST_ADD_END(child->requests, state, tmp);
|
||||
|
||||
schedule_async_request(child);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void async_request_sent(void *private, BOOL success)
|
||||
{
|
||||
struct winbindd_async_request *state =
|
||||
talloc_get_type_abort(private, struct winbindd_async_request);
|
||||
|
||||
if (!success) {
|
||||
DEBUG(5, ("Could not send async request\n"));
|
||||
|
||||
state->response->length = sizeof(struct winbindd_response);
|
||||
state->response->result = WINBINDD_ERROR;
|
||||
state->continuation(state->private, False);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Request successfully sent to the child, setup the wait for reply */
|
||||
|
||||
setup_async_read(&state->child->event,
|
||||
&state->response->result,
|
||||
sizeof(state->response->result),
|
||||
async_reply_recv, state);
|
||||
}
|
||||
|
||||
static void async_reply_recv(void *private, BOOL success)
|
||||
{
|
||||
struct winbindd_async_request *state =
|
||||
talloc_get_type_abort(private, struct winbindd_async_request);
|
||||
struct winbindd_child *child = state->child;
|
||||
|
||||
state->response->length = sizeof(struct winbindd_response);
|
||||
|
||||
if (!success) {
|
||||
DEBUG(5, ("Could not receive async reply\n"));
|
||||
state->response->result = WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if (state->response->result == WINBINDD_OK)
|
||||
SMB_ASSERT(cache_retrieve_response(child->pid,
|
||||
state->response));
|
||||
|
||||
DLIST_REMOVE(child->requests, state);
|
||||
|
||||
schedule_async_request(child);
|
||||
|
||||
state->continuation(state->private, True);
|
||||
}
|
||||
|
||||
static BOOL fork_domain_child(struct winbindd_child *child);
|
||||
|
||||
static void schedule_async_request(struct winbindd_child *child)
|
||||
{
|
||||
struct winbindd_async_request *request = child->requests;
|
||||
|
||||
if (request == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (child->event.flags != 0) {
|
||||
return; /* Busy */
|
||||
}
|
||||
|
||||
if ((child->pid == 0) && (!fork_domain_child(child))) {
|
||||
/* Cancel all outstanding requests */
|
||||
|
||||
while (request != NULL) {
|
||||
/* request might be free'd in the continuation */
|
||||
struct winbindd_async_request *next = request->next;
|
||||
request->continuation(request->private, False);
|
||||
request = next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setup_async_write(&child->event, request->request,
|
||||
sizeof(*request->request),
|
||||
async_request_sent, request);
|
||||
return;
|
||||
}
|
||||
|
||||
struct domain_request_state {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_domain *domain;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
void (*continuation)(void *private, BOOL success);
|
||||
void *private;
|
||||
};
|
||||
|
||||
static void domain_init_recv(void *private, BOOL success);
|
||||
|
||||
void async_domain_request(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_domain *domain,
|
||||
struct winbindd_request *request,
|
||||
struct winbindd_response *response,
|
||||
void (*continuation)(void *private, BOOL success),
|
||||
void *private)
|
||||
{
|
||||
struct domain_request_state *state;
|
||||
|
||||
if (domain->initialized) {
|
||||
async_request(mem_ctx, &domain->child, request, response,
|
||||
continuation, private);
|
||||
return;
|
||||
}
|
||||
|
||||
state = TALLOC_P(mem_ctx, struct domain_request_state);
|
||||
if (state == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
continuation(private, False);
|
||||
return;
|
||||
}
|
||||
|
||||
state->mem_ctx = mem_ctx;
|
||||
state->domain = domain;
|
||||
state->request = request;
|
||||
state->response = response;
|
||||
state->continuation = continuation;
|
||||
state->private = private;
|
||||
|
||||
init_child_connection(domain, domain_init_recv, state);
|
||||
}
|
||||
|
||||
static void domain_init_recv(void *private, BOOL success)
|
||||
{
|
||||
struct domain_request_state *state =
|
||||
talloc_get_type_abort(private, struct domain_request_state);
|
||||
|
||||
if (!success) {
|
||||
DEBUG(5, ("Domain init returned an error\n"));
|
||||
state->continuation(state->private, False);
|
||||
return;
|
||||
}
|
||||
|
||||
async_request(state->mem_ctx, &state->domain->child,
|
||||
state->request, state->response,
|
||||
state->continuation, state->private);
|
||||
}
|
||||
|
||||
struct winbindd_child_dispatch_table {
|
||||
enum winbindd_cmd cmd;
|
||||
enum winbindd_result (*fn)(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state);
|
||||
const char *winbindd_cmd_name;
|
||||
};
|
||||
|
||||
static struct winbindd_child_dispatch_table child_dispatch_table[] = {
|
||||
|
||||
{ WINBINDD_LOOKUPSID, winbindd_dual_lookupsid, "LOOKUPSID" },
|
||||
{ WINBINDD_LOOKUPNAME, winbindd_dual_lookupname, "LOOKUPNAME" },
|
||||
{ WINBINDD_LIST_TRUSTDOM, winbindd_dual_list_trusted_domains,
|
||||
"LIST_TRUSTDOM" },
|
||||
{ WINBINDD_INIT_CONNECTION, winbindd_dual_init_connection,
|
||||
"INIT_CONNECTION" },
|
||||
{ WINBINDD_GETDCNAME, winbindd_dual_getdcname, "GETDCNAME" },
|
||||
{ WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence,
|
||||
"SHOW_SEQUENCE" },
|
||||
{ WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" },
|
||||
{ WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" },
|
||||
{ WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct,
|
||||
"CHECK_MACHACC" },
|
||||
{ WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" },
|
||||
{ WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" },
|
||||
{ WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" },
|
||||
{ WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" },
|
||||
{ WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" },
|
||||
{ WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" },
|
||||
{ WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" },
|
||||
{ WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
|
||||
{ WINBINDD_ALLOCATE_RID, winbindd_dual_allocate_rid, "ALLOCATE_RID" },
|
||||
{ WINBINDD_ALLOCATE_RID_AND_GID, winbindd_dual_allocate_rid_and_gid,
|
||||
"ALLOCATE_RID_AND_GID" },
|
||||
{ WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups,
|
||||
"GETUSERDOMGROUPS" },
|
||||
{ WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases,
|
||||
"GETSIDALIASES" },
|
||||
/* End of list */
|
||||
|
||||
{ WINBINDD_NUM_CMDS, NULL, "NONE" }
|
||||
};
|
||||
|
||||
static void child_process_request(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_child_dispatch_table *table;
|
||||
|
||||
/* Free response data - we may be interrupted and receive another
|
||||
command before being able to send this data off. */
|
||||
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
state->response.length = sizeof(struct winbindd_response);
|
||||
|
||||
state->mem_ctx = talloc_init("winbind request");
|
||||
if (state->mem_ctx == NULL)
|
||||
return;
|
||||
|
||||
/* Process command */
|
||||
|
||||
for (table = child_dispatch_table; table->fn; table++) {
|
||||
if (state->request.cmd == table->cmd) {
|
||||
DEBUG(10,("process_request: request fn %s\n",
|
||||
table->winbindd_cmd_name ));
|
||||
state->response.result = table->fn(domain, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!table->fn) {
|
||||
DEBUG(10,("process_request: unknown request fn number %d\n",
|
||||
(int)state->request.cmd ));
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
talloc_destroy(state->mem_ctx);
|
||||
}
|
||||
|
||||
void setup_domain_child(struct winbindd_domain *domain,
|
||||
struct winbindd_child *child,
|
||||
const char *explicit_logfile)
|
||||
{
|
||||
if (explicit_logfile != NULL) {
|
||||
pstr_sprintf(child->logfilename, "%s/log.winbindd-%s",
|
||||
dyn_LOGFILEBASE, explicit_logfile);
|
||||
} else if (domain != NULL) {
|
||||
pstr_sprintf(child->logfilename, "%s/log.wb-%s",
|
||||
dyn_LOGFILEBASE, domain->name);
|
||||
} else {
|
||||
smb_panic("Internal error: domain == NULL && "
|
||||
"explicit_logfile == NULL");
|
||||
}
|
||||
|
||||
child->domain = domain;
|
||||
}
|
||||
|
||||
struct winbindd_child *children = NULL;
|
||||
|
||||
void winbind_child_died(pid_t pid)
|
||||
{
|
||||
struct winbindd_child *child;
|
||||
|
||||
for (child = children; child != NULL; child = child->next) {
|
||||
if (child->pid == pid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (child == NULL) {
|
||||
DEBUG(0, ("Unknown child %d died!\n", pid));
|
||||
return;
|
||||
}
|
||||
|
||||
remove_fd_event(&child->event);
|
||||
close(child->event.fd);
|
||||
child->event.fd = 0;
|
||||
child->event.flags = 0;
|
||||
child->pid = 0;
|
||||
|
||||
schedule_async_request(child);
|
||||
}
|
||||
|
||||
static BOOL fork_domain_child(struct winbindd_child *child)
|
||||
{
|
||||
int fdpair[2];
|
||||
struct winbindd_cli_state state;
|
||||
extern BOOL override_logfile;
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fdpair) != 0) {
|
||||
DEBUG(0, ("Could not open child pipe: %s\n",
|
||||
strerror(errno)));
|
||||
return False;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(state);
|
||||
state.pid = getpid();
|
||||
|
||||
child->pid = sys_fork();
|
||||
|
||||
if (child->pid == -1) {
|
||||
DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (child->pid != 0) {
|
||||
/* Parent */
|
||||
close(fdpair[0]);
|
||||
child->next = child->prev = NULL;
|
||||
DLIST_ADD(children, child);
|
||||
child->event.fd = fdpair[1];
|
||||
child->event.flags = 0;
|
||||
child->requests = NULL;
|
||||
add_fd_event(&child->event);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Child */
|
||||
|
||||
state.sock = fdpair[0];
|
||||
close(fdpair[1]);
|
||||
|
||||
/* tdb needs special fork handling */
|
||||
if (tdb_reopen_all() == -1) {
|
||||
DEBUG(0,("tdb_reopen_all failed.\n"));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
close_conns_after_fork();
|
||||
|
||||
if (!override_logfile) {
|
||||
lp_set_logfile(child->logfilename);
|
||||
reopen_logs();
|
||||
}
|
||||
|
||||
dual_daemon_pipe = -1;
|
||||
opt_dual_daemon = False;
|
||||
|
||||
while (1) {
|
||||
/* free up any talloc memory */
|
||||
lp_talloc_free();
|
||||
main_loop_talloc_free();
|
||||
|
||||
/* fetch a request from the main daemon */
|
||||
dual_client_read(&state);
|
||||
|
||||
if (state.finished) {
|
||||
/* we lost contact with our parent */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* process full rquests */
|
||||
if (state.read_buf_len == sizeof(state.request)) {
|
||||
DEBUG(4,("child daemon request %d\n",
|
||||
(int)state.request.cmd));
|
||||
|
||||
state.request.null_term = '\0';
|
||||
child_process_request(child->domain, &state);
|
||||
|
||||
if (state.response.result == WINBINDD_OK)
|
||||
cache_store_response(sys_getpid(),
|
||||
&state.response);
|
||||
|
||||
SAFE_FREE(state.response.extra_data);
|
||||
|
||||
/* We just send the result code back, the result
|
||||
* structure needs to be fetched via the
|
||||
* winbindd_cache. Hmm. That needs fixing... */
|
||||
|
||||
if (write_data(state.sock,
|
||||
(void *)&state.response.result,
|
||||
sizeof(state.response.result)) !=
|
||||
sizeof(state.response.result)) {
|
||||
DEBUG(0, ("Could not write result\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
state.read_buf_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
|
||||
enum SID_NAME_USE group_name_type,
|
||||
int *num_gr_mem, char **gr_mem, int *gr_mem_len)
|
||||
{
|
||||
DOM_SID **sid_mem = NULL;
|
||||
DOM_SID *sid_mem = NULL;
|
||||
uint32 num_names = 0;
|
||||
uint32 *name_types = NULL;
|
||||
unsigned int buf_len, buf_ndx, i;
|
||||
@@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
|
||||
|
||||
if (DEBUGLEVEL >= 10) {
|
||||
for (i = 0; i < num_names; i++)
|
||||
DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
|
||||
DEBUG(10, ("\t%20s %s %d\n", names[i],
|
||||
sid_string_static(&sid_mem[i]),
|
||||
name_types[i]));
|
||||
}
|
||||
|
||||
@@ -222,7 +223,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
|
||||
|
||||
parse_domain_user(tmp, name_domain, name_group);
|
||||
|
||||
/* if no domain or our local domain, default to our local domain for aliases */
|
||||
/* if no domain or our local domain and no local tdb group, default to
|
||||
* our local domain for aliases */
|
||||
|
||||
if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
|
||||
fstrcpy(name_domain, get_global_sam_name());
|
||||
@@ -245,8 +247,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
|
||||
|
||||
/* Get rid and name type from name */
|
||||
|
||||
if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid,
|
||||
&name_type)) {
|
||||
if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
|
||||
name_group, &group_sid, &name_type)) {
|
||||
DEBUG(1, ("group %s in domain %s does not exist\n",
|
||||
name_group, name_domain));
|
||||
return WINBINDD_ERROR;
|
||||
@@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* Get rid from gid */
|
||||
if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
|
||||
if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) {
|
||||
DEBUG(1, ("could not convert gid %lu to rid\n",
|
||||
(unsigned long)state->request.data.gid));
|
||||
return WINBINDD_ERROR;
|
||||
@@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
|
||||
|
||||
/* Get name from sid */
|
||||
|
||||
if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
|
||||
if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
|
||||
group_name, &name_type)) {
|
||||
DEBUG(1, ("could not lookup sid\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Fill in group structure */
|
||||
|
||||
domain = find_domain_from_sid(&group_sid);
|
||||
domain = find_domain_from_sid_noinit(&group_sid);
|
||||
|
||||
if (!domain) {
|
||||
DEBUG(1,("Can't find domain from sid\n"));
|
||||
@@ -794,10 +797,6 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
|
||||
if ( *which_domain && !strequal(which_domain, domain->name) )
|
||||
continue;
|
||||
|
||||
if ( !domain->initialized )
|
||||
set_dc_type_and_flags( domain );
|
||||
|
||||
|
||||
ZERO_STRUCT(groups);
|
||||
|
||||
/* Get list of sam groups */
|
||||
@@ -856,323 +855,155 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
static BOOL enum_alias_memberships(const DOM_SID *member_sid,
|
||||
DOM_SID **aliases, int *num_aliases)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = talloc_init("enum_alias_memberships");
|
||||
|
||||
uint32 *rids = NULL;
|
||||
int i, num_rids = 0;
|
||||
|
||||
BOOL result = False;
|
||||
|
||||
if (mem_ctx == NULL)
|
||||
return False;
|
||||
|
||||
*aliases = NULL;
|
||||
*num_aliases = 0;
|
||||
|
||||
if (!pdb_enum_alias_memberships(mem_ctx, get_global_sam_sid(),
|
||||
member_sid, 1, &rids, &num_rids))
|
||||
goto done;
|
||||
|
||||
for (i=0; i<num_rids; i++) {
|
||||
DOM_SID alias_sid;
|
||||
sid_copy(&alias_sid, get_global_sam_sid());
|
||||
sid_append_rid(&alias_sid, rids[i]);
|
||||
add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
|
||||
}
|
||||
|
||||
if (!pdb_enum_alias_memberships(mem_ctx, &global_sid_Builtin,
|
||||
member_sid, 1, &rids, &num_rids))
|
||||
goto done;
|
||||
|
||||
for (i=0; i<num_rids; i++) {
|
||||
DOM_SID alias_sid;
|
||||
sid_copy(&alias_sid, &global_sid_Builtin);
|
||||
sid_append_rid(&alias_sid, rids[i]);
|
||||
add_sid_to_array(NULL, &alias_sid, aliases, num_aliases);
|
||||
}
|
||||
|
||||
result = True;
|
||||
done:
|
||||
if (mem_ctx != NULL)
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
|
||||
{
|
||||
gid_t gid;
|
||||
DOM_SID *aliases;
|
||||
int j, num_aliases;
|
||||
|
||||
DEBUG(10, ("Adding local gids from SID: %s\n",
|
||||
sid_string_static(sid)));
|
||||
|
||||
/* Don't expand aliases if not explicitly activated -- for now
|
||||
-- jerry */
|
||||
|
||||
if (!lp_winbind_nested_groups())
|
||||
return;
|
||||
|
||||
/* Add nested group memberships */
|
||||
|
||||
if (!enum_alias_memberships(sid, &aliases, &num_aliases))
|
||||
return;
|
||||
|
||||
for (j=0; j<num_aliases; j++) {
|
||||
enum SID_NAME_USE type;
|
||||
|
||||
if (!local_sid_to_gid(&gid, &aliases[j], &type)) {
|
||||
DEBUG(1, ("Got an alias membership with no alias\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) {
|
||||
DEBUG(1, ("Got an alias membership in a non-alias\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
add_gid_to_array_unique(NULL, gid, gids, num);
|
||||
}
|
||||
SAFE_FREE(aliases);
|
||||
}
|
||||
|
||||
static void add_gids_from_user_sid(DOM_SID *sid, gid_t **gids, int *num)
|
||||
{
|
||||
DEBUG(10, ("Adding gids from user SID: %s\n",
|
||||
sid_string_static(sid)));
|
||||
|
||||
add_local_gids_from_sid(sid, gids, num);
|
||||
}
|
||||
|
||||
static void add_gids_from_group_sid(DOM_SID *sid, gid_t **gids, int *num)
|
||||
{
|
||||
gid_t gid;
|
||||
|
||||
DEBUG(10, ("Adding gids from group SID: %s\n",
|
||||
sid_string_static(sid)));
|
||||
|
||||
if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
|
||||
add_gid_to_array_unique(NULL, gid, gids, num);
|
||||
|
||||
add_local_gids_from_sid(sid, gids, num);
|
||||
}
|
||||
|
||||
/* Get user supplementary groups. This is much quicker than trying to
|
||||
invert the groups database. We merge the groups from the gids and
|
||||
other_sids info3 fields as trusted domain, universal group
|
||||
memberships, and nested groups (win2k native mode only) are not
|
||||
returned by the getgroups RPC call but are present in the info3. */
|
||||
|
||||
struct getgroups_state {
|
||||
struct winbindd_cli_state *state;
|
||||
struct winbindd_domain *domain;
|
||||
char *domname;
|
||||
char *username;
|
||||
DOM_SID user_sid;
|
||||
|
||||
const DOM_SID *token_sids;
|
||||
int i, num_token_sids;
|
||||
|
||||
gid_t *token_gids;
|
||||
int num_token_gids;
|
||||
};
|
||||
|
||||
static void getgroups_usersid_recv(void *private, BOOL success,
|
||||
const DOM_SID *sid, enum SID_NAME_USE type);
|
||||
static void getgroups_tokensids_recv(void *private, BOOL success,
|
||||
DOM_SID *token_sids, int num_token_sids);
|
||||
static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid);
|
||||
|
||||
enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
|
||||
{
|
||||
fstring name_domain, name_user;
|
||||
DOM_SID user_sid, group_sid;
|
||||
enum SID_NAME_USE name_type;
|
||||
uint32 num_groups = 0;
|
||||
uint32 num_gids = 0;
|
||||
NTSTATUS status;
|
||||
DOM_SID **user_grpsids;
|
||||
struct winbindd_domain *domain;
|
||||
enum winbindd_result result = WINBINDD_ERROR;
|
||||
gid_t *gid_list = NULL;
|
||||
unsigned int i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
NET_USER_INFO_3 *info3 = NULL;
|
||||
struct getgroups_state *s;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.username[sizeof(state->request.data.username)-1]='\0';
|
||||
state->request.data.username
|
||||
[sizeof(state->request.data.username)-1]='\0';
|
||||
|
||||
DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
|
||||
state->request.data.username));
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)",
|
||||
state->request.data.username)))
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* Parse domain and username */
|
||||
|
||||
parse_domain_user(state->request.data.username,
|
||||
name_domain, name_user);
|
||||
s = TALLOC_P(state->mem_ctx, struct getgroups_state);
|
||||
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 */
|
||||
|
||||
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",
|
||||
name_domain));
|
||||
goto done;
|
||||
s->domname));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if ( domain->primary && lp_winbind_trusted_domains_only()) {
|
||||
DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
|
||||
"getgroups() for %s\\%s.\n", name_domain, name_user));
|
||||
if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
|
||||
DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
|
||||
"getgroups() for %s\\%s.\n", s->domname,
|
||||
s->username));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
&name_type)) {
|
||||
DEBUG(4, ("user '%s' does not exist\n", name_user));
|
||||
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;
|
||||
winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
|
||||
getgroups_usersid_recv, s);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
|
||||
DOM_SID ***sids, int *num_sids)
|
||||
static void getgroups_usersid_recv(void *private, BOOL success,
|
||||
const DOM_SID *sid, enum SID_NAME_USE type)
|
||||
{
|
||||
int i;
|
||||
struct getgroups_state *s = private;
|
||||
|
||||
for (i=0; i<(*num_sids); i++) {
|
||||
if (sid_compare(sid, (*sids)[i]) == 0)
|
||||
if ((!success) ||
|
||||
((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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (*sids == NULL)
|
||||
return;
|
||||
|
||||
(*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;
|
||||
s->state->response.data.num_entries = s->num_token_gids;
|
||||
s->state->response.extra_data = s->token_gids;
|
||||
s->state->response.length += s->num_token_gids * sizeof(gid_t);
|
||||
s->state->response.result = WINBINDD_OK;
|
||||
request_finished(s->state);
|
||||
}
|
||||
|
||||
/* Get user supplementary sids. This is equivalent to the
|
||||
@@ -1186,106 +1017,50 @@ static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
|
||||
you pass in another type of SID then you may get unpredictable
|
||||
results.
|
||||
*/
|
||||
|
||||
static void getusersids_recv(void *private, BOOL success, DOM_SID *sids,
|
||||
int num_sids);
|
||||
|
||||
enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID user_sid;
|
||||
NTSTATUS status;
|
||||
DOM_SID **user_grpsids;
|
||||
struct winbindd_domain *domain;
|
||||
enum winbindd_result result = WINBINDD_ERROR;
|
||||
unsigned int i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
char *ret = NULL;
|
||||
uint32 num_groups;
|
||||
unsigned ofs, ret_size = 0;
|
||||
DOM_SID *user_sid;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
|
||||
|
||||
if (!string_to_sid(&user_sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
|
||||
user_sid = TALLOC_P(state->mem_ctx, DOM_SID);
|
||||
if (user_sid == NULL) {
|
||||
DEBUG(1, ("talloc failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)",
|
||||
state->request.data.username))) {
|
||||
if (!string_to_sid(user_sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not get convert sid %s from string\n",
|
||||
state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Get info for the domain */
|
||||
if ((domain = find_domain_from_sid(&user_sid)) == NULL) {
|
||||
DEBUG(0,("could not find domain entry for sid %s\n",
|
||||
sid_string_static(&user_sid)));
|
||||
winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv,
|
||||
state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
for (i = 0; i < num_groups; i++) {
|
||||
const char *s = sid_string_static(user_grpsids[i]);
|
||||
for (i = 0; i < num_sids; i++) {
|
||||
const char *s = sid_string_static(&sids[i]);
|
||||
ret_size += strlen(s) + 1;
|
||||
}
|
||||
|
||||
@@ -1293,22 +1068,94 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
|
||||
ret = SMB_MALLOC(ret_size);
|
||||
if (!ret) goto done;
|
||||
ofs = 0;
|
||||
for (i = 0; i < num_groups; i++) {
|
||||
const char *s = sid_string_static(user_grpsids[i]);
|
||||
for (i = 0; i < num_sids; i++) {
|
||||
const char *s = sid_string_static(&sids[i]);
|
||||
safe_strcpy(ret + ofs, s, ret_size - ofs - 1);
|
||||
ofs += strlen(ret+ofs) + 1;
|
||||
}
|
||||
|
||||
no_groups:
|
||||
/* Send data back to client */
|
||||
state->response.data.num_entries = num_groups;
|
||||
state->response.data.num_entries = num_sids;
|
||||
state->response.extra_data = ret;
|
||||
state->response.length += ret_size;
|
||||
result = WINBINDD_OK;
|
||||
state->response.result = WINBINDD_OK;
|
||||
|
||||
done:
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return result;
|
||||
request_finished(state);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
646
source/nsswitch/winbindd_ldap.c
Normal file
646
source/nsswitch/winbindd_ldap.c
Normal 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;
|
||||
}
|
||||
@@ -30,12 +30,21 @@
|
||||
/* Check the machine account password is valid */
|
||||
|
||||
enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
|
||||
{
|
||||
DEBUG(3, ("[%5lu]: check machine account\n",
|
||||
(unsigned long)state->pid));
|
||||
|
||||
async_domain_request(state->mem_ctx, find_our_domain(),
|
||||
&state->request, &state->response,
|
||||
request_finished_cont, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
uchar trust_passwd[16];
|
||||
int num_retries = 0;
|
||||
struct cli_state *cli;
|
||||
uint32 sec_channel_type;
|
||||
struct winbindd_domain *contact_domain;
|
||||
|
||||
DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
|
||||
@@ -43,26 +52,22 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
|
||||
/* Get trust account password */
|
||||
|
||||
again:
|
||||
if (!secrets_fetch_trust_account_password(
|
||||
lp_workgroup(), trust_passwd, NULL, &sec_channel_type)) {
|
||||
result = NT_STATUS_INTERNAL_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
contact_domain = find_our_domain();
|
||||
if (!contact_domain) {
|
||||
result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
|
||||
DEBUG(1, ("Cannot find our own domain!\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* This call does a cli_nt_setup_creds() which implicitly checks
|
||||
the trust account password. */
|
||||
/* Don't shut this down - it belongs to the connection cache code */
|
||||
|
||||
result = cm_get_netlogon_cli(contact_domain,
|
||||
trust_passwd, sec_channel_type, True, &cli);
|
||||
invalidate_cm_connection(&contact_domain->conn);
|
||||
|
||||
{
|
||||
struct rpc_pipe_client *cli;
|
||||
unsigned char *session_key;
|
||||
DOM_CRED *creds;
|
||||
|
||||
result = cm_connect_netlogon(contact_domain, state->mem_ctx,
|
||||
&cli, &session_key, &creds);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
|
||||
@@ -100,108 +105,256 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
|
||||
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
|
||||
*state)
|
||||
enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
int total_entries = 0, extra_data_len = 0;
|
||||
char *ted, *extra_data = NULL;
|
||||
DEBUG(3, ("[%5lu]: list trusted domains\n",
|
||||
(unsigned long)state->pid));
|
||||
|
||||
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
|
||||
have changed since we last looked. There may be a sequence
|
||||
number or something we should use but I haven't found it yet. */
|
||||
enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
uint32 i, num_domains;
|
||||
char **names, **alt_names;
|
||||
DOM_SID *sids;
|
||||
int extra_data_len = 0;
|
||||
char *extra_data;
|
||||
NTSTATUS result;
|
||||
|
||||
if (!init_domain_list()) {
|
||||
DEBUG(1, ("winbindd_list_trusted_domains: could not "
|
||||
"refresh trusted domain list\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
DEBUG(3, ("[%5lu]: list trusted domains\n",
|
||||
(unsigned long)state->pid));
|
||||
|
||||
for(domain = domain_list(); domain; domain = domain->next) {
|
||||
result = domain->methods->trusted_domains(domain, state->mem_ctx,
|
||||
&num_domains, &names,
|
||||
&alt_names, &sids);
|
||||
|
||||
/* Skip own domain */
|
||||
extra_data = talloc_strdup(state->mem_ctx, "");
|
||||
|
||||
if (domain->primary) continue;
|
||||
if (num_domains > 0)
|
||||
extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
|
||||
names[0], alt_names[0],
|
||||
sid_string_static(&sids[0]));
|
||||
|
||||
/* Add domain to list */
|
||||
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]));
|
||||
|
||||
total_entries++;
|
||||
ted = SMB_REALLOC(extra_data, sizeof(fstring) *
|
||||
total_entries);
|
||||
/* This is a bit excessive, but the extra data sooner or later will be
|
||||
talloc'ed */
|
||||
|
||||
if (!ted) {
|
||||
DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
|
||||
SAFE_FREE(extra_data);
|
||||
return WINBINDD_ERROR;
|
||||
} else
|
||||
extra_data = ted;
|
||||
extra_data_len = strlen(extra_data);
|
||||
|
||||
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) {
|
||||
if (extra_data_len > 1)
|
||||
extra_data[extra_data_len - 1] = '\0';
|
||||
state->response.extra_data = extra_data;
|
||||
state->response.length += extra_data_len;
|
||||
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;
|
||||
}
|
||||
|
||||
result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
|
||||
state->request.domain_name,
|
||||
dcname_slash);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
p = dcname_slash;
|
||||
if (*p == '\\') p+=1;
|
||||
if (*p == '\\') p+=1;
|
||||
|
||||
fstrcpy(state->response.data.dc_name, p);
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
struct sequence_state {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_cli_state *cli_state;
|
||||
struct winbindd_domain *domain;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
char *extra_data;
|
||||
};
|
||||
|
||||
static void sequence_recv(void *private, BOOL success);
|
||||
|
||||
enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
char *extra_data = NULL;
|
||||
const char *which_domain;
|
||||
struct sequence_state *seq;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
|
||||
|
||||
if (strlen(state->request.domain_name) > 0) {
|
||||
struct winbindd_domain *domain;
|
||||
domain = find_domain_from_name_noinit(
|
||||
state->request.domain_name);
|
||||
if (domain == NULL)
|
||||
return WINBINDD_ERROR;
|
||||
async_domain_request(state->mem_ctx, domain,
|
||||
&state->request, &state->response,
|
||||
request_finished_cont, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
/* Ask all domains in sequence, collect the results in sequence_recv */
|
||||
|
||||
seq = TALLOC_P(state->mem_ctx, struct sequence_state);
|
||||
if (seq == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
seq->mem_ctx = state->mem_ctx;
|
||||
seq->cli_state = state;
|
||||
seq->domain = domain_list();
|
||||
if (seq->domain == NULL) {
|
||||
DEBUG(0, ("domain list empty\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
seq->request = TALLOC_ZERO_P(state->mem_ctx,
|
||||
struct winbindd_request);
|
||||
seq->response = TALLOC_ZERO_P(state->mem_ctx,
|
||||
struct winbindd_response);
|
||||
seq->extra_data = talloc_strdup(state->mem_ctx, "");
|
||||
|
||||
if ((seq->request == NULL) || (seq->response == NULL) ||
|
||||
(seq->extra_data == NULL)) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
seq->request->length = sizeof(*seq->request);
|
||||
seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
|
||||
fstrcpy(seq->request->domain_name, seq->domain->name);
|
||||
|
||||
async_domain_request(state->mem_ctx, seq->domain,
|
||||
seq->request, seq->response,
|
||||
sequence_recv, seq);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
static void sequence_recv(void *private, BOOL success)
|
||||
{
|
||||
struct sequence_state *state = private;
|
||||
uint32 seq = DOM_SEQUENCE_NONE;
|
||||
|
||||
if ((success) && (state->response->result == WINBINDD_OK))
|
||||
seq = state->response->data.domain_info.sequence_number;
|
||||
|
||||
if (seq == DOM_SEQUENCE_NONE) {
|
||||
state->extra_data = talloc_asprintf(state->mem_ctx,
|
||||
"%s%s : DISCONNECTED\n",
|
||||
state->extra_data,
|
||||
state->domain->name);
|
||||
} else {
|
||||
state->extra_data = talloc_asprintf(state->mem_ctx,
|
||||
"%s%s : %d\n",
|
||||
state->extra_data,
|
||||
state->domain->name, seq);
|
||||
}
|
||||
|
||||
state->domain->sequence_number = seq;
|
||||
|
||||
state->domain = state->domain->next;
|
||||
|
||||
if (state->domain == NULL) {
|
||||
struct winbindd_cli_state *cli_state = state->cli_state;
|
||||
cli_state->response.result = WINBINDD_OK;
|
||||
cli_state->response.length =
|
||||
sizeof(cli_state->response) +
|
||||
strlen(state->extra_data) + 1;
|
||||
cli_state->response.extra_data =
|
||||
SMB_STRDUP(state->extra_data);
|
||||
request_finished(cli_state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ask the next domain */
|
||||
fstrcpy(state->request->domain_name, state->domain->name);
|
||||
async_domain_request(state->mem_ctx, state->domain,
|
||||
state->request, state->response,
|
||||
sequence_recv, state);
|
||||
}
|
||||
|
||||
/* This is the child-only version of --sequence. It only allows for a single
|
||||
* domain (ie "our" one) to be displayed. */
|
||||
|
||||
enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
|
||||
which_domain = state->request.domain_name;
|
||||
|
||||
extra_data = SMB_STRDUP("");
|
||||
domain->methods->sequence_number(domain, &domain->sequence_number);
|
||||
|
||||
/* this makes for a very simple data format, and is easily parsable as well
|
||||
if that is ever needed */
|
||||
for (domain = domain_list(); domain; domain = domain->next) {
|
||||
char *s;
|
||||
|
||||
/* if we have a domain name restricting the request and this
|
||||
one in the list doesn't match, then just bypass the remainder
|
||||
of the loop */
|
||||
|
||||
if ( *which_domain && !strequal(which_domain, domain->name) )
|
||||
continue;
|
||||
|
||||
domain->methods->sequence_number(domain, &domain->sequence_number);
|
||||
|
||||
if (DOM_SEQUENCE_NONE == (unsigned)domain->sequence_number) {
|
||||
asprintf(&s,"%s%s : DISCONNECTED\n", extra_data,
|
||||
domain->name);
|
||||
} else {
|
||||
asprintf(&s,"%s%s : %u\n", extra_data,
|
||||
domain->name, (unsigned)domain->sequence_number);
|
||||
}
|
||||
free(extra_data);
|
||||
extra_data = s;
|
||||
}
|
||||
|
||||
state->response.extra_data = extra_data;
|
||||
/* must add one to length to copy the 0 for string termination */
|
||||
state->response.length += strlen(extra_data) + 1;
|
||||
state->response.data.domain_info.sequence_number =
|
||||
domain->sequence_number;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
struct domain_info_state {
|
||||
struct winbindd_domain *domain;
|
||||
struct winbindd_cli_state *cli_state;
|
||||
};
|
||||
|
||||
static void domain_info_init_recv(void *private, BOOL success);
|
||||
|
||||
enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
@@ -209,7 +362,7 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
|
||||
state->request.domain_name));
|
||||
|
||||
domain = find_domain_from_name(state->request.domain_name);
|
||||
domain = find_domain_from_name_noinit(state->request.domain_name);
|
||||
|
||||
if (domain == NULL) {
|
||||
DEBUG(3, ("Did not find domain [%s]\n",
|
||||
@@ -217,21 +370,78 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
fstrcpy(state->response.data.domain_info.name, domain->name);
|
||||
fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
|
||||
if (!domain->initialized) {
|
||||
struct domain_info_state *istate;
|
||||
|
||||
istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
|
||||
if (istate == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
istate->cli_state = state;
|
||||
istate->domain = domain;
|
||||
|
||||
init_child_connection(domain, domain_info_init_recv, istate);
|
||||
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
fstrcpy(state->response.data.domain_info.name,
|
||||
domain->name);
|
||||
fstrcpy(state->response.data.domain_info.alt_name,
|
||||
domain->alt_name);
|
||||
fstrcpy(state->response.data.domain_info.sid,
|
||||
sid_string_static(&domain->sid));
|
||||
|
||||
state->response.data.domain_info.native_mode = domain->native_mode;
|
||||
state->response.data.domain_info.active_directory = domain->active_directory;
|
||||
state->response.data.domain_info.primary = domain->primary;
|
||||
|
||||
state->response.data.domain_info.native_mode =
|
||||
domain->native_mode;
|
||||
state->response.data.domain_info.active_directory =
|
||||
domain->active_directory;
|
||||
state->response.data.domain_info.primary =
|
||||
domain->primary;
|
||||
state->response.data.domain_info.sequence_number =
|
||||
domain->sequence_number;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
static void domain_info_init_recv(void *private, BOOL success)
|
||||
{
|
||||
struct domain_info_state *istate = private;
|
||||
struct winbindd_cli_state *state = istate->cli_state;
|
||||
struct winbindd_domain *domain = istate->domain;
|
||||
|
||||
DEBUG(10, ("Got back from child init: %d\n", success));
|
||||
|
||||
if ((!success) || (!domain->initialized)) {
|
||||
DEBUG(5, ("Could not init child for domain %s\n",
|
||||
domain->name));
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
request_finished_cont(state, False);
|
||||
return;
|
||||
}
|
||||
|
||||
fstrcpy(state->response.data.domain_info.name,
|
||||
domain->name);
|
||||
fstrcpy(state->response.data.domain_info.alt_name,
|
||||
domain->alt_name);
|
||||
fstrcpy(state->response.data.domain_info.sid,
|
||||
sid_string_static(&domain->sid));
|
||||
|
||||
state->response.data.domain_info.native_mode =
|
||||
domain->native_mode;
|
||||
state->response.data.domain_info.active_directory =
|
||||
domain->active_directory;
|
||||
state->response.data.domain_info.primary =
|
||||
domain->primary;
|
||||
state->response.data.domain_info.sequence_number =
|
||||
domain->sequence_number;
|
||||
|
||||
state->response.result = WINBINDD_OK;
|
||||
request_finished_cont(state, True);
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_ping(struct winbindd_cli_state
|
||||
*state)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
/* Update this when you change the interface. */
|
||||
|
||||
#define WINBIND_INTERFACE_VERSION 10
|
||||
#define WINBIND_INTERFACE_VERSION 11
|
||||
|
||||
/* Socket commands */
|
||||
|
||||
@@ -83,6 +83,7 @@ enum winbindd_cmd {
|
||||
WINBINDD_UID_TO_SID,
|
||||
WINBINDD_GID_TO_SID,
|
||||
WINBINDD_ALLOCATE_RID,
|
||||
WINBINDD_ALLOCATE_RID_AND_GID,
|
||||
|
||||
/* Miscellaneous other stuff */
|
||||
|
||||
@@ -93,6 +94,7 @@ enum winbindd_cmd {
|
||||
|
||||
WINBINDD_DOMAIN_INFO, /* Most of what we know from
|
||||
struct winbindd_domain */
|
||||
WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
|
||||
|
||||
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
|
||||
|
||||
@@ -112,7 +114,27 @@ enum winbindd_cmd {
|
||||
/* return a list of group sids for a user sid */
|
||||
WINBINDD_GETUSERSIDS,
|
||||
|
||||
/* Placeholder for end of cmd list */
|
||||
/* 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,
|
||||
|
||||
WINBINDD_NUM_CMDS
|
||||
};
|
||||
|
||||
@@ -148,6 +170,9 @@ typedef struct winbindd_gr {
|
||||
#define WBFLAG_PAM_AFS_TOKEN 0x0100
|
||||
#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200
|
||||
|
||||
/* This is a flag that can only be sent from parent to child */
|
||||
#define WBFLAG_IS_PRIVILEGED 0x0400
|
||||
|
||||
/* Winbind request structure */
|
||||
|
||||
struct winbindd_request {
|
||||
@@ -156,6 +181,7 @@ struct winbindd_request {
|
||||
pid_t pid; /* pid of calling process */
|
||||
uint32 flags; /* flags relavant to a given request */
|
||||
fstring domain_name; /* name of domain for which the request applies */
|
||||
int msgid;
|
||||
|
||||
union {
|
||||
fstring winsreq; /* WINS request */
|
||||
@@ -197,6 +223,24 @@ struct winbindd_request {
|
||||
fstring username;
|
||||
fstring groupname;
|
||||
} acct_mgt;
|
||||
struct {
|
||||
BOOL is_primary;
|
||||
fstring dcname;
|
||||
} init_conn;
|
||||
struct {
|
||||
fstring sid;
|
||||
fstring name;
|
||||
BOOL alloc;
|
||||
} dual_sid2id;
|
||||
struct {
|
||||
int type;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
fstring sid;
|
||||
} dual_idmapset;
|
||||
struct {
|
||||
fstring cache_key;
|
||||
} dual_sidaliases;
|
||||
} data;
|
||||
char null_term;
|
||||
};
|
||||
@@ -205,6 +249,7 @@ struct winbindd_request {
|
||||
|
||||
enum winbindd_result {
|
||||
WINBINDD_ERROR,
|
||||
WINBINDD_PENDING,
|
||||
WINBINDD_OK
|
||||
};
|
||||
|
||||
@@ -250,6 +295,7 @@ struct winbindd_response {
|
||||
} info;
|
||||
fstring domain_name;
|
||||
fstring netbios_name;
|
||||
fstring dc_name;
|
||||
|
||||
struct auth_reply {
|
||||
uint32 nt_status;
|
||||
@@ -260,6 +306,10 @@ struct winbindd_response {
|
||||
char first_8_lm_hash[8];
|
||||
} auth;
|
||||
uint32 rid; /* create user or group or allocate rid */
|
||||
struct {
|
||||
uint32 rid;
|
||||
gid_t gid;
|
||||
} rid_and_gid;
|
||||
struct {
|
||||
fstring name;
|
||||
fstring alt_name;
|
||||
@@ -269,6 +319,11 @@ struct winbindd_response {
|
||||
BOOL primary;
|
||||
uint32 sequence_number;
|
||||
} domain_info;
|
||||
struct {
|
||||
fstring acct_name;
|
||||
fstring full_name;
|
||||
uint32 group_rid;
|
||||
} user_info;
|
||||
} data;
|
||||
|
||||
/* Variable length return data */
|
||||
|
||||
@@ -145,24 +145,99 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
|
||||
static struct winbindd_domain *find_auth_domain(const char *domain_name)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
if (IS_DC) {
|
||||
domain = find_domain_from_name_noinit(domain_name);
|
||||
if (domain == NULL) {
|
||||
DEBUG(3, ("Authentication for domain [%s] "
|
||||
"as it is not a trusted domain\n",
|
||||
domain_name));
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
if (is_myname(domain_name)) {
|
||||
DEBUG(3, ("Authentication for domain %s (local domain "
|
||||
"to this server) not supported at this "
|
||||
"stage\n", domain_name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return find_our_domain();
|
||||
}
|
||||
|
||||
static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
|
||||
{
|
||||
resp->data.auth.nt_status = NT_STATUS_V(result);
|
||||
fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
|
||||
|
||||
/* we might have given a more useful error above */
|
||||
if (*resp->data.auth.error_string == '\0')
|
||||
fstrcpy(resp->data.auth.error_string,
|
||||
get_friendly_nt_error_msg(result));
|
||||
resp->data.auth.pam_error = nt_status_to_pam(result);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Authenticate a user with a clear text password
|
||||
**********************************************************************/
|
||||
|
||||
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
fstring name_domain, name_user;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.auth.user
|
||||
[sizeof(state->request.data.auth.user)-1]='\0';
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.auth.pass
|
||||
[sizeof(state->request.data.auth.pass)-1]='\0';
|
||||
|
||||
DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
|
||||
state->request.data.auth.user));
|
||||
|
||||
/* Parse domain and username */
|
||||
|
||||
parse_domain_user(state->request.data.auth.user,
|
||||
name_domain, name_user);
|
||||
|
||||
domain = find_auth_domain(name_domain);
|
||||
|
||||
if (domain == NULL) {
|
||||
set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
|
||||
DEBUG(5, ("Plain text authentication for %s returned %s "
|
||||
"(PAM: %d)\n",
|
||||
state->request.data.auth.user,
|
||||
state->response.data.auth.nt_status_string,
|
||||
state->response.data.auth.pam_error));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
async_domain_request(state->mem_ctx, domain,
|
||||
&state->request, &state->response,
|
||||
request_finished_cont, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
NTSTATUS result;
|
||||
fstring name_domain, name_user;
|
||||
unsigned char trust_passwd[16];
|
||||
time_t last_change_time;
|
||||
uint32 sec_channel_type;
|
||||
const char *srv_name_slash;
|
||||
NET_USER_INFO_3 info3;
|
||||
struct cli_state *cli = NULL;
|
||||
unsigned char *session_key;
|
||||
struct rpc_pipe_client *pipe_cli;
|
||||
uchar chal[8];
|
||||
TALLOC_CTX *mem_ctx = NULL;
|
||||
DATA_BLOB lm_resp;
|
||||
DATA_BLOB nt_resp;
|
||||
DOM_CRED ret_creds;
|
||||
DOM_CRED *credentials;
|
||||
int attempts = 0;
|
||||
unsigned char local_lm_response[24];
|
||||
unsigned char local_nt_response[24];
|
||||
@@ -178,12 +253,6 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
|
||||
state->request.data.auth.user));
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbind pam auth for %s", state->request.data.auth.user))) {
|
||||
DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Parse domain and username */
|
||||
|
||||
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
|
||||
@@ -197,7 +266,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
DATA_BLOB names_blob;
|
||||
DATA_BLOB nt_response;
|
||||
DATA_BLOB lm_response;
|
||||
server_chal = data_blob_talloc(mem_ctx, chal, 8);
|
||||
server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
|
||||
|
||||
/* note that the 'workgroup' here is a best guess - we don't know
|
||||
the server's domain at this point. The 'server name' is also
|
||||
@@ -218,8 +287,10 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
}
|
||||
data_blob_free(&names_blob);
|
||||
data_blob_free(&server_chal);
|
||||
lm_resp = data_blob_talloc(mem_ctx, lm_response.data, lm_response.length);
|
||||
nt_resp = data_blob_talloc(mem_ctx, nt_response.data, nt_response.length);
|
||||
lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
|
||||
lm_response.length);
|
||||
nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
|
||||
nt_response.length);
|
||||
data_blob_free(&lm_response);
|
||||
data_blob_free(&nt_response);
|
||||
|
||||
@@ -228,7 +299,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
&& SMBencrypt(state->request.data.auth.pass,
|
||||
chal,
|
||||
local_lm_response)) {
|
||||
lm_resp = data_blob_talloc(mem_ctx,
|
||||
lm_resp = data_blob_talloc(state->mem_ctx,
|
||||
local_lm_response,
|
||||
sizeof(local_lm_response));
|
||||
} else {
|
||||
@@ -238,7 +309,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
chal,
|
||||
local_nt_response);
|
||||
|
||||
nt_resp = data_blob_talloc(mem_ctx,
|
||||
nt_resp = data_blob_talloc(state->mem_ctx,
|
||||
local_nt_response,
|
||||
sizeof(local_nt_response));
|
||||
}
|
||||
@@ -261,80 +332,95 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(contact_domain = find_our_domain())) {
|
||||
DEBUG(1, ("Authentication for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
|
||||
state->request.data.auth.user, name_domain, name_user));
|
||||
result = NT_STATUS_NO_SUCH_USER;
|
||||
goto done;
|
||||
}
|
||||
contact_domain = find_our_domain();
|
||||
}
|
||||
|
||||
if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
|
||||
result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
|
||||
goto done;
|
||||
srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
|
||||
contact_domain->dcname);
|
||||
if (srv_name_slash == NULL) {
|
||||
DEBUG(0, ("talloc_asprintf failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* check authentication loop */
|
||||
|
||||
do {
|
||||
DOM_CRED clnt_creds;
|
||||
|
||||
ZERO_STRUCT(info3);
|
||||
ZERO_STRUCT(ret_creds);
|
||||
retry = False;
|
||||
|
||||
/* Don't shut this down - it belongs to the connection cache code */
|
||||
result = cm_get_netlogon_cli(contact_domain, trust_passwd,
|
||||
sec_channel_type, False, &cli);
|
||||
result = cm_connect_netlogon(contact_domain, state->mem_ctx,
|
||||
&pipe_cli, &session_key,
|
||||
&credentials);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
|
||||
&ret_creds,
|
||||
name_user, name_domain,
|
||||
global_myname(), chal,
|
||||
lm_resp, nt_resp,
|
||||
&info3);
|
||||
credentials->timestamp.time = time(NULL);
|
||||
memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
|
||||
|
||||
/* Calculate the new credentials. */
|
||||
cred_create(session_key, &credentials->challenge,
|
||||
clnt_creds.timestamp, &(clnt_creds.challenge));
|
||||
|
||||
result = rpccli_netlogon_sam_network_logon(pipe_cli,
|
||||
state->mem_ctx,
|
||||
srv_name_slash,
|
||||
&clnt_creds,
|
||||
&ret_creds,
|
||||
name_user,
|
||||
name_domain,
|
||||
global_myname(),
|
||||
chal, lm_resp,
|
||||
nt_resp, &info3,
|
||||
session_key);
|
||||
attempts += 1;
|
||||
|
||||
/* We have to try a second time as cm_get_netlogon_cli
|
||||
/* We have to try a second time as cm_connect_netlogon
|
||||
might not yet have noticed that the DC has killed
|
||||
our connection. */
|
||||
|
||||
if ( cli->fd == -1 ) {
|
||||
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
|
||||
retry = True;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if we get access denied, a possible cuase was that we had and open
|
||||
connection to the DC, but someone changed our machine account password
|
||||
out from underneath us using 'net rpc changetrustpw' */
|
||||
/* if we get access denied, a possible cause was that we had
|
||||
and open connection to the DC, but someone changed our
|
||||
machine account password out from underneath us using 'net
|
||||
rpc changetrustpw' */
|
||||
|
||||
if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
|
||||
DEBUG(3,("winbindd_pam_auth: sam_logon returned ACCESS_DENIED. Maybe the trust account "
|
||||
"password was changed and we didn't know it. Killing connections to domain %s\n",
|
||||
if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
|
||||
DEBUG(3,("winbindd_pam_auth: sam_logon returned "
|
||||
"ACCESS_DENIED. Maybe the trust account "
|
||||
"password was changed and we didn't know it. "
|
||||
"Killing connections to domain %s\n",
|
||||
name_domain));
|
||||
winbindd_cm_flush();
|
||||
invalidate_cm_connection(&contact_domain->conn);
|
||||
retry = True;
|
||||
cli = NULL;
|
||||
}
|
||||
|
||||
} while ( (attempts < 2) && retry );
|
||||
|
||||
if (cli != NULL) {
|
||||
/* We might have come out of the loop above with cli == NULL,
|
||||
so don't dereference that. */
|
||||
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
|
||||
if (NT_STATUS_IS_OK(result) &&
|
||||
(!clnt_deal_with_creds(session_key, credentials,
|
||||
&ret_creds))) {
|
||||
DEBUG(3, ("DC %s sent wrong credentials\n",
|
||||
pipe_cli->cli->srv_name_slash));
|
||||
result = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
|
||||
netsamlogon_cache_store(state->mem_ctx, name_user, &info3);
|
||||
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
|
||||
|
||||
/* Check if the user is in the right group */
|
||||
|
||||
if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
|
||||
if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth.require_membership_of_sid))) {
|
||||
DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
|
||||
state->request.data.auth.user,
|
||||
state->request.data.auth.require_membership_of_sid));
|
||||
@@ -407,9 +493,6 @@ done:
|
||||
SAFE_FREE(afsname);
|
||||
}
|
||||
|
||||
if (mem_ctx)
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
@@ -417,15 +500,79 @@ done:
|
||||
Challenge Response Authentication Protocol
|
||||
**********************************************************************/
|
||||
|
||||
enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
enum winbindd_result winbindd_crap_auth(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *domain = NULL;
|
||||
const char *domain_name = NULL;
|
||||
NTSTATUS result;
|
||||
|
||||
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;
|
||||
unsigned char trust_passwd[16];
|
||||
time_t last_change_time;
|
||||
uint32 sec_channel_type;
|
||||
const char *srv_name_slash;
|
||||
NET_USER_INFO_3 info3;
|
||||
struct cli_state *cli = NULL;
|
||||
TALLOC_CTX *mem_ctx = NULL;
|
||||
unsigned char *session_key;
|
||||
struct rpc_pipe_client *pipe_cli;
|
||||
DOM_CRED *credentials;
|
||||
const char *name_user = NULL;
|
||||
const char *name_domain = NULL;
|
||||
const char *workstation;
|
||||
@@ -436,30 +583,13 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
|
||||
DATA_BLOB lm_resp, nt_resp;
|
||||
|
||||
if (!state->privileged) {
|
||||
char *error_string = NULL;
|
||||
DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied. !\n"));
|
||||
DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions on %s are set correctly.\n",
|
||||
get_winbind_priv_pipe_dir()));
|
||||
/* send a better message than ACCESS_DENIED */
|
||||
asprintf(&error_string, "winbind client not authorized to use winbindd_pam_auth_crap. Ensure permissions on %s are set correctly.",
|
||||
get_winbind_priv_pipe_dir());
|
||||
fstrcpy(state->response.data.auth.error_string, error_string);
|
||||
SAFE_FREE(error_string);
|
||||
result = NT_STATUS_ACCESS_DENIED;
|
||||
goto done;
|
||||
}
|
||||
/* This is child-only, so no check for privileged access is needed
|
||||
anymore */
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
|
||||
state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbind pam auth crap for %s", state->request.data.auth_crap.user))) {
|
||||
DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
name_user = state->request.data.auth_crap.user;
|
||||
|
||||
if (*state->request.data.auth_crap.domain) {
|
||||
@@ -491,8 +621,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
goto done;
|
||||
}
|
||||
|
||||
lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
|
||||
nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
|
||||
lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
|
||||
nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
|
||||
|
||||
|
||||
/* what domain should we contact? */
|
||||
@@ -512,26 +642,25 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(contact_domain = find_our_domain())) {
|
||||
DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
|
||||
state->request.data.auth_crap.user, name_domain, name_user));
|
||||
result = NT_STATUS_NO_SUCH_USER;
|
||||
goto done;
|
||||
}
|
||||
contact_domain = find_our_domain();
|
||||
}
|
||||
|
||||
if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) {
|
||||
result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
|
||||
goto done;
|
||||
srv_name_slash = talloc_asprintf(state->mem_ctx, "\\\\%s",
|
||||
contact_domain->dcname);
|
||||
if (srv_name_slash == NULL) {
|
||||
DEBUG(0, ("talloc_asprintf failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
do {
|
||||
DOM_CRED clnt_creds;
|
||||
ZERO_STRUCT(info3);
|
||||
ZERO_STRUCT(ret_creds);
|
||||
retry = False;
|
||||
|
||||
/* Don't shut this down - it belongs to the connection cache code */
|
||||
result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli);
|
||||
result = cm_connect_netlogon(contact_domain, state->mem_ctx,
|
||||
&pipe_cli, &session_key,
|
||||
&credentials);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
|
||||
@@ -539,21 +668,33 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
|
||||
&ret_creds,
|
||||
name_user, name_domain,
|
||||
workstation,
|
||||
state->request.data.auth_crap.chal,
|
||||
lm_resp, nt_resp,
|
||||
&info3);
|
||||
credentials->timestamp.time = time(NULL);
|
||||
memcpy(&clnt_creds, credentials, sizeof(clnt_creds));
|
||||
|
||||
/* Calculate the new credentials. */
|
||||
cred_create(session_key, &credentials->challenge,
|
||||
clnt_creds.timestamp, &(clnt_creds.challenge));
|
||||
|
||||
result = rpccli_netlogon_sam_network_logon(pipe_cli,
|
||||
state->mem_ctx,
|
||||
srv_name_slash,
|
||||
&clnt_creds,
|
||||
&ret_creds,
|
||||
name_user,
|
||||
name_domain,
|
||||
global_myname(),
|
||||
state->request.data.auth_crap.chal,
|
||||
lm_resp,
|
||||
nt_resp, &info3,
|
||||
session_key);
|
||||
|
||||
attempts += 1;
|
||||
|
||||
/* We have to try a second time as cm_get_netlogon_cli
|
||||
/* We have to try a second time as cm_connect_netlogon
|
||||
might not yet have noticed that the DC has killed
|
||||
our connection. */
|
||||
|
||||
if ( cli->fd == -1 ) {
|
||||
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
|
||||
retry = True;
|
||||
continue;
|
||||
}
|
||||
@@ -562,28 +703,31 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
connection to the DC, but someone changed our machine account password
|
||||
out from underneath us using 'net rpc changetrustpw' */
|
||||
|
||||
if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) {
|
||||
DEBUG(3,("winbindd_pam_auth_crap: sam_logon returned ACCESS_DENIED. Maybe the trust account "
|
||||
"password was changed and we didn't know it. Killing connections to domain %s\n",
|
||||
contact_domain->name));
|
||||
winbindd_cm_flush();
|
||||
if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
|
||||
DEBUG(3,("winbindd_pam_auth: sam_logon returned "
|
||||
"ACCESS_DENIED. Maybe the trust account "
|
||||
"password was changed and we didn't know it. "
|
||||
"Killing connections to domain %s\n",
|
||||
name_domain));
|
||||
invalidate_cm_connection(&contact_domain->conn);
|
||||
retry = True;
|
||||
cli = NULL;
|
||||
}
|
||||
|
||||
} while ( (attempts < 2) && retry );
|
||||
|
||||
if (cli != NULL) {
|
||||
/* We might have come out of the loop above with cli == NULL,
|
||||
so don't dereference that. */
|
||||
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
|
||||
if (NT_STATUS_IS_OK(result) &&
|
||||
(!clnt_deal_with_creds(session_key, credentials,
|
||||
&ret_creds))) {
|
||||
DEBUG(3, ("DC %s sent wrong credentials\n",
|
||||
pipe_cli->cli->srv_name_slash));
|
||||
result = NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
netsamlogon_cache_store( cli->mem_ctx, name_user, &info3 );
|
||||
netsamlogon_cache_store( state->mem_ctx, name_user, &info3 );
|
||||
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
|
||||
if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, state->request.data.auth_crap.require_membership_of_sid))) {
|
||||
DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
|
||||
state->request.data.auth_crap.user,
|
||||
state->request.data.auth_crap.require_membership_of_sid));
|
||||
@@ -591,19 +735,19 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
|
||||
}
|
||||
|
||||
if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
|
||||
result = append_info3_as_ndr(mem_ctx, state, &info3);
|
||||
result = append_info3_as_ndr(state->mem_ctx, state, &info3);
|
||||
} else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
|
||||
/* ntlm_auth should return the unix username, per
|
||||
'winbind use default domain' settings and the like */
|
||||
|
||||
fstring username_out;
|
||||
const char *nt_username, *nt_domain;
|
||||
if (!(nt_username = unistr2_tdup(mem_ctx, &(info3.uni_user_name)))) {
|
||||
if (!(nt_username = unistr2_tdup(state->mem_ctx, &(info3.uni_user_name)))) {
|
||||
/* If the server didn't give us one, just use the one we sent them */
|
||||
nt_username = name_user;
|
||||
}
|
||||
|
||||
if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3.uni_logon_dom)))) {
|
||||
if (!(nt_domain = unistr2_tdup(state->mem_ctx, &(info3.uni_logon_dom)))) {
|
||||
/* If the server didn't give us one, just use the one we sent them */
|
||||
nt_domain = name_domain;
|
||||
}
|
||||
@@ -653,9 +797,6 @@ done:
|
||||
state->response.data.auth.nt_status_string,
|
||||
state->response.data.auth.pam_error));
|
||||
|
||||
if (mem_ctx)
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
@@ -666,20 +807,13 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
|
||||
NTSTATUS result;
|
||||
char *oldpass, *newpass;
|
||||
fstring domain, user;
|
||||
CLI_POLICY_HND *hnd;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
POLICY_HND dom_pol;
|
||||
struct winbindd_domain *contact_domain;
|
||||
struct rpc_pipe_client *cli;
|
||||
|
||||
DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
|
||||
state->request.data.chauthtok.user));
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbind password change for %s",
|
||||
state->request.data.chauthtok.user))) {
|
||||
DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
|
||||
result = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Setup crap */
|
||||
|
||||
if (state == NULL)
|
||||
@@ -701,12 +835,15 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
|
||||
|
||||
/* Get sam handle */
|
||||
|
||||
if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(contact_domain, &hnd)) ) {
|
||||
result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
|
||||
&dom_pol);
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = cli_samr_chgpasswd_user(hnd->cli, mem_ctx, user, newpass, oldpass);
|
||||
result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass,
|
||||
oldpass);
|
||||
|
||||
done:
|
||||
state->response.data.auth.nt_status = NT_STATUS_V(result);
|
||||
@@ -721,8 +858,5 @@ done:
|
||||
state->response.data.auth.nt_status_string,
|
||||
state->response.data.auth.pam_error));
|
||||
|
||||
if (mem_ctx)
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
|
||||
enum SID_NAME_USE type;
|
||||
|
||||
uint32 num_names;
|
||||
DOM_SID **sid_mem;
|
||||
DOM_SID *sid_mem;
|
||||
char **names;
|
||||
uint32 *types;
|
||||
|
||||
@@ -126,7 +126,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
|
||||
|
||||
for (i=0; i<num_names; i++) {
|
||||
DEBUG(10, ("Adding group member SID %s\n",
|
||||
sid_string_static(sid_mem[i])));
|
||||
sid_string_static(&sid_mem[i])));
|
||||
|
||||
if (types[i] != SID_NAME_USER) {
|
||||
DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
|
||||
@@ -297,24 +297,29 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
|
||||
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *user_sid,
|
||||
uint32 *num_groups, DOM_SID ***user_gids)
|
||||
uint32 *num_groups, DOM_SID **user_gids)
|
||||
{
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
}
|
||||
|
||||
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32 num_sids, DOM_SID **sids,
|
||||
uint32 *num_aliases, uint32 **aliases)
|
||||
uint32 num_sids, const DOM_SID *sids,
|
||||
uint32 *num_aliases, uint32 **rids)
|
||||
{
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
BOOL result;
|
||||
|
||||
result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
|
||||
sids, num_sids, rids, num_aliases);
|
||||
|
||||
return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Lookup group membership given a rid. */
|
||||
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const DOM_SID *group_sid, uint32 *num_names,
|
||||
DOM_SID ***sid_mem, char ***names,
|
||||
DOM_SID **sid_mem, char ***names,
|
||||
uint32 **name_types)
|
||||
{
|
||||
return NT_STATUS_OK;
|
||||
|
||||
273
source/nsswitch/winbindd_reconnect.c
Normal file
273
source/nsswitch/winbindd_reconnect.c
Normal 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
@@ -28,12 +28,13 @@
|
||||
|
||||
/* Convert a string */
|
||||
|
||||
static void lookupsid_recv(void *private, BOOL success,
|
||||
const char *dom_name, const char *name,
|
||||
enum SID_NAME_USE type);
|
||||
|
||||
enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
|
||||
{
|
||||
enum SID_NAME_USE type;
|
||||
DOM_SID sid;
|
||||
fstring name;
|
||||
fstring dom_name;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
|
||||
@@ -41,38 +42,46 @@ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
|
||||
state->request.data.sid));
|
||||
|
||||
/* Lookup sid from PDC using lsa_lookup_sids() */
|
||||
|
||||
if (!string_to_sid(&sid, state->request.data.sid)) {
|
||||
DEBUG(5, ("%s not a SID\n", state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Lookup the sid */
|
||||
winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) {
|
||||
return WINBINDD_ERROR;
|
||||
static void lookupsid_recv(void *private, BOOL success,
|
||||
const char *dom_name, const char *name,
|
||||
enum SID_NAME_USE type)
|
||||
{
|
||||
struct winbindd_cli_state *state =
|
||||
talloc_get_type_abort(private, struct winbindd_cli_state);
|
||||
|
||||
if (!success) {
|
||||
DEBUG(5, ("lookupsid returned an error\n"));
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
request_finished(state);
|
||||
return;
|
||||
}
|
||||
|
||||
fstrcpy(state->response.data.name.dom_name, dom_name);
|
||||
fstrcpy(state->response.data.name.name, name);
|
||||
|
||||
state->response.data.name.type = type;
|
||||
|
||||
return WINBINDD_OK;
|
||||
state->response.result = WINBINDD_OK;
|
||||
request_finished(state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up the SID for a qualified name.
|
||||
**/
|
||||
|
||||
static void lookupname_recv(void *private, BOOL success,
|
||||
const DOM_SID *sid, enum SID_NAME_USE type);
|
||||
|
||||
enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
|
||||
{
|
||||
enum SID_NAME_USE type;
|
||||
fstring sid_str;
|
||||
char *name_domain, *name_user;
|
||||
DOM_SID sid;
|
||||
struct winbindd_domain *domain;
|
||||
char *p;
|
||||
|
||||
/* Ensure null termination */
|
||||
@@ -95,27 +104,48 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
|
||||
name_domain, lp_winbind_separator(), name_user));
|
||||
|
||||
if ((domain = find_lookup_domain_from_name(name_domain)) == NULL) {
|
||||
DEBUG(0, ("could not find domain entry for domain %s\n",
|
||||
name_domain));
|
||||
return WINBINDD_ERROR;
|
||||
winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
|
||||
lookupname_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
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() */
|
||||
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);
|
||||
sid_to_string(state->response.data.sid.sid, sid);
|
||||
state->response.data.sid.type = type;
|
||||
state->response.result = WINBINDD_OK;
|
||||
request_finished(state);
|
||||
return;
|
||||
}
|
||||
|
||||
return WINBINDD_OK;
|
||||
static struct winbindd_child static_idmap_child;
|
||||
|
||||
void init_idmap_child(void)
|
||||
{
|
||||
setup_domain_child(NULL, &static_idmap_child, "idmap");
|
||||
}
|
||||
|
||||
struct winbindd_child *idmap_child(void)
|
||||
{
|
||||
return &static_idmap_child;
|
||||
}
|
||||
|
||||
/* Convert a sid to a uid. We assume we only have one rid attached to the
|
||||
sid. */
|
||||
|
||||
static void sid2uid_recv(void *private, BOOL success, uid_t uid);
|
||||
|
||||
enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID sid;
|
||||
@@ -127,105 +157,53 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
|
||||
state->request.data.sid));
|
||||
|
||||
if (!string_to_sid(&sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid));
|
||||
if (idmap_proxyonly()) {
|
||||
DEBUG(8, ("IDMAP proxy only\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* This gets a little tricky. If we assume that usernames are syncd between
|
||||
/etc/passwd and the windows domain (such as a member of a Samba domain),
|
||||
the we need to get the uid from the OS and not alocate one ourselves */
|
||||
|
||||
if ( lp_winbind_trusted_domains_only() ) {
|
||||
struct winbindd_domain *domain = NULL;
|
||||
DOM_SID sid2;
|
||||
uint32 rid;
|
||||
|
||||
domain = find_our_domain();
|
||||
if ( !domain ) {
|
||||
DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
sid_copy( &sid2, &sid );
|
||||
sid_split_rid( &sid2, &rid );
|
||||
|
||||
if ( sid_equal( &sid2, &domain->sid ) ) {
|
||||
|
||||
fstring domain_name;
|
||||
fstring user;
|
||||
enum SID_NAME_USE type;
|
||||
struct passwd *pw = NULL;
|
||||
unid_t id;
|
||||
|
||||
/* ok...here's we know that we are dealing with our
|
||||
own domain (the one to which we are joined). And
|
||||
we know that there must be a UNIX account for this user.
|
||||
So we lookup the sid and the call getpwnam().*/
|
||||
|
||||
|
||||
/* But first check and see if we don't already have a mapping */
|
||||
|
||||
if ( NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), ID_QUERY_ONLY)) )
|
||||
return WINBINDD_OK;
|
||||
|
||||
/* now fall back to the hard way */
|
||||
|
||||
if ( !winbindd_lookup_name_by_sid(&sid, domain_name, user, &type) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( !(pw = getpwnam(user)) ) {
|
||||
DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
|
||||
"set but this user [%s] doesn't exist!\n", user));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
state->response.data.uid = pw->pw_uid;
|
||||
|
||||
id.uid = pw->pw_uid;
|
||||
idmap_set_mapping( &sid, id, ID_USERID );
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
if (!string_to_sid(&sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not get convert sid %s from string\n",
|
||||
state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Find uid for this sid and return it */
|
||||
/* Query only the local tdb, everything else might possibly block */
|
||||
|
||||
result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
|
||||
ID_QUERY_ONLY);
|
||||
ID_QUERY_ONLY|ID_CACHE_ONLY);
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
return WINBINDD_OK;
|
||||
|
||||
if (state->request.flags & WBFLAG_QUERY_ONLY)
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* The query-only did not work, allocate a new uid *if* it's a user */
|
||||
|
||||
{
|
||||
fstring dom_name, name;
|
||||
enum SID_NAME_USE type;
|
||||
|
||||
if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type))
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
result = idmap_sid_to_uid(&sid, &(state->response.data.uid), 0);
|
||||
winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
return WINBINDD_OK;
|
||||
static void sid2uid_recv(void *private, BOOL success, uid_t uid)
|
||||
{
|
||||
struct winbindd_cli_state *state =
|
||||
talloc_get_type_abort(private, struct winbindd_cli_state);
|
||||
|
||||
DEBUG(4, ("Could not get uid for sid %s\n", state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
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
|
||||
sid.*/
|
||||
|
||||
static void sid2gid_recv(void *private, BOOL success, gid_t gid);
|
||||
|
||||
enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID sid;
|
||||
@@ -237,250 +215,298 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
|
||||
state->request.data.sid));
|
||||
|
||||
if (!string_to_sid(&sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not cvt string to sid %s\n", state->request.data.sid));
|
||||
if (idmap_proxyonly()) {
|
||||
DEBUG(8, ("IDMAP proxy only\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* This gets a little tricky. If we assume that usernames are syncd between
|
||||
/etc/passwd and the windows domain (such as a member of a Samba domain),
|
||||
the we need to get the uid from the OS and not alocate one ourselves */
|
||||
|
||||
if ( lp_winbind_trusted_domains_only() ) {
|
||||
struct winbindd_domain *domain = NULL;
|
||||
DOM_SID sid2;
|
||||
uint32 rid;
|
||||
unid_t id;
|
||||
|
||||
domain = find_our_domain();
|
||||
if ( !domain ) {
|
||||
DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
sid_copy( &sid2, &sid );
|
||||
sid_split_rid( &sid2, &rid );
|
||||
|
||||
if ( sid_equal( &sid2, &domain->sid ) ) {
|
||||
|
||||
fstring domain_name;
|
||||
fstring group;
|
||||
enum SID_NAME_USE type;
|
||||
struct group *grp = NULL;
|
||||
|
||||
/* ok...here's we know that we are dealing with our
|
||||
own domain (the one to which we are joined). And
|
||||
we know that there must be a UNIX account for this group.
|
||||
So we lookup the sid and the call getpwnam().*/
|
||||
|
||||
/* But first check and see if we don't already have a mapping */
|
||||
|
||||
if ( NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), ID_QUERY_ONLY)) )
|
||||
return WINBINDD_OK;
|
||||
|
||||
/* now fall back to the hard way */
|
||||
|
||||
if ( !winbindd_lookup_name_by_sid(&sid, domain_name, group, &type) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( !(grp = getgrnam(group)) ) {
|
||||
DEBUG(0,("winbindd_sid_to_uid: 'winbind trusted domains only' is "
|
||||
"set but this group [%s] doesn't exist!\n", group));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
state->response.data.gid = grp->gr_gid;
|
||||
|
||||
id.gid = grp->gr_gid;
|
||||
idmap_set_mapping( &sid, id, ID_GROUPID );
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
if (!string_to_sid(&sid, state->request.data.sid)) {
|
||||
DEBUG(1, ("Could not get convert sid %s from string\n",
|
||||
state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Find gid for this sid and return it */
|
||||
/* Query only the local tdb, everything else might possibly block */
|
||||
|
||||
result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
|
||||
ID_QUERY_ONLY);
|
||||
ID_QUERY_ONLY|ID_CACHE_ONLY);
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
return WINBINDD_OK;
|
||||
|
||||
if (state->request.flags & WBFLAG_QUERY_ONLY)
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* 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);
|
||||
winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
return WINBINDD_OK;
|
||||
static void sid2gid_recv(void *private, BOOL success, gid_t gid)
|
||||
{
|
||||
struct winbindd_cli_state *state =
|
||||
talloc_get_type_abort(private, struct winbindd_cli_state);
|
||||
|
||||
DEBUG(4, ("Could not get gid for sid %s\n", state->request.data.sid));
|
||||
return WINBINDD_ERROR;
|
||||
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 */
|
||||
|
||||
struct uid2sid_state {
|
||||
struct winbindd_cli_state *cli_state;
|
||||
uid_t uid;
|
||||
fstring name;
|
||||
DOM_SID sid;
|
||||
enum SID_NAME_USE type;
|
||||
};
|
||||
|
||||
static void uid2sid_uid2name_recv(void *private, BOOL success,
|
||||
const char *username);
|
||||
static void uid2sid_lookupname_recv(void *private, BOOL success,
|
||||
const DOM_SID *sid,
|
||||
enum SID_NAME_USE type);
|
||||
static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success);
|
||||
|
||||
enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID sid;
|
||||
NTSTATUS status;
|
||||
struct uid2sid_state *uid2sid_state;
|
||||
|
||||
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
|
||||
(unsigned long)state->request.data.uid));
|
||||
|
||||
if ( (state->request.data.uid < server_state.uid_low )
|
||||
|| (state->request.data.uid > server_state.uid_high) )
|
||||
{
|
||||
struct passwd *pw = NULL;
|
||||
enum SID_NAME_USE type;
|
||||
unid_t id;
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
/* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
|
||||
|
||||
/* if we don't trust /etc/password then when can't know
|
||||
anything about this uid */
|
||||
|
||||
if ( !lp_winbind_trusted_domains_only() )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
|
||||
/* look for an idmap entry first */
|
||||
|
||||
if ( NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid)) )
|
||||
goto done;
|
||||
|
||||
/* if users exist in /etc/passwd, we should try to
|
||||
use that uid. Get the username and the lookup the SID */
|
||||
|
||||
if ( !(pw = getpwuid(state->request.data.uid)) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( !(domain = find_our_domain()) ) {
|
||||
DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if ( !winbindd_lookup_sid_by_name(domain, domain->name, pw->pw_name, &sid, &type) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( type != SID_NAME_USER )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* don't fail if we can't store it */
|
||||
|
||||
id.uid = pw->pw_uid;
|
||||
idmap_set_mapping( &sid, id, ID_USERID );
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
if (idmap_proxyonly()) {
|
||||
DEBUG(8, ("IDMAP proxy only\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
done:
|
||||
sid_to_string(state->response.data.sid.sid, &sid);
|
||||
state->response.data.sid.type = SID_NAME_USER;
|
||||
status = idmap_uid_to_sid(&sid, state->request.data.uid,
|
||||
ID_QUERY_ONLY | ID_CACHE_ONLY);
|
||||
|
||||
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 */
|
||||
|
||||
struct gid2sid_state {
|
||||
struct winbindd_cli_state *cli_state;
|
||||
gid_t gid;
|
||||
fstring name;
|
||||
DOM_SID sid;
|
||||
enum SID_NAME_USE type;
|
||||
};
|
||||
|
||||
static void gid2sid_gid2name_recv(void *private, BOOL success,
|
||||
const char *groupname);
|
||||
static void gid2sid_lookupname_recv(void *private, BOOL success,
|
||||
const DOM_SID *sid,
|
||||
enum SID_NAME_USE type);
|
||||
static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success);
|
||||
|
||||
enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID sid;
|
||||
NTSTATUS status;
|
||||
struct gid2sid_state *gid2sid_state;
|
||||
|
||||
DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
|
||||
(unsigned long)state->request.data.gid));
|
||||
|
||||
if ( (state->request.data.gid < server_state.gid_low)
|
||||
|| (state->request.data.gid > server_state.gid_high) )
|
||||
{
|
||||
struct group *grp = NULL;
|
||||
enum SID_NAME_USE type;
|
||||
unid_t id;
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
/* SPECIAL CASE FOR MEMBERS OF SAMBA DOMAINS */
|
||||
|
||||
/* if we don't trust /etc/group then when can't know
|
||||
anything about this gid */
|
||||
|
||||
if ( !lp_winbind_trusted_domains_only() )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* look for an idmap entry first */
|
||||
|
||||
if ( NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid)) )
|
||||
goto done;
|
||||
|
||||
/* if users exist in /etc/group, we should try to
|
||||
use that gid. Get the username and the lookup the SID */
|
||||
|
||||
if ( !(grp = getgrgid(state->request.data.gid)) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( !(domain = find_our_domain()) ) {
|
||||
DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if ( !winbindd_lookup_sid_by_name(domain, domain->name, grp->gr_name, &sid, &type) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
if ( type!=SID_NAME_DOM_GRP && type!=SID_NAME_ALIAS )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* don't fail if we can't store it */
|
||||
|
||||
id.gid = grp->gr_gid;
|
||||
idmap_set_mapping( &sid, id, ID_GROUPID );
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
if (idmap_proxyonly()) {
|
||||
DEBUG(8, ("IDMAP proxy only\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
done:
|
||||
/* Construct sid and return it */
|
||||
sid_to_string(state->response.data.sid.sid, &sid);
|
||||
state->response.data.sid.type = SID_NAME_DOM_GRP;
|
||||
status = idmap_gid_to_sid(&sid, state->request.data.gid,
|
||||
ID_QUERY_ONLY | ID_CACHE_ONLY);
|
||||
|
||||
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)
|
||||
@@ -491,6 +517,15 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
async_request(state->mem_ctx, idmap_child(),
|
||||
&state->request, &state->response,
|
||||
request_finished_cont, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
/* We tell idmap to always allocate a user RID. There might be a good
|
||||
* reason to keep RID allocation for users to even and groups to
|
||||
* odd. This needs discussion I think. For now only allocate user
|
||||
@@ -502,3 +537,45 @@ enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state)
|
||||
{
|
||||
if ( !state->privileged ) {
|
||||
DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
|
||||
"denied!\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
async_request(state->mem_ctx, idmap_child(),
|
||||
&state->request, &state->response,
|
||||
request_finished_cont, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
NTSTATUS result;
|
||||
DOM_SID sid;
|
||||
|
||||
/* We tell idmap to always allocate a user RID. This is really
|
||||
* historic and needs to be fixed. I *think* this has to do with the
|
||||
* way winbind determines its free RID space. */
|
||||
|
||||
result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid,
|
||||
USER_RID_TYPE);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
sid_copy(&sid, get_global_sam_sid());
|
||||
sid_append_rid(&sid, state->response.data.rid_and_gid.rid);
|
||||
|
||||
result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid,
|
||||
0);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
@@ -106,17 +106,208 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
|
||||
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. */
|
||||
|
||||
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;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
fstring domname, username;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.data.username[sizeof(state->request.data.username)-1]='\0';
|
||||
@@ -124,67 +315,57 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
|
||||
state->request.data.username));
|
||||
|
||||
/* Parse domain and username */
|
||||
if (!parse_domain_user(state->request.data.username, domname,
|
||||
username)) {
|
||||
DEBUG(0, ("Could not parse domain user: %s\n",
|
||||
state->request.data.username));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
parse_domain_user(state->request.data.username,
|
||||
name_domain, name_user);
|
||||
/* Get info for the domain */
|
||||
|
||||
/* should we deal with users for our domain? */
|
||||
domain = find_lookup_domain_from_name(domname);
|
||||
|
||||
if ((domain = find_domain_from_name(name_domain)) == NULL) {
|
||||
DEBUG(5, ("no such domain: %s\n", name_domain));
|
||||
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()) {
|
||||
DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n",
|
||||
name_domain, name_user));
|
||||
DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
|
||||
"getgroups() for %s\\%s.\n", domname, username));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Get rid and name type from name */
|
||||
/* 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, &name_type)) {
|
||||
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) {
|
||||
DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
|
||||
name_type));
|
||||
return WINBINDD_ERROR;
|
||||
if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
|
||||
DEBUG(5, ("%s is not a user\n", state->request.data.username));
|
||||
state->response.result = WINBINDD_ERROR;
|
||||
request_finished(state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
&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;
|
||||
winbindd_getpwsid(state, sid);
|
||||
}
|
||||
|
||||
/* Return a password structure given a uid number */
|
||||
@@ -192,14 +373,7 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
|
||||
enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID user_sid;
|
||||
struct winbindd_domain *domain;
|
||||
fstring dom_name;
|
||||
fstring user_name;
|
||||
enum SID_NAME_USE name_type;
|
||||
WINBIND_USERINFO user_info;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
NTSTATUS status;
|
||||
gid_t gid;
|
||||
|
||||
/* Bug out if the uid isn't in the winbind range */
|
||||
|
||||
@@ -210,70 +384,17 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
|
||||
DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
|
||||
(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))) {
|
||||
DEBUG(1, ("could not convert uid %lu to SID\n",
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(5, ("Could not find SID for uid %lu\n",
|
||||
(unsigned long)state->request.data.uid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Get name and name type from rid */
|
||||
|
||||
if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) {
|
||||
fstring temp;
|
||||
|
||||
sid_to_string(temp, &user_sid);
|
||||
DEBUG(1, ("could not lookup sid %s\n", temp));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
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;
|
||||
winbindd_getpwsid(state, &user_sid);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -365,14 +486,13 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
|
||||
field is incremented to the index of the next user to fetch. Return True if
|
||||
some users were returned, False otherwise. */
|
||||
|
||||
static BOOL get_sam_user_entries(struct getent_state *ent)
|
||||
static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint32 num_entries;
|
||||
WINBIND_USERINFO *info;
|
||||
struct getpwent_user *name_list = NULL;
|
||||
BOOL result = False;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_domain *domain;
|
||||
struct winbindd_methods *methods;
|
||||
unsigned int i;
|
||||
@@ -380,10 +500,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
|
||||
if (ent->num_sam_entries)
|
||||
return False;
|
||||
|
||||
if (!(mem_ctx = talloc_init("get_sam_user_entries(%s)",
|
||||
ent->domain_name)))
|
||||
return False;
|
||||
|
||||
if (!(domain = find_domain_from_name(ent->domain_name))) {
|
||||
DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
|
||||
ent->domain_name));
|
||||
@@ -433,8 +549,10 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
|
||||
}
|
||||
|
||||
/* User and group ids */
|
||||
sid_copy(&name_list[ent->num_sam_entries+i].user_sid, info[i].user_sid);
|
||||
sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_sid);
|
||||
sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
|
||||
&info[i].user_sid);
|
||||
sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
|
||||
&info[i].group_sid);
|
||||
}
|
||||
|
||||
ent->num_sam_entries += num_entries;
|
||||
@@ -447,8 +565,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
|
||||
|
||||
done:
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -497,7 +613,8 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
|
||||
|
||||
if (ent->num_sam_entries == ent->sam_entry_index) {
|
||||
|
||||
while(ent && !get_sam_user_entries(ent)) {
|
||||
while(ent &&
|
||||
!get_sam_user_entries(ent, state->mem_ctx)) {
|
||||
struct getent_state *next_ent;
|
||||
|
||||
/* Free state information for this domain */
|
||||
@@ -560,14 +677,10 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
|
||||
uint32 num_entries = 0, total_entries = 0;
|
||||
char *ted, *extra_data = NULL;
|
||||
int extra_data_len = 0;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
enum winbindd_result rv = WINBINDD_ERROR;
|
||||
|
||||
DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbindd_list_users")))
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
|
||||
which_domain = state->request.domain_name;
|
||||
@@ -586,13 +699,10 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
|
||||
if ( *which_domain && !strequal(which_domain, domain->name) )
|
||||
continue;
|
||||
|
||||
if ( !domain->initialized )
|
||||
set_dc_type_and_flags( domain );
|
||||
|
||||
methods = domain->methods;
|
||||
|
||||
/* Query display info */
|
||||
status = methods->query_user_list(domain, mem_ctx,
|
||||
status = methods->query_user_list(domain, state->mem_ctx,
|
||||
&num_entries, &info);
|
||||
|
||||
if (num_entries == 0)
|
||||
@@ -646,7 +756,5 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
|
||||
|
||||
done:
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
#include "includes.h"
|
||||
#include "winbindd.h"
|
||||
|
||||
extern struct winbindd_methods cache_methods;
|
||||
extern struct winbindd_methods passdb_methods;
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
|
||||
@@ -65,8 +62,7 @@ struct winbindd_domain *domain_list(void)
|
||||
/* Initialise list */
|
||||
|
||||
if (!_domain_list)
|
||||
if (!init_domain_list())
|
||||
return NULL;
|
||||
init_domain_list();
|
||||
|
||||
return _domain_list;
|
||||
}
|
||||
@@ -91,12 +87,7 @@ static BOOL is_internal_domain(const DOM_SID *sid)
|
||||
if (sid == NULL)
|
||||
return False;
|
||||
|
||||
if ( sid_compare_domain( sid, get_global_sam_sid() ) == 0 )
|
||||
return True;
|
||||
if ( sid_compare_domain( sid, &global_sid_Builtin ) == 0 )
|
||||
return True;
|
||||
|
||||
return False;
|
||||
return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
|
||||
}
|
||||
|
||||
|
||||
@@ -181,80 +172,115 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
|
||||
rescan our domains looking for new trusted domains
|
||||
********************************************************************/
|
||||
|
||||
struct trustdom_state {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_response *response;
|
||||
};
|
||||
|
||||
static void trustdom_recv(void *private, BOOL success);
|
||||
|
||||
static void add_trusted_domains( struct winbindd_domain *domain )
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
NTSTATUS result;
|
||||
time_t t;
|
||||
char **names;
|
||||
char **alt_names;
|
||||
int num_domains = 0;
|
||||
DOM_SID *dom_sids, null_sid;
|
||||
int i;
|
||||
struct winbindd_domain *new_domain;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
|
||||
/* trusted domains might be disabled */
|
||||
if (!lp_allow_trusted_domains()) {
|
||||
struct trustdom_state *state;
|
||||
|
||||
mem_ctx = talloc_init("add_trusted_domains");
|
||||
if (mem_ctx == NULL) {
|
||||
DEBUG(0, ("talloc_init failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(5, ("scanning trusted domain list\n"));
|
||||
request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
|
||||
response = TALLOC_P(mem_ctx, struct winbindd_response);
|
||||
state = TALLOC_P(mem_ctx, struct trustdom_state);
|
||||
|
||||
if (!(mem_ctx = talloc_init("init_domain_list")))
|
||||
if ((request == NULL) || (response == NULL) || (state == NULL)) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
talloc_destroy(mem_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(&null_sid);
|
||||
state->mem_ctx = mem_ctx;
|
||||
state->response = response;
|
||||
|
||||
t = time(NULL);
|
||||
request->length = sizeof(*request);
|
||||
request->cmd = WINBINDD_LIST_TRUSTDOM;
|
||||
|
||||
/* ask the DC what domains it trusts */
|
||||
async_domain_request(mem_ctx, domain, request, response,
|
||||
trustdom_recv, state);
|
||||
}
|
||||
|
||||
result = domain->methods->trusted_domains(domain, mem_ctx, (unsigned int *)&num_domains,
|
||||
&names, &alt_names, &dom_sids);
|
||||
static void trustdom_recv(void *private, BOOL success)
|
||||
{
|
||||
extern struct winbindd_methods cache_methods;
|
||||
struct trustdom_state *state =
|
||||
talloc_get_type_abort(private, struct trustdom_state);
|
||||
struct winbindd_response *response = state->response;
|
||||
char *p;
|
||||
|
||||
if ( NT_STATUS_IS_OK(result) ) {
|
||||
if ((!success) || (response->result != WINBINDD_OK)) {
|
||||
DEBUG(1, ("Could not receive trustdoms\n"));
|
||||
talloc_destroy(state->mem_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add each domain to the trusted domain list */
|
||||
p = response->extra_data;
|
||||
|
||||
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]);
|
||||
while ((p != NULL) && (*p != '\0')) {
|
||||
char *q, *sidstr, *alt_name;
|
||||
DOM_SID sid;
|
||||
|
||||
/* if the SID was empty, we better set it now */
|
||||
|
||||
if ( sid_equal(&dom_sids[i], &null_sid) ) {
|
||||
enum SID_NAME_USE type;
|
||||
new_domain = find_domain_from_name(names[i]);
|
||||
|
||||
/* this should never happen */
|
||||
if ( !new_domain ) {
|
||||
DEBUG(0,("rescan_trust_domains: can't find the domain I just added! [%s]\n",
|
||||
names[i]));
|
||||
break;
|
||||
}
|
||||
|
||||
/* call the cache method; which will operate on the winbindd_domain \
|
||||
passed in and choose either rpc or ads as appropriate */
|
||||
|
||||
result = domain->methods->name_to_sid( domain,
|
||||
mem_ctx,
|
||||
new_domain->name,
|
||||
NULL,
|
||||
&new_domain->sid,
|
||||
&type);
|
||||
|
||||
if ( NT_STATUS_IS_OK(result) )
|
||||
sid_copy( &dom_sids[i], &new_domain->sid );
|
||||
}
|
||||
|
||||
/* store trusted domain in the cache */
|
||||
trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL,
|
||||
&dom_sids[i], t + WINBINDD_RESCAN_FREQ);
|
||||
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 )
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct winbindd_domain *mydomain = NULL;
|
||||
|
||||
/* see if the time has come... */
|
||||
|
||||
if ( (now > last_trustdom_scan) && ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
|
||||
if ((now >= last_trustdom_scan) &&
|
||||
((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
|
||||
return;
|
||||
|
||||
if ( (mydomain = find_our_domain()) == NULL ) {
|
||||
DEBUG(0,("rescan_trusted_domains: Can't find my own domain!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* this will only add new domains we didn't already know about */
|
||||
|
||||
add_trusted_domains( mydomain );
|
||||
add_trusted_domains( find_our_domain() );
|
||||
|
||||
last_trustdom_scan = now;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look up global info for the winbind daemon */
|
||||
BOOL init_domain_list(void)
|
||||
struct init_child_state {
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_domain *domain;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
void (*continuation)(void *private, BOOL success);
|
||||
void *private;
|
||||
};
|
||||
|
||||
static void init_child_recv(void *private, BOOL success);
|
||||
static void init_child_getdc_recv(void *private, BOOL success);
|
||||
|
||||
enum winbindd_result init_child_connection(struct winbindd_domain *domain,
|
||||
void (*continuation)(void *private,
|
||||
BOOL success),
|
||||
void *private)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct winbindd_request *request;
|
||||
struct winbindd_response *response;
|
||||
struct init_child_state *state;
|
||||
|
||||
mem_ctx = talloc_init("init_child_connection");
|
||||
if (mem_ctx == NULL) {
|
||||
DEBUG(0, ("talloc_init failed\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
|
||||
response = TALLOC_P(mem_ctx, struct winbindd_response);
|
||||
state = TALLOC_P(mem_ctx, struct init_child_state);
|
||||
|
||||
if ((request == NULL) || (response == NULL) || (state == NULL)) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
continuation(private, False);
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
request->length = sizeof(*request);
|
||||
|
||||
state->mem_ctx = mem_ctx;
|
||||
state->domain = domain;
|
||||
state->request = request;
|
||||
state->response = response;
|
||||
state->continuation = continuation;
|
||||
state->private = private;
|
||||
|
||||
if (domain->primary) {
|
||||
/* The primary domain has to find the DC name itself */
|
||||
request->cmd = WINBINDD_INIT_CONNECTION;
|
||||
fstrcpy(request->domain_name, domain->name);
|
||||
request->data.init_conn.is_primary = True;
|
||||
fstrcpy(request->data.init_conn.dcname, "");
|
||||
|
||||
async_request(mem_ctx, &domain->child, request, response,
|
||||
init_child_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
/* This is *not* the primary domain, let's ask our DC about a DC
|
||||
* name */
|
||||
|
||||
request->cmd = WINBINDD_GETDCNAME;
|
||||
fstrcpy(request->domain_name, domain->name);
|
||||
|
||||
async_domain_request(mem_ctx, find_our_domain(), request, response,
|
||||
init_child_getdc_recv, state);
|
||||
return WINBINDD_PENDING;
|
||||
}
|
||||
|
||||
static void init_child_getdc_recv(void *private, BOOL success)
|
||||
{
|
||||
struct init_child_state *state =
|
||||
talloc_get_type_abort(private, struct init_child_state);
|
||||
const char *dcname = "";
|
||||
|
||||
DEBUG(10, ("Received getdcname response\n"));
|
||||
|
||||
if (success && (state->response->result == WINBINDD_OK)) {
|
||||
dcname = state->response->data.dc_name;
|
||||
}
|
||||
|
||||
state->request->cmd = WINBINDD_INIT_CONNECTION;
|
||||
fstrcpy(state->request->domain_name, state->domain->name);
|
||||
state->request->data.init_conn.is_primary = False;
|
||||
fstrcpy(state->request->data.init_conn.dcname, dcname);
|
||||
|
||||
async_request(state->mem_ctx, &state->domain->child,
|
||||
state->request, state->response,
|
||||
init_child_recv, state);
|
||||
}
|
||||
|
||||
static void init_child_recv(void *private, BOOL success)
|
||||
{
|
||||
struct init_child_state *state =
|
||||
talloc_get_type_abort(private, struct init_child_state);
|
||||
|
||||
DEBUG(5, ("Received child initialization response for domain %s\n",
|
||||
state->domain->name));
|
||||
|
||||
if ((!success) || (state->response->result != WINBINDD_OK)) {
|
||||
DEBUG(3, ("Could not init child\n"));
|
||||
state->continuation(state->private, False);
|
||||
talloc_destroy(state->mem_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
fstrcpy(state->domain->name,
|
||||
state->response->data.domain_info.name);
|
||||
fstrcpy(state->domain->alt_name,
|
||||
state->response->data.domain_info.alt_name);
|
||||
string_to_sid(&state->domain->sid,
|
||||
state->response->data.domain_info.sid);
|
||||
state->domain->native_mode =
|
||||
state->response->data.domain_info.native_mode;
|
||||
state->domain->active_directory =
|
||||
state->response->data.domain_info.active_directory;
|
||||
state->domain->sequence_number =
|
||||
state->response->data.domain_info.sequence_number;
|
||||
|
||||
state->domain->initialized = 1;
|
||||
|
||||
if (state->continuation != NULL)
|
||||
state->continuation(state->private, True);
|
||||
talloc_destroy(state->mem_ctx);
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
struct in_addr ipaddr;
|
||||
|
||||
/* Ensure null termination */
|
||||
state->request.domain_name
|
||||
[sizeof(state->request.domain_name)-1]='\0';
|
||||
state->request.data.init_conn.dcname
|
||||
[sizeof(state->request.data.init_conn.dcname)-1]='\0';
|
||||
|
||||
fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
|
||||
|
||||
if (strlen(domain->dcname) > 0) {
|
||||
if (!resolve_name(domain->dcname, &ipaddr, 0x20)) {
|
||||
DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
|
||||
domain->dcname, domain->name));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
domain->dcaddr.sin_family = PF_INET;
|
||||
putip((char *)&(domain->dcaddr.sin_addr), (char *)&ipaddr);
|
||||
domain->dcaddr.sin_port = 0;
|
||||
}
|
||||
|
||||
set_dc_type_and_flags(domain);
|
||||
|
||||
if (!domain->initialized) {
|
||||
DEBUG(1, ("Could not initialize domain %s\n",
|
||||
state->request.domain_name));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
fstrcpy(state->response.data.domain_info.name, domain->name);
|
||||
fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
|
||||
fstrcpy(state->response.data.domain_info.sid,
|
||||
sid_string_static(&domain->sid));
|
||||
|
||||
state->response.data.domain_info.native_mode
|
||||
= domain->native_mode;
|
||||
state->response.data.domain_info.active_directory
|
||||
= domain->active_directory;
|
||||
state->response.data.domain_info.primary
|
||||
= domain->primary;
|
||||
state->response.data.domain_info.sequence_number =
|
||||
domain->sequence_number;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Look up global info for the winbind daemon */
|
||||
void init_domain_list(void)
|
||||
{
|
||||
extern struct winbindd_methods cache_methods;
|
||||
extern struct winbindd_methods passdb_methods;
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
/* Free existing list */
|
||||
@@ -297,50 +497,35 @@ BOOL init_domain_list(void)
|
||||
|
||||
if (IS_DC) {
|
||||
domain = add_trusted_domain(get_global_sam_name(), NULL,
|
||||
&passdb_methods, get_global_sam_sid());
|
||||
&passdb_methods,
|
||||
get_global_sam_sid());
|
||||
} else {
|
||||
|
||||
domain = add_trusted_domain( lp_workgroup(), lp_realm(),
|
||||
&cache_methods, NULL);
|
||||
DOM_SID our_sid;
|
||||
|
||||
/* set flags about native_mode, active_directory */
|
||||
set_dc_type_and_flags(domain);
|
||||
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(),
|
||||
&cache_methods, &our_sid);
|
||||
}
|
||||
|
||||
domain->primary = True;
|
||||
|
||||
/* 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);
|
||||
|
||||
setup_domain_child(domain, &domain->child, NULL);
|
||||
|
||||
/* Add our local SAM domains */
|
||||
|
||||
add_trusted_domain("BUILTIN", NULL, &passdb_methods,
|
||||
&global_sid_Builtin);
|
||||
domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
|
||||
&global_sid_Builtin);
|
||||
setup_domain_child(domain, &domain->child, NULL);
|
||||
|
||||
if (!IS_DC) {
|
||||
add_trusted_domain(get_global_sam_name(), NULL,
|
||||
&passdb_methods, get_global_sam_sid());
|
||||
domain = add_trusted_domain(get_global_sam_name(), NULL,
|
||||
&passdb_methods,
|
||||
get_global_sam_sid());
|
||||
setup_domain_child(domain, &domain->child, NULL);
|
||||
}
|
||||
|
||||
/* avoid rescanning this right away */
|
||||
last_trustdom_scan = time(NULL);
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +540,7 @@ BOOL init_domain_list(void)
|
||||
* @return The domain structure for the named domain, if it is working.
|
||||
*/
|
||||
|
||||
struct winbindd_domain *find_domain_from_name(const char *domain_name)
|
||||
struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
@@ -363,10 +548,8 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
|
||||
|
||||
for (domain = domain_list(); domain != NULL; domain = domain->next) {
|
||||
if (strequal(domain_name, domain->name) ||
|
||||
(domain->alt_name[0] && strequal(domain_name, domain->alt_name))) {
|
||||
if (!domain->initialized)
|
||||
set_dc_type_and_flags(domain);
|
||||
|
||||
(domain->alt_name[0] &&
|
||||
strequal(domain_name, domain->alt_name))) {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
@@ -376,29 +559,56 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct winbindd_domain *find_domain_from_name(const char *domain_name)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
domain = find_domain_from_name_noinit(domain_name);
|
||||
|
||||
if (domain == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!domain->initialized)
|
||||
set_dc_type_and_flags(domain);
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
/* Given a domain sid, return the struct winbindd domain info for it */
|
||||
|
||||
struct winbindd_domain *find_domain_from_sid_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 */
|
||||
|
||||
struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
/* Search through list */
|
||||
domain = find_domain_from_sid_noinit(sid);
|
||||
|
||||
for (domain = domain_list(); domain != NULL; domain = domain->next) {
|
||||
if (sid_compare_domain(sid, &domain->sid) == 0) {
|
||||
if (!domain->initialized)
|
||||
set_dc_type_and_flags(domain);
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
if (domain == NULL)
|
||||
return NULL;
|
||||
|
||||
/* 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 *domain;
|
||||
@@ -410,11 +620,24 @@ struct winbindd_domain *find_our_domain(void)
|
||||
return domain;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
|
||||
smb_panic("Could not find our domain\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct winbindd_domain *find_builtin_domain(void)
|
||||
{
|
||||
DOM_SID sid;
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
string_to_sid(&sid, "S-1-5-32");
|
||||
domain = find_domain_from_sid(&sid);
|
||||
|
||||
if (domain == NULL)
|
||||
smb_panic("Could not find BUILTIN domain\n");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
/* Find the appropriate domain to lookup a name or SID */
|
||||
|
||||
struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
|
||||
@@ -436,31 +659,24 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
|
||||
{
|
||||
if (IS_DC || strequal(domain_name, "BUILTIN") ||
|
||||
strequal(domain_name, get_global_sam_name()))
|
||||
return find_domain_from_name(domain_name);
|
||||
return find_domain_from_name_noinit(domain_name);
|
||||
|
||||
return find_our_domain();
|
||||
}
|
||||
|
||||
/* Lookup a sid in a domain from a name */
|
||||
|
||||
BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
|
||||
BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_domain *domain,
|
||||
const char *domain_name,
|
||||
const char *name, DOM_SID *sid,
|
||||
enum SID_NAME_USE *type)
|
||||
{
|
||||
NTSTATUS result;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
mem_ctx = talloc_init("lookup_sid_by_name for %s\\%s\n",
|
||||
domain_name, name);
|
||||
if (!mem_ctx)
|
||||
return False;
|
||||
|
||||
/* Lookup name */
|
||||
result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
/* Return rid and type if lookup successful */
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
*type = SID_NAME_UNKNOWN;
|
||||
@@ -480,7 +696,8 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
|
||||
* @retval True if the name exists, in which case @p name and @p type
|
||||
* are set, otherwise False.
|
||||
**/
|
||||
BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
|
||||
BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
|
||||
DOM_SID *sid,
|
||||
fstring dom_name,
|
||||
fstring name,
|
||||
enum SID_NAME_USE *type)
|
||||
@@ -488,7 +705,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
|
||||
char *names;
|
||||
char *dom_names;
|
||||
NTSTATUS result;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
BOOL rv = False;
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
@@ -501,9 +717,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
|
||||
|
||||
/* Lookup name */
|
||||
|
||||
if (!(mem_ctx = talloc_init("winbindd_lookup_name_by_sid")))
|
||||
return False;
|
||||
|
||||
result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
|
||||
|
||||
/* Return name and type if successful */
|
||||
@@ -516,12 +729,9 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
|
||||
fstrcpy(name, name_deadbeef);
|
||||
}
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* Free state information held for {set,get,end}{pw,gr}ent() functions */
|
||||
|
||||
void free_getent_state(struct getent_state *state)
|
||||
@@ -553,31 +763,30 @@ BOOL winbindd_param_init(void)
|
||||
/* Parse winbind uid and winbind_gid parameters */
|
||||
|
||||
if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
|
||||
DEBUG(2, ("winbindd: idmap uid range missing or invalid\n"));
|
||||
DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
|
||||
DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
|
||||
DEBUG(2, ("winbindd: idmap gid range missing or invalid\n"));
|
||||
DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
|
||||
DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Check if a domain is present in a comma-separated list of domains */
|
||||
|
||||
BOOL check_domain_env(char *domain_env, char *domain)
|
||||
BOOL is_in_uid_range(uid_t uid)
|
||||
{
|
||||
fstring name;
|
||||
const char *tmp = domain_env;
|
||||
return ((uid >= server_state.uid_low) &&
|
||||
(uid <= server_state.uid_high));
|
||||
}
|
||||
|
||||
while(next_token(&tmp, name, ",", sizeof(fstring))) {
|
||||
if (strequal(name, domain))
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
BOOL is_in_gid_range(gid_t gid)
|
||||
{
|
||||
return ((gid >= server_state.gid_low) &&
|
||||
(gid <= server_state.gid_high));
|
||||
}
|
||||
|
||||
/* Is this a domain which we may assume no DOMAIN\ prefix? */
|
||||
@@ -620,6 +829,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
|
||||
char **domain, char **user)
|
||||
{
|
||||
fstring fstr_domain, fstr_user;
|
||||
parse_domain_user(domuser, fstr_domain, fstr_user);
|
||||
*domain = talloc_strdup(mem_ctx, fstr_domain);
|
||||
*user = talloc_strdup(mem_ctx, fstr_user);
|
||||
return ((*domain != NULL) && (*user != NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
|
||||
'winbind separator' options.
|
||||
@@ -635,14 +854,16 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
|
||||
*/
|
||||
void fill_domain_username(fstring name, const char *domain, const char *user)
|
||||
{
|
||||
strlower_m(CONST_DISCARD(char *, user));
|
||||
fstring tmp_user;
|
||||
|
||||
fstrcpy(tmp_user, user);
|
||||
|
||||
if (assume_domain(domain)) {
|
||||
strlcpy(name, user, sizeof(fstring));
|
||||
} else {
|
||||
slprintf(name, sizeof(fstring) - 1, "%s%c%s",
|
||||
domain, *lp_winbind_separator(),
|
||||
user);
|
||||
tmp_user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,22 +985,6 @@ int winbindd_num_clients(void)
|
||||
return _num_clients;
|
||||
}
|
||||
|
||||
/* Help with RID -> SID conversion */
|
||||
|
||||
DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32 rid)
|
||||
{
|
||||
DOM_SID *sid;
|
||||
sid = TALLOC_P(mem_ctx, DOM_SID);
|
||||
if (!sid) {
|
||||
smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
|
||||
}
|
||||
sid_copy(sid, &domain->sid);
|
||||
sid_append_rid(sid, rid);
|
||||
return sid;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
For idmap conversion: convert one record to new format
|
||||
Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
|
||||
@@ -986,52 +1191,3 @@ BOOL winbindd_upgrade_idmap(void)
|
||||
|
||||
return idmap_convert(idmap_name);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
wrapper around retrieving the trust account password
|
||||
*******************************************************************/
|
||||
|
||||
BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
|
||||
time_t *pass_last_set_time, uint32 *channel)
|
||||
{
|
||||
DOM_SID sid;
|
||||
char *pwd;
|
||||
|
||||
/* if we are a DC and this is not our domain, then lookup an account
|
||||
for the domain trust */
|
||||
|
||||
if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() )
|
||||
{
|
||||
if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
|
||||
pass_last_set_time) )
|
||||
{
|
||||
DEBUG(0, ("get_trust_pw: could not fetch trust account "
|
||||
"password for trusted domain %s\n", domain));
|
||||
return False;
|
||||
}
|
||||
|
||||
*channel = SEC_CHAN_DOMAIN;
|
||||
E_md4hash(pwd, ret_pwd);
|
||||
SAFE_FREE(pwd);
|
||||
|
||||
return True;
|
||||
}
|
||||
else /* just get the account for our domain (covers
|
||||
ROLE_DOMAIN_MEMBER as well */
|
||||
{
|
||||
/* get the machine trust account for our domain */
|
||||
|
||||
if ( !secrets_fetch_trust_account_password (lp_workgroup(), ret_pwd,
|
||||
pass_last_set_time, channel) )
|
||||
{
|
||||
DEBUG(0, ("get_trust_pw: could not fetch trust account "
|
||||
"password for my domain %s\n", domain));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Failure */
|
||||
}
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@ typedef struct
|
||||
int min_passwd_length;
|
||||
int oplock_break_wait_time;
|
||||
int winbind_cache_time;
|
||||
int winbind_max_idle_children;
|
||||
int iLockSpinCount;
|
||||
int iLockSpinTime;
|
||||
char *szLdapMachineSuffix;
|
||||
@@ -1223,6 +1224,7 @@ static struct parm_struct parm_table[] = {
|
||||
{"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED},
|
||||
{"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED},
|
||||
{"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED},
|
||||
{"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED},
|
||||
|
||||
{NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
|
||||
};
|
||||
@@ -1567,6 +1569,7 @@ static void init_globals(void)
|
||||
Globals.bWinbindUseDefaultDomain = False;
|
||||
Globals.bWinbindTrustedDomainsOnly = False;
|
||||
Globals.bWinbindNestedGroups = False;
|
||||
Globals.winbind_max_idle_children = 3;
|
||||
|
||||
Globals.bEnableRidAlgorithm = True;
|
||||
|
||||
@@ -1986,6 +1989,7 @@ FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
|
||||
FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size);
|
||||
FN_LOCAL_CHAR(lp_magicchar, magic_char)
|
||||
FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
|
||||
FN_GLOBAL_INTEGER(lp_winbind_max_idle_children, &Globals.winbind_max_idle_children)
|
||||
FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
|
||||
FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
|
||||
FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
|
||||
|
||||
@@ -112,6 +112,44 @@ BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAM
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL sid_to_local_user_name(const DOM_SID *sid, fstring username)
|
||||
{
|
||||
fstring dom_name;
|
||||
fstring name;
|
||||
enum SID_NAME_USE type;
|
||||
|
||||
if (!sid_check_is_in_our_domain(sid))
|
||||
return False;
|
||||
|
||||
if (!lookup_sid(sid, dom_name, name, &type))
|
||||
return False;
|
||||
|
||||
if (type != SID_NAME_USER)
|
||||
return False;
|
||||
|
||||
fstrcpy(username, name);
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL sid_to_local_dom_grp_name(const DOM_SID *sid, fstring groupname)
|
||||
{
|
||||
fstring dom_name;
|
||||
fstring name;
|
||||
enum SID_NAME_USE type;
|
||||
|
||||
if (!sid_check_is_in_our_domain(sid))
|
||||
return False;
|
||||
|
||||
if (!lookup_sid(sid, dom_name, name, &type))
|
||||
return False;
|
||||
|
||||
if (type != SID_NAME_DOM_GRP)
|
||||
return False;
|
||||
|
||||
fstrcpy(groupname, name);
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Id mapping cache. This is to avoid Winbind mappings already
|
||||
@@ -250,8 +288,8 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
|
||||
if (sid_compare(&pc->sid, psid) == 0) {
|
||||
fstring sid;
|
||||
*pgid = pc->gid;
|
||||
DEBUG(3,("fetch uid from cache %u -> %s\n",
|
||||
(unsigned int)*pgid, sid_to_string(sid, psid)));
|
||||
DEBUG(3,("fetch gid from cache %u -> %s\n",
|
||||
(unsigned int)*pgid, sid_to_string(sid, psid)));
|
||||
DLIST_PROMOTE(gid_sid_cache_head, pc);
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -906,7 +906,7 @@ static int printing_value_info( char *key, REGVAL_CTR *val )
|
||||
|
||||
static BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
|
||||
{
|
||||
return False;
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@@ -917,7 +917,7 @@ static BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
|
||||
|
||||
static BOOL printing_store_value( char *key, REGVAL_CTR *val )
|
||||
{
|
||||
return False;
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
Get information about the server and directory services
|
||||
********************************************************************/
|
||||
|
||||
NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
uint16 level, DS_DOMINFO_CTR *ctr)
|
||||
NTSTATUS rpccli_ds_getprimarydominfo(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint16 level, DS_DOMINFO_CTR *ctr)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
DS_Q_GETPRIMDOMINFO q;
|
||||
@@ -50,7 +51,7 @@ NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
q.level = level;
|
||||
|
||||
if (!ds_io_q_getprimdominfo("", &qbuf, 0, &q)
|
||||
|| !rpc_api_pipe_req(cli, PI_LSARPC_DS, DS_GETPRIMDOMINFO, &qbuf, &rbuf)) {
|
||||
|| !rpc_api_pipe_req_int(cli, DS_GETPRIMDOMINFO, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -81,13 +82,23 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_ds_getprimarydominfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
uint16 level, DS_DOMINFO_CTR *ctr)
|
||||
{
|
||||
return rpccli_ds_getprimarydominfo(&cli->pipes[PI_LSARPC_DS], mem_ctx,
|
||||
level, ctr);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
Enumerate trusted domains in an AD forest
|
||||
********************************************************************/
|
||||
|
||||
NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *server, uint32 flags,
|
||||
struct ds_domain_trust **trusts, uint32 *num_domains)
|
||||
NTSTATUS rpccli_ds_enum_domain_trusts(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *server, uint32 flags,
|
||||
struct ds_domain_trust **trusts,
|
||||
uint32 *num_domains)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
DS_Q_ENUM_DOM_TRUSTS q;
|
||||
@@ -110,7 +121,7 @@ NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_q_ds_enum_domain_trusts( &q, server, flags );
|
||||
|
||||
if (!ds_io_q_enum_domain_trusts("", &qbuf, 0, &q)
|
||||
|| !rpc_api_pipe_req(cli, PI_NETLOGON, DS_ENUM_DOM_TRUSTS, &qbuf, &rbuf)) {
|
||||
|| !rpc_api_pipe_req_int(cli, DS_ENUM_DOM_TRUSTS, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -163,3 +174,13 @@ done:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_ds_enum_domain_trusts(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *server, uint32 flags,
|
||||
struct ds_domain_trust **trusts,
|
||||
uint32 *num_domains)
|
||||
{
|
||||
return rpccli_ds_enum_domain_trusts(&cli->pipes[PI_NETLOGON], mem_ctx,
|
||||
server, flags, trusts,
|
||||
num_domains);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@
|
||||
*
|
||||
* @param cli Handle on an initialised SMB connection */
|
||||
|
||||
NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
|
||||
NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
BOOL sec_qos, uint32 des_access,
|
||||
POLICY_HND *pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_OPEN_POL q;
|
||||
@@ -52,6 +54,8 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
LSA_SEC_QOS qos;
|
||||
NTSTATUS result;
|
||||
|
||||
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
|
||||
@@ -72,7 +76,7 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!lsa_io_q_open_pol("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_OPENPOLICY, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_OPENPOLICY, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -100,13 +104,21 @@ NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
|
||||
{
|
||||
return rpccli_lsa_open_policy(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
sec_qos, des_access, pol);
|
||||
}
|
||||
|
||||
/** Open a LSA policy handle
|
||||
*
|
||||
* @param cli Handle on an initialised SMB connection
|
||||
*/
|
||||
|
||||
NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
|
||||
NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx, BOOL sec_qos,
|
||||
uint32 des_access, POLICY_HND *pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_OPEN_POL2 q;
|
||||
@@ -126,17 +138,17 @@ NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
if (sec_qos) {
|
||||
init_lsa_sec_qos(&qos, 2, 1, 0);
|
||||
init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
|
||||
init_q_open_pol2(&q, cli->cli->srv_name_slash, 0, des_access,
|
||||
&qos);
|
||||
} else {
|
||||
init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
|
||||
init_q_open_pol2(&q, cli->cli->srv_name_slash, 0, des_access,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -164,16 +176,26 @@ NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
|
||||
{
|
||||
return rpccli_lsa_open_policy2(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
sec_qos, des_access, pol);
|
||||
}
|
||||
|
||||
|
||||
/** Close a LSA policy handle */
|
||||
|
||||
NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol)
|
||||
NTSTATUS rpccli_lsa_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_CLOSE q;
|
||||
LSA_R_CLOSE r;
|
||||
NTSTATUS result;
|
||||
|
||||
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
|
||||
@@ -187,7 +209,7 @@ NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_lsa_q_close(&q, pol);
|
||||
|
||||
if (!lsa_io_q_close("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_CLOSE, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_CLOSE, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -215,11 +237,19 @@ NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol)
|
||||
{
|
||||
return rpccli_lsa_close(&cli->pipes[PI_LSARPC], mem_ctx, pol);
|
||||
}
|
||||
|
||||
/** Lookup a list of sids */
|
||||
|
||||
NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_sids, const DOM_SID *sids,
|
||||
char ***domains, char ***names, uint32 **types)
|
||||
NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_sids,
|
||||
const DOM_SID *sids,
|
||||
char ***domains, char ***names, uint32 **types)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_LOOKUP_SIDS q;
|
||||
@@ -242,7 +272,7 @@ NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
|
||||
|
||||
if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -332,12 +362,23 @@ NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_sids,
|
||||
const DOM_SID *sids,
|
||||
char ***domains, char ***names, uint32 **types)
|
||||
{
|
||||
return rpccli_lsa_lookup_sids(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
pol, num_sids, sids,
|
||||
domains, names, types);
|
||||
}
|
||||
|
||||
/** Lookup a list of names */
|
||||
|
||||
NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_names,
|
||||
const char **names, DOM_SID **sids,
|
||||
uint32 **types)
|
||||
NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_names,
|
||||
const char **names, DOM_SID **sids,
|
||||
uint32 **types)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_LOOKUP_NAMES q;
|
||||
@@ -359,7 +400,7 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
|
||||
|
||||
if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -433,19 +474,31 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, int num_names,
|
||||
const char **names, DOM_SID **sids,
|
||||
uint32 **types)
|
||||
{
|
||||
return rpccli_lsa_lookup_names(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
pol, num_names, names, sids, types);
|
||||
}
|
||||
|
||||
/** Query info policy
|
||||
*
|
||||
* @param domain_sid - returned remote server's domain sid */
|
||||
|
||||
NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, DOM_SID **domain_sid)
|
||||
NTSTATUS rpccli_lsa_query_info_policy(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, DOM_SID **domain_sid)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_QUERY_INFO q;
|
||||
LSA_R_QUERY_INFO r;
|
||||
NTSTATUS result;
|
||||
|
||||
SMB_ASSERT(cli->pipe_idx == PI_LSARPC);
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
|
||||
@@ -459,7 +512,7 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_q_query(&q, pol, info_class);
|
||||
|
||||
if (!lsa_io_q_query("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -523,6 +576,15 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, DOM_SID **domain_sid)
|
||||
{
|
||||
return rpccli_lsa_query_info_policy(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
pol, info_class, domain_name,
|
||||
domain_sid);
|
||||
}
|
||||
|
||||
/** Query info policy2
|
||||
*
|
||||
* @param domain_name - returned remote server's domain name
|
||||
@@ -531,11 +593,13 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
* @param domain_guid - returned remote server's domain guid
|
||||
* @param domain_sid - returned remote server's domain sid */
|
||||
|
||||
NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, char **dns_name,
|
||||
char **forest_name, struct uuid **domain_guid,
|
||||
DOM_SID **domain_sid)
|
||||
NTSTATUS rpccli_lsa_query_info_policy2(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, char **dns_name,
|
||||
char **forest_name,
|
||||
struct uuid **domain_guid,
|
||||
DOM_SID **domain_sid)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_QUERY_INFO2 q;
|
||||
@@ -558,7 +622,7 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_q_query2(&q, pol, info_class);
|
||||
|
||||
if (!lsa_io_q_query_info2("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_LSARPC, LSA_QUERYINFO2, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, LSA_QUERYINFO2, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -616,6 +680,19 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint16 info_class,
|
||||
char **domain_name, char **dns_name,
|
||||
char **forest_name,
|
||||
struct uuid **domain_guid,
|
||||
DOM_SID **domain_sid)
|
||||
{
|
||||
return rpccli_lsa_query_info_policy2(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
pol, info_class, domain_name,
|
||||
dns_name, forest_name,
|
||||
domain_guid, domain_sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate list of trusted domains
|
||||
*
|
||||
@@ -631,10 +708,11 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
* @return nt status code of response
|
||||
**/
|
||||
|
||||
NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *enum_ctx,
|
||||
uint32 *num_domains,
|
||||
char ***domain_names, DOM_SID **domain_sids)
|
||||
NTSTATUS rpccli_lsa_enum_trust_dom(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *enum_ctx,
|
||||
uint32 *num_domains,
|
||||
char ***domain_names, DOM_SID **domain_sids)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
LSA_Q_ENUM_TRUST_DOM in;
|
||||
@@ -650,7 +728,7 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
init_q_enum_trust_dom(&in, pol, *enum_ctx, 0x10000);
|
||||
|
||||
CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUMTRUSTDOM,
|
||||
CLI_DO_RPC_EX( cli, mem_ctx, PI_LSARPC, LSA_ENUMTRUSTDOM,
|
||||
in, out,
|
||||
qbuf, rbuf,
|
||||
lsa_io_q_enum_trust_dom,
|
||||
@@ -701,6 +779,15 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return out.status;
|
||||
}
|
||||
|
||||
NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *enum_ctx,
|
||||
uint32 *num_domains,
|
||||
char ***domain_names, DOM_SID **domain_sids)
|
||||
{
|
||||
return rpccli_lsa_enum_trust_dom(&cli->pipes[PI_LSARPC], mem_ctx,
|
||||
pol, enum_ctx, num_domains,
|
||||
domain_names, domain_sids);
|
||||
}
|
||||
|
||||
/** Enumerate privileges*/
|
||||
|
||||
|
||||
@@ -75,6 +75,55 @@ NTSTATUS cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS rpccli_net_req_chal(struct rpc_pipe_client *cli,
|
||||
const char *server_name,
|
||||
const char *computer_name,
|
||||
DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
NET_Q_REQ_CHAL q;
|
||||
NET_R_REQ_CHAL r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->cli->mem_ctx, MARSHALL);
|
||||
prs_init(&rbuf, 0, cli->cli->mem_ctx, UNMARSHALL);
|
||||
|
||||
/* create and send a MSRPC command with api NET_REQCHAL */
|
||||
|
||||
DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s\n",
|
||||
computer_name, server_name));
|
||||
|
||||
/* store the parameters */
|
||||
init_q_req_chal(&q, server_name, computer_name, clnt_chal);
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!net_io_q_req_chal("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req_int(cli, NET_REQCHAL, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Unmarhall response */
|
||||
|
||||
if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = r.status;
|
||||
|
||||
/* Return result */
|
||||
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
|
||||
}
|
||||
|
||||
done:
|
||||
prs_mem_free(&qbuf);
|
||||
prs_mem_free(&rbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
LSA Authenticate 2
|
||||
|
||||
@@ -158,6 +207,61 @@ password ?).\n", cli->desthost ));
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
|
||||
const char *server_name,
|
||||
const char *account_name,
|
||||
uint16 sec_chan_type,
|
||||
const char *computer_name,
|
||||
const DOM_CHAL *credentials,
|
||||
uint32 *neg_flags,
|
||||
DOM_CHAL *srv_chal)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
NET_Q_AUTH_2 q;
|
||||
NET_R_AUTH_2 r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
|
||||
prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
|
||||
|
||||
/* create and send a MSRPC command with api NET_AUTH2 */
|
||||
|
||||
DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s neg: %x\n",
|
||||
server_name, account_name, sec_chan_type, computer_name,
|
||||
*neg_flags));
|
||||
|
||||
/* store the parameters */
|
||||
|
||||
init_q_auth_2(&q, server_name, account_name, sec_chan_type,
|
||||
computer_name, credentials, *neg_flags);
|
||||
|
||||
/* turn parameters into data stream */
|
||||
|
||||
if (!net_io_q_auth_2("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req_int(cli, NET_AUTH2, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Unmarshall response */
|
||||
|
||||
if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = r.status;
|
||||
|
||||
if (NT_STATUS_IS_OK(result)) {
|
||||
*srv_chal = r.srv_chal;
|
||||
*neg_flags = r.srv_flgs.neg_flags;
|
||||
}
|
||||
|
||||
done:
|
||||
prs_mem_free(&qbuf);
|
||||
prs_mem_free(&rbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
LSA Authenticate 3
|
||||
|
||||
@@ -340,8 +444,9 @@ NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* GetDCName */
|
||||
|
||||
NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *domainname, fstring dcname)
|
||||
NTSTATUS rpccli_netlogon_getdcname(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx, const char *mydcname,
|
||||
const char *domainname, fstring newdcname)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
NET_Q_GETDCNAME q;
|
||||
@@ -358,12 +463,12 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Initialise input parameters */
|
||||
|
||||
init_net_q_getdcname(&q, cli->srv_name_slash, domainname);
|
||||
init_net_q_getdcname(&q, mydcname, domainname);
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!net_io_q_getdcname("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_NETLOGON, NET_GETDCNAME, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, NET_GETDCNAME, &qbuf, &rbuf)) {
|
||||
result = NT_STATUS_UNSUCCESSFUL;
|
||||
goto done;
|
||||
}
|
||||
@@ -378,7 +483,7 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
result = r.status;
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
rpcstr_pull_unistr2_fstring(dcname, &r.uni_dcname);
|
||||
rpcstr_pull_unistr2_fstring(newdcname, &r.uni_dcname);
|
||||
|
||||
done:
|
||||
prs_mem_free(&qbuf);
|
||||
@@ -387,6 +492,14 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *domainname, fstring dcname)
|
||||
{
|
||||
return rpccli_netlogon_getdcname(&cli->pipes[PI_NETLOGON], mem_ctx,
|
||||
cli->srv_name_slash, domainname,
|
||||
dcname);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Generate the next creds to use.
|
||||
****************************************************************************/
|
||||
@@ -636,19 +749,25 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
* @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
|
||||
**/
|
||||
|
||||
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
DOM_CRED *ret_creds,
|
||||
const char *username, const char *domain, const char *workstation,
|
||||
const uint8 chal[8],
|
||||
DATA_BLOB lm_response, DATA_BLOB nt_response,
|
||||
NET_USER_INFO_3 *info3)
|
||||
|
||||
NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *server_name_slash,
|
||||
DOM_CRED *clnt_creds,
|
||||
DOM_CRED *ret_creds,
|
||||
const char *username,
|
||||
const char *domain,
|
||||
const char *workstation,
|
||||
const uint8 chal[8],
|
||||
DATA_BLOB lm_response,
|
||||
DATA_BLOB nt_response,
|
||||
NET_USER_INFO_3 *info3,
|
||||
const uint8 *session_key)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
NET_Q_SAM_LOGON q;
|
||||
NET_R_SAM_LOGON r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
DOM_CRED clnt_creds, dummy_rtn_creds;
|
||||
DOM_CRED dummy_rtn_creds;
|
||||
NET_ID_INFO_CTR ctr;
|
||||
int validation_level = 3;
|
||||
char *workstation_name_slash;
|
||||
@@ -661,7 +780,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
|
||||
ZERO_STRUCT(dummy_rtn_creds);
|
||||
|
||||
workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
|
||||
|
||||
if (!workstation_name_slash) {
|
||||
DEBUG(0, ("talloc_asprintf failed!\n"));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
@@ -674,8 +792,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
|
||||
|
||||
/* Initialise input parameters */
|
||||
|
||||
gen_next_creds(cli, &clnt_creds);
|
||||
|
||||
q.validation_level = validation_level;
|
||||
|
||||
if (ret_creds == NULL)
|
||||
@@ -689,14 +805,14 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
|
||||
username, workstation_name_slash, (const uchar*)chal,
|
||||
lm_response.data, lm_response.length, nt_response.data, nt_response.length);
|
||||
|
||||
init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(),
|
||||
&clnt_creds, ret_creds, NET_LOGON_TYPE,
|
||||
init_sam_info(&q.sam_id, server_name_slash, global_myname(),
|
||||
clnt_creds, ret_creds, NET_LOGON_TYPE,
|
||||
&ctr);
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_NETLOGON, NET_SAMLOGON, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -709,7 +825,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
|
||||
}
|
||||
|
||||
ZERO_STRUCT(netlogon_sess_key);
|
||||
memcpy(netlogon_sess_key, cli->sess_key, 8);
|
||||
memcpy(netlogon_sess_key, session_key, 8);
|
||||
|
||||
if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
|
||||
SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16);
|
||||
@@ -740,6 +856,30 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
DOM_CRED *ret_creds,
|
||||
const char *username,
|
||||
const char *domain,
|
||||
const char *workstation,
|
||||
const uint8 chal[8],
|
||||
DATA_BLOB lm_response,
|
||||
DATA_BLOB nt_response,
|
||||
NET_USER_INFO_3 *info3)
|
||||
{
|
||||
DOM_CRED clnt_creds;
|
||||
|
||||
gen_next_creds(cli, &clnt_creds);
|
||||
|
||||
return rpccli_netlogon_sam_network_logon(&cli->pipes[PI_NETLOGON],
|
||||
mem_ctx, cli->srv_name_slash,
|
||||
&clnt_creds,
|
||||
ret_creds, username,
|
||||
domain, workstation, chal,
|
||||
lm_response, nt_response,
|
||||
info3, cli->sess_key);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
LSA Server Password Set.
|
||||
****************************************************************************/
|
||||
|
||||
@@ -62,7 +62,8 @@ static uint32 get_rpc_call_id(void)
|
||||
Use SMBreadX to get rest of one fragment's worth of rpc data.
|
||||
********************************************************************/
|
||||
|
||||
static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
|
||||
static BOOL rpc_read(struct rpc_pipe_client *cli, prs_struct *rdata,
|
||||
uint32 data_to_read, uint32 *rdata_offset)
|
||||
{
|
||||
size_t size = (size_t)cli->max_recv_frag;
|
||||
int stream_offset = 0;
|
||||
@@ -95,13 +96,14 @@ static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uin
|
||||
if (size > (size_t)data_to_read)
|
||||
size = (size_t)data_to_read;
|
||||
|
||||
num_read = (int)cli_read(cli, cli->nt_pipe_fnum[pipe_idx], pdata, (off_t)stream_offset, size);
|
||||
num_read = (int)cli_read(cli->cli, cli->fnum, pdata,
|
||||
(off_t)stream_offset, size);
|
||||
|
||||
DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
|
||||
num_read, stream_offset, data_to_read));
|
||||
|
||||
if (cli_is_dos_error(cli)) {
|
||||
cli_dos_error(cli, &eclass, &ecode);
|
||||
if (cli_is_dos_error(cli->cli)) {
|
||||
cli_dos_error(cli->cli, &eclass, &ecode);
|
||||
if (eclass != ERRDOS && ecode != ERRmoredata) {
|
||||
DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
|
||||
eclass, (unsigned int)ecode));
|
||||
@@ -168,7 +170,7 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
|
||||
Never on bind requests/responses.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
|
||||
static BOOL rpc_auth_pipe(struct rpc_pipe_client *cli, prs_struct *rdata,
|
||||
uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
|
||||
int *pauth_padding_len)
|
||||
{
|
||||
@@ -219,7 +221,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
|
||||
DEBUG(10,("rpc_auth_pipe: packet:\n"));
|
||||
dump_data(100, dp, auth_len);
|
||||
|
||||
prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
|
||||
prs_init(&auth_verf, 0, cli->cli->mem_ctx, UNMARSHALL);
|
||||
|
||||
/* The endinness must be preserved. JRA. */
|
||||
prs_set_endian_data( &auth_verf, rdata->bigendian_data);
|
||||
@@ -394,7 +396,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data, prs_struct *rdata,
|
||||
static BOOL rpc_api_pipe(struct rpc_pipe_client *cli, prs_struct *data, prs_struct *rdata,
|
||||
uint8 expected_pkt_type)
|
||||
{
|
||||
uint32 len;
|
||||
@@ -416,23 +418,24 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
/* Create setup parameters - must be in native byte order. */
|
||||
|
||||
setup[0] = TRANSACT_DCERPCCMD;
|
||||
setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* Pipe file handle. */
|
||||
setup[1] = cli->fnum; /* Pipe file handle. */
|
||||
|
||||
DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum[pipe_idx]));
|
||||
DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->fnum));
|
||||
|
||||
/* Send the RPC request and receive a response. For short RPC
|
||||
calls (about 1024 bytes or so) the RPC request and response
|
||||
appears in a SMBtrans request and response. Larger RPC
|
||||
responses are received further on. */
|
||||
|
||||
if (!cli_api_pipe(cli, "\\PIPE\\",
|
||||
if (!cli_api_pipe(cli->cli, "\\PIPE\\",
|
||||
setup, 2, 0, /* Setup, length, max */
|
||||
NULL, 0, 0, /* Params, length, max */
|
||||
pdata, data_len, max_data, /* data, length, max */
|
||||
&rparam, &rparam_len, /* return params, len */
|
||||
&prdata, &rdata_len)) /* return data, len */
|
||||
{
|
||||
DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
|
||||
DEBUG(0, ("cli_pipe: return critical error. Error was %s\n",
|
||||
cli_errstr(cli->cli)));
|
||||
return False;
|
||||
}
|
||||
|
||||
@@ -442,7 +445,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
|
||||
if (prdata == NULL) {
|
||||
DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
|
||||
(int)cli->nt_pipe_fnum[pipe_idx]));
|
||||
(int)cli->fnum));
|
||||
return False;
|
||||
}
|
||||
|
||||
@@ -470,7 +473,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
}
|
||||
|
||||
if (rhdr.pkt_type == RPC_BINDNACK) {
|
||||
DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum[pipe_idx]));
|
||||
DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->fnum));
|
||||
prs_mem_free(rdata);
|
||||
return False;
|
||||
}
|
||||
@@ -485,7 +488,9 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
}
|
||||
|
||||
if (rhdr.pkt_type != expected_pkt_type) {
|
||||
DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum[pipe_idx], rhdr.pkt_type, expected_pkt_type));
|
||||
DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet "
|
||||
"type - %d, not %d\n", (int)cli->fnum,
|
||||
rhdr.pkt_type, expected_pkt_type));
|
||||
prs_mem_free(rdata);
|
||||
return False;
|
||||
}
|
||||
@@ -502,7 +507,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
|
||||
/* Read the remaining part of the first response fragment */
|
||||
|
||||
if (!rpc_read(cli, pipe_idx, rdata, len, ¤t_offset)) {
|
||||
if (!rpc_read(cli, rdata, len, ¤t_offset)) {
|
||||
prs_mem_free(rdata);
|
||||
return False;
|
||||
}
|
||||
@@ -554,12 +559,13 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
* First read the header of the next PDU.
|
||||
*/
|
||||
|
||||
prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
|
||||
prs_init(&hps, 0, cli->cli->mem_ctx, UNMARSHALL);
|
||||
prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
|
||||
|
||||
num_read = cli_read(cli, cli->nt_pipe_fnum[pipe_idx], hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
|
||||
if (cli_is_dos_error(cli)) {
|
||||
cli_dos_error(cli, &eclass, &ecode);
|
||||
num_read = cli_read(cli->cli, cli->fnum, hdr_data, 0,
|
||||
RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
|
||||
if (cli_is_dos_error(cli->cli)) {
|
||||
cli_dos_error(cli->cli, &eclass, &ecode);
|
||||
if (eclass != ERRDOS && ecode != ERRmoredata) {
|
||||
DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
|
||||
return False;
|
||||
@@ -602,7 +608,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
* Now read the rest of the PDU.
|
||||
*/
|
||||
|
||||
if (!rpc_read(cli, pipe_idx, rdata, len, ¤t_offset)) {
|
||||
if (!rpc_read(cli, rdata, len, ¤t_offset)) {
|
||||
prs_mem_free(rdata);
|
||||
return False;
|
||||
}
|
||||
@@ -644,7 +650,8 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
|
||||
|
||||
********************************************************************/
|
||||
|
||||
static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
|
||||
static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
|
||||
prs_struct *rpc_out,
|
||||
uint32 rpc_call_id,
|
||||
RPC_IFACE *abstract, RPC_IFACE *transfer,
|
||||
const char *my_name, const char *domain)
|
||||
@@ -783,7 +790,7 @@ static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
|
||||
the authentication handshake.
|
||||
********************************************************************/
|
||||
|
||||
static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
|
||||
static NTSTATUS create_rpc_bind_resp(struct rpc_pipe_client *cli,
|
||||
uint32 rpc_call_id,
|
||||
prs_struct *rpc_out)
|
||||
{
|
||||
@@ -916,8 +923,8 @@ static BOOL create_auth_hdr(prs_struct *outgoing_packet,
|
||||
* @param rdata Unparsed NDR response data.
|
||||
**/
|
||||
|
||||
BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
prs_struct *data, prs_struct *rdata)
|
||||
BOOL rpc_api_pipe_req_int(struct rpc_pipe_client *cli, uint8 op_num,
|
||||
prs_struct *data, prs_struct *rdata)
|
||||
{
|
||||
uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
|
||||
NTSTATUS nt_status;
|
||||
@@ -959,7 +966,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
send_size = MIN(data_left, max_data);
|
||||
|
||||
if (!prs_init(&sec_blob, send_size, /* will need at least this much */
|
||||
cli->mem_ctx, MARSHALL)) {
|
||||
cli->cli->mem_ctx, MARSHALL)) {
|
||||
DEBUG(0,("Could not malloc %u bytes",
|
||||
send_size+auth_padding));
|
||||
return False;
|
||||
@@ -1066,7 +1073,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
* Malloc parse struct to hold it (and enough for alignments).
|
||||
*/
|
||||
if(!prs_init(&outgoing_packet, data_len + 8,
|
||||
cli->mem_ctx, MARSHALL)) {
|
||||
cli->cli->mem_ctx, MARSHALL)) {
|
||||
DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
|
||||
return False;
|
||||
}
|
||||
@@ -1095,10 +1102,10 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
prs_offset(&outgoing_packet)));
|
||||
|
||||
if (flags & RPC_FLG_LAST)
|
||||
ret = rpc_api_pipe(cli, pipe_idx, &outgoing_packet,
|
||||
ret = rpc_api_pipe(cli, &outgoing_packet,
|
||||
rdata, RPC_RESPONSE);
|
||||
else {
|
||||
cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x0008,
|
||||
cli_write(cli->cli, cli->fnum, 0x0008,
|
||||
prs_data_p(&outgoing_packet),
|
||||
data_sent, data_len);
|
||||
}
|
||||
@@ -1108,17 +1115,26 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
}
|
||||
/* Also capture received data */
|
||||
slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s",
|
||||
cli_pipe_get_name(cli));
|
||||
cli_pipe_get_name(cli->cli));
|
||||
prs_dump(dump_name, op_num, rdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
|
||||
prs_struct *data, prs_struct *rdata)
|
||||
{
|
||||
return rpc_api_pipe_req_int(&cli->pipes[pipe_idx], op_num,
|
||||
data, rdata);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Set the handle state.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const char *pipe_name, uint16 device_state)
|
||||
static BOOL rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
|
||||
const char *pipe_name, uint16 device_state)
|
||||
{
|
||||
BOOL state_set = False;
|
||||
char param[2];
|
||||
@@ -1131,17 +1147,17 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const ch
|
||||
return False;
|
||||
|
||||
DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
|
||||
cli->nt_pipe_fnum[pipe_idx], pipe_name, device_state));
|
||||
cli->fnum, pipe_name, device_state));
|
||||
|
||||
/* create parameters: device state */
|
||||
SSVAL(param, 0, device_state);
|
||||
|
||||
/* create setup parameters. */
|
||||
setup[0] = 0x0001;
|
||||
setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* pipe file handle. got this from an SMBOpenX. */
|
||||
setup[1] = cli->fnum; /* pipe file handle. got this from an SMBOpenX. */
|
||||
|
||||
/* send the data on \PIPE\ */
|
||||
if (cli_api_pipe(cli, "\\PIPE\\",
|
||||
if (cli_api_pipe(cli->cli, "\\PIPE\\",
|
||||
setup, 2, 0, /* setup, length, max */
|
||||
param, 2, 0, /* param, length, max */
|
||||
NULL, 0, 1024, /* data, length, max */
|
||||
@@ -1281,20 +1297,21 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFAC
|
||||
Create and send the third packet in an RPC auth.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 rpc_call_id)
|
||||
static BOOL rpc_send_auth_reply(struct rpc_pipe_client *cli,
|
||||
prs_struct *rdata, uint32 rpc_call_id)
|
||||
{
|
||||
prs_struct rpc_out;
|
||||
ssize_t ret;
|
||||
|
||||
prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */
|
||||
cli->mem_ctx, MARSHALL);
|
||||
cli->cli->mem_ctx, MARSHALL);
|
||||
|
||||
if (!NT_STATUS_IS_OK(create_rpc_bind_resp(cli, rpc_call_id,
|
||||
&rpc_out))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if ((ret = cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x8, prs_data_p(&rpc_out),
|
||||
if ((ret = cli_write(cli->cli, cli->fnum, 0x8, prs_data_p(&rpc_out),
|
||||
0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
|
||||
DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
|
||||
prs_mem_free(&rpc_out);
|
||||
@@ -1309,7 +1326,7 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct
|
||||
Do an rpc bind.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name)
|
||||
static BOOL rpc_pipe_bind(struct rpc_pipe_client *cli)
|
||||
{
|
||||
RPC_IFACE abstract;
|
||||
RPC_IFACE transfer;
|
||||
@@ -1318,15 +1335,16 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
|
||||
uint32 rpc_call_id;
|
||||
char buffer[MAX_PDU_FRAG_LEN];
|
||||
|
||||
if ( (pipe_idx < 0) || (pipe_idx >= PI_MAX_PIPES) )
|
||||
if ( (cli->pipe_idx < 0) || (cli->pipe_idx >= PI_MAX_PIPES) )
|
||||
return False;
|
||||
|
||||
DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum[pipe_idx], pipe_names[pipe_idx].client_pipe));
|
||||
DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->fnum,
|
||||
pipe_names[cli->pipe_idx].client_pipe));
|
||||
|
||||
if (!valid_pipe_name(pipe_idx, &abstract, &transfer))
|
||||
if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer))
|
||||
return False;
|
||||
|
||||
prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
|
||||
prs_init(&rpc_out, 0, cli->cli->mem_ctx, MARSHALL);
|
||||
|
||||
/*
|
||||
* Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
|
||||
@@ -1391,10 +1409,10 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
|
||||
global_myname(), cli->domain);
|
||||
|
||||
/* Initialize the incoming data struct. */
|
||||
prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
|
||||
prs_init(&rdata, 0, cli->cli->mem_ctx, UNMARSHALL);
|
||||
|
||||
/* send data on \PIPE\. receive a response */
|
||||
if (rpc_api_pipe(cli, pipe_idx, &rpc_out, &rdata, RPC_BINDACK)) {
|
||||
if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) {
|
||||
RPC_HDR_BA hdr_ba;
|
||||
|
||||
DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
|
||||
@@ -1405,7 +1423,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
|
||||
return False;
|
||||
}
|
||||
|
||||
if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) {
|
||||
if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) {
|
||||
DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
|
||||
prs_mem_free(&rdata);
|
||||
return False;
|
||||
@@ -1421,7 +1439,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
|
||||
*/
|
||||
|
||||
if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP)
|
||||
&& !rpc_send_auth_reply(cli, pipe_idx, &rdata, rpc_call_id)) {
|
||||
&& !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
|
||||
DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
|
||||
prs_mem_free(&rdata);
|
||||
return False;
|
||||
@@ -1440,11 +1458,9 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
|
||||
BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
|
||||
{
|
||||
int fnum;
|
||||
struct rpc_pipe_client *cli_pipe;
|
||||
|
||||
/* At the moment we can't have more than one pipe open over
|
||||
a cli connection. )-: */
|
||||
|
||||
SMB_ASSERT(cli->nt_pipe_fnum[pipe_idx] == 0);
|
||||
SMB_ASSERT(cli->pipes[pipe_idx].fnum == 0);
|
||||
|
||||
/* The pipe index must fall within our array */
|
||||
|
||||
@@ -1457,7 +1473,7 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
|
||||
return False;
|
||||
}
|
||||
|
||||
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
|
||||
cli->pipes[pipe_idx].fnum = (uint16)fnum;
|
||||
} else {
|
||||
if ((fnum = cli_open(cli, pipe_names[pipe_idx].client_pipe, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
|
||||
DEBUG(1,("cli_nt_session_open: cli_open failed on pipe %s to machine %s. Error was %s\n",
|
||||
@@ -1465,25 +1481,32 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
|
||||
return False;
|
||||
}
|
||||
|
||||
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
|
||||
cli->pipes[pipe_idx].fnum = (uint16)fnum;
|
||||
|
||||
/**************** Set Named Pipe State ***************/
|
||||
if (!rpc_pipe_set_hnd_state(cli, pipe_idx, pipe_names[pipe_idx].client_pipe, 0x4300)) {
|
||||
if (!rpc_pipe_set_hnd_state(&cli->pipes[pipe_idx], pipe_names[pipe_idx].client_pipe, 0x4300)) {
|
||||
DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
|
||||
cli_errstr(cli)));
|
||||
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
|
||||
cli->nt_pipe_fnum[pipe_idx] = 0;
|
||||
cli_close(cli, cli->pipes[pipe_idx].fnum);
|
||||
cli->pipes[pipe_idx].fnum = 0;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
cli_pipe = &cli->pipes[pipe_idx];
|
||||
cli_pipe->pipe_idx = pipe_idx;
|
||||
cli_pipe->cli = cli;
|
||||
cli_pipe->pipe_auth_flags = cli->pipe_auth_flags;
|
||||
memcpy(&cli_pipe->auth_info.sess_key,
|
||||
cli->sess_key, sizeof(cli->sess_key));
|
||||
|
||||
/******************* bind request on pipe *****************/
|
||||
|
||||
if (!rpc_pipe_bind(cli, pipe_idx, global_myname())) {
|
||||
if (!rpc_pipe_bind(&cli->pipes[pipe_idx])) {
|
||||
DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
|
||||
get_pipe_name_from_index(pipe_idx)));
|
||||
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
|
||||
cli->nt_pipe_fnum[pipe_idx] = 0;
|
||||
cli_close(cli, cli->pipes[pipe_idx].fnum);
|
||||
cli->pipes[pipe_idx].fnum = 0;
|
||||
return False;
|
||||
}
|
||||
|
||||
@@ -1523,7 +1546,6 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
|
||||
{
|
||||
NTSTATUS result;
|
||||
uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
|
||||
int fnum;
|
||||
|
||||
cli_nt_netlogon_netsec_session_close(cli);
|
||||
|
||||
@@ -1554,60 +1576,20 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
|
||||
|
||||
}
|
||||
|
||||
cli->netlogon_pipe = cli->pipes[PI_NETLOGON];
|
||||
ZERO_STRUCT(cli->pipes[PI_NETLOGON]);
|
||||
|
||||
/* Server offered schannel, so try it. */
|
||||
|
||||
memcpy(cli->auth_info.sess_key, cli->sess_key,
|
||||
sizeof(cli->auth_info.sess_key));
|
||||
|
||||
cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum[PI_NETLOGON];
|
||||
memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->sess_key,
|
||||
sizeof(cli->pipes[PI_NETLOGON].auth_info.sess_key));
|
||||
|
||||
cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
|
||||
cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
|
||||
cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
|
||||
|
||||
if (cli->capabilities & CAP_NT_SMBS) {
|
||||
|
||||
/* The secure channel connection must be opened on the same
|
||||
session (TCP connection) as the one the challenge was
|
||||
requested from. */
|
||||
if ((fnum = cli_nt_create(cli, PIPE_NETLOGON_PLAIN,
|
||||
DESIRED_ACCESS_PIPE)) == -1) {
|
||||
DEBUG(0,("cli_nt_create failed to %s machine %s. "
|
||||
"Error was %s\n",
|
||||
PIPE_NETLOGON, cli->desthost,
|
||||
cli_errstr(cli)));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
cli->nt_pipe_fnum[PI_NETLOGON] = (uint16)fnum;
|
||||
} else {
|
||||
if ((fnum = cli_open(cli, PIPE_NETLOGON,
|
||||
O_CREAT|O_RDWR, DENY_NONE)) == -1) {
|
||||
DEBUG(0,("cli_open failed on pipe %s to machine %s. "
|
||||
"Error was %s\n",
|
||||
PIPE_NETLOGON, cli->desthost,
|
||||
cli_errstr(cli)));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
cli->nt_pipe_fnum[PI_NETLOGON] = (uint16)fnum;
|
||||
|
||||
/**************** Set Named Pipe State ***************/
|
||||
if (!rpc_pipe_set_hnd_state(cli, PI_NETLOGON, PIPE_NETLOGON, 0x4300)) {
|
||||
DEBUG(0,("Pipe hnd state failed. Error was %s\n",
|
||||
cli_errstr(cli)));
|
||||
cli_close(cli, cli->nt_pipe_fnum[PI_NETLOGON]);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname())) {
|
||||
DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
|
||||
cli_close(cli, cli->nt_pipe_fnum[PI_NETLOGON]);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
return cli_nt_session_open(cli, PI_NETLOGON) ?
|
||||
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1640,18 +1622,19 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
ZERO_STRUCT(cli->auth_info.sess_key);
|
||||
ZERO_STRUCT(cli->pipes[cli->pipe_idx].auth_info.sess_key);
|
||||
ZERO_STRUCT(cli->sess_key);
|
||||
cli->pipe_auth_flags = 0;
|
||||
cli_nt_session_close(cli);
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(cli->auth_info.sess_key, cli->sess_key,
|
||||
sizeof(cli->auth_info.sess_key));
|
||||
memcpy(cli->pipes[PI_NETLOGON].auth_info.sess_key, cli->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 */
|
||||
cli->pipe_auth_flags = auth_flags;
|
||||
@@ -1664,4 +1647,124 @@ const char *cli_pipe_get_name(struct cli_state *cli)
|
||||
return cli->pipe_name;
|
||||
}
|
||||
|
||||
static struct rpc_pipe_client *cli_rpc_open(struct cli_state *cli,
|
||||
int pipe_idx)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct rpc_pipe_client *result;
|
||||
int fnum;
|
||||
|
||||
/* The pipe index must fall within our array */
|
||||
SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
|
||||
|
||||
mem_ctx = talloc_init("struct rpc_pipe_client");
|
||||
if (mem_ctx == NULL) return NULL;
|
||||
|
||||
result = TALLOC_P(mem_ctx, struct rpc_pipe_client);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->mem_ctx = mem_ctx;
|
||||
|
||||
fnum = cli_nt_create(cli, &pipe_names[pipe_idx].client_pipe[5],
|
||||
DESIRED_ACCESS_PIPE);
|
||||
|
||||
if (fnum == -1) {
|
||||
DEBUG(0,("cli_rpc_open failed on pipe %s "
|
||||
"to machine %s. Error was %s\n",
|
||||
&pipe_names[pipe_idx].client_pipe[5], cli->desthost,
|
||||
cli_errstr(cli)));
|
||||
talloc_destroy(result->mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result->fnum = fnum;
|
||||
result->cli = cli;
|
||||
result->pipe_idx = pipe_idx;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rpc_pipe_client *cli_rpc_open_noauth(struct cli_state *cli,
|
||||
int pipe_idx)
|
||||
{
|
||||
struct rpc_pipe_client *result;
|
||||
|
||||
result = cli_rpc_open(cli, pipe_idx);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->max_xmit_frag = 0;
|
||||
result->pipe_auth_flags = 0;
|
||||
|
||||
if (!rpc_pipe_bind(result)) {
|
||||
DEBUG(0, ("rpc_pipe_bind failed\n"));
|
||||
talloc_destroy(result->mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rpc_pipe_client *cli_rpc_open_ntlmssp(struct cli_state *cli,
|
||||
int pipe_idx,
|
||||
const char *domain,
|
||||
const char *username,
|
||||
const char *password)
|
||||
{
|
||||
struct rpc_pipe_client *result;
|
||||
|
||||
result = cli_rpc_open(cli, pipe_idx);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->max_xmit_frag = 0;
|
||||
result->pipe_auth_flags =
|
||||
AUTH_PIPE_NTLMSSP|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL;
|
||||
result->domain = domain;
|
||||
result->user_name = username;
|
||||
pwd_set_cleartext(&result->pwd, password);
|
||||
|
||||
if (!rpc_pipe_bind(result)) {
|
||||
DEBUG(0, ("cli_rpc_pipe_bind failed\n"));
|
||||
talloc_destroy(result->mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rpc_pipe_client *cli_rpc_open_schannel(struct cli_state *cli,
|
||||
int pipe_idx,
|
||||
const uchar session_key[16],
|
||||
const char *domain)
|
||||
{
|
||||
struct rpc_pipe_client *result;
|
||||
|
||||
result = cli_rpc_open(cli, pipe_idx);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->max_xmit_frag = 0;
|
||||
result->pipe_auth_flags =
|
||||
AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN | AUTH_PIPE_SEAL;
|
||||
result->domain = domain;
|
||||
memcpy(result->auth_info.sess_key, session_key, 16);
|
||||
|
||||
if (!rpc_pipe_bind(result)) {
|
||||
DEBUG(0, ("cli_rpc_pipe_bind failed\n"));
|
||||
talloc_destroy(result->mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void cli_rpc_close(struct rpc_pipe_client *cli_pipe)
|
||||
{
|
||||
if (!cli_close(cli_pipe->cli, cli_pipe->fnum))
|
||||
DEBUG(0,("cli_rpc_open failed on pipe %s "
|
||||
"to machine %s. Error was %s\n",
|
||||
&pipe_names[cli_pipe->pipe_idx].client_pipe[5],
|
||||
cli_pipe->cli->desthost,
|
||||
cli_errstr(cli_pipe->cli)));
|
||||
|
||||
talloc_destroy(cli_pipe->mem_ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
|
||||
/* Connect to SAMR database */
|
||||
|
||||
NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
uint32 access_mask, POLICY_HND *connect_pol)
|
||||
NTSTATUS rpccli_samr_connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
|
||||
uint32 access_mask, POLICY_HND *connect_pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_CONNECT q;
|
||||
SAMR_R_CONNECT r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG(10,("cli_samr_connect to %s\n", cli->desthost));
|
||||
DEBUG(10,("cli_samr_connect to %s\n", cli->cli->desthost));
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
@@ -47,10 +47,10 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
init_samr_q_connect(&q, cli->desthost, access_mask);
|
||||
init_samr_q_connect(&q, cli->cli->desthost, access_mask);
|
||||
|
||||
if (!samr_io_q_connect("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_CONNECT, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_CONNECT, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -74,6 +74,12 @@ NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
uint32 access_mask, POLICY_HND *connect_pol)
|
||||
{
|
||||
return rpccli_samr_connect(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
access_mask, connect_pol);
|
||||
}
|
||||
/* Connect to SAMR database */
|
||||
|
||||
NTSTATUS cli_samr_connect4(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
@@ -125,8 +131,8 @@ NTSTATUS cli_samr_connect4(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Close SAMR handle */
|
||||
|
||||
NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol)
|
||||
NTSTATUS rpccli_samr_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_CLOSE_HND q;
|
||||
@@ -148,7 +154,7 @@ NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_close_hnd(&q, connect_pol);
|
||||
|
||||
if (!samr_io_q_close_hnd("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_CLOSE_HND, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_CLOSE_HND, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -172,11 +178,18 @@ NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol)
|
||||
{
|
||||
return rpccli_samr_close(&cli->pipes[PI_SAMR], mem_ctx, connect_pol);
|
||||
}
|
||||
|
||||
/* Open handle on a domain */
|
||||
|
||||
NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol, uint32 access_mask,
|
||||
const DOM_SID *domain_sid, POLICY_HND *domain_pol)
|
||||
NTSTATUS rpccli_samr_open_domain(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol, uint32 access_mask,
|
||||
const DOM_SID *domain_sid,
|
||||
POLICY_HND *domain_pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_OPEN_DOMAIN q;
|
||||
@@ -198,7 +211,7 @@ NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_open_domain(&q, connect_pol, access_mask, domain_sid);
|
||||
|
||||
if (!samr_io_q_open_domain("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_DOMAIN, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_OPEN_DOMAIN, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -224,9 +237,21 @@ NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Open handle on a user */
|
||||
|
||||
NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 user_rid, POLICY_HND *user_pol)
|
||||
NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol, uint32 access_mask,
|
||||
const DOM_SID *domain_sid,
|
||||
POLICY_HND *domain_pol)
|
||||
{
|
||||
return rpccli_samr_open_domain(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
connect_pol, access_mask, domain_sid,
|
||||
domain_pol);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS rpccli_samr_open_user(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 user_rid, POLICY_HND *user_pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_OPEN_USER q;
|
||||
@@ -248,7 +273,7 @@ NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_open_user(&q, domain_pol, access_mask, user_rid);
|
||||
|
||||
if (!samr_io_q_open_user("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_USER, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_OPEN_USER, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -272,11 +297,21 @@ NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 user_rid, POLICY_HND *user_pol)
|
||||
{
|
||||
return rpccli_samr_open_user(&cli->pipes[PI_SAMR], mem_ctx, domain_pol,
|
||||
access_mask, user_rid, user_pol);
|
||||
}
|
||||
|
||||
|
||||
/* Open handle on a group */
|
||||
|
||||
NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 group_rid, POLICY_HND *group_pol)
|
||||
NTSTATUS rpccli_samr_open_group(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 group_rid, POLICY_HND *group_pol)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_OPEN_GROUP q;
|
||||
@@ -298,7 +333,7 @@ NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_open_group(&q, domain_pol, access_mask, group_rid);
|
||||
|
||||
if (!samr_io_q_open_group("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_OPEN_GROUP, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_OPEN_GROUP, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -322,6 +357,15 @@ NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 access_mask,
|
||||
uint32 group_rid, POLICY_HND *group_pol)
|
||||
{
|
||||
return rpccli_samr_open_group(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
domain_pol, access_mask, group_rid,
|
||||
group_pol);
|
||||
}
|
||||
|
||||
/* Create domain group */
|
||||
|
||||
NTSTATUS cli_samr_create_dom_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
@@ -461,9 +505,10 @@ NTSTATUS cli_samr_del_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Query user info */
|
||||
|
||||
NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol, uint16 switch_value,
|
||||
SAM_USERINFO_CTR **ctr)
|
||||
NTSTATUS rpccli_samr_query_userinfo(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol, uint16 switch_value,
|
||||
SAM_USERINFO_CTR **ctr)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_USERINFO q;
|
||||
@@ -485,7 +530,7 @@ NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_query_userinfo(&q, user_pol, switch_value);
|
||||
|
||||
if (!samr_io_q_query_userinfo("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERINFO, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_USERINFO, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -505,6 +550,14 @@ NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol, uint16 switch_value,
|
||||
SAM_USERINFO_CTR **ctr)
|
||||
{
|
||||
return rpccli_samr_query_userinfo(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
user_pol, switch_value, ctr);
|
||||
}
|
||||
|
||||
/* Set group info */
|
||||
|
||||
NTSTATUS cli_samr_set_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
@@ -598,9 +651,11 @@ NTSTATUS cli_samr_query_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Query user groups */
|
||||
|
||||
NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol, uint32 *num_groups,
|
||||
DOM_GID **gid)
|
||||
NTSTATUS rpccli_samr_query_usergroups(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol,
|
||||
uint32 *num_groups,
|
||||
DOM_GID **gid)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_USERGROUPS q;
|
||||
@@ -622,7 +677,7 @@ NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_query_usergroups(&q, user_pol);
|
||||
|
||||
if (!samr_io_q_query_usergroups("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -644,6 +699,14 @@ NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *user_pol, uint32 *num_groups,
|
||||
DOM_GID **gid)
|
||||
{
|
||||
return rpccli_samr_query_usergroups(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
user_pol, num_groups, gid);
|
||||
}
|
||||
|
||||
/* Set alias info */
|
||||
|
||||
NTSTATUS cli_samr_set_aliasinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
@@ -690,9 +753,11 @@ NTSTATUS cli_samr_set_aliasinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Query user aliases */
|
||||
|
||||
NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *dom_pol, uint32 num_sids, DOM_SID2 *sid,
|
||||
uint32 *num_aliases, uint32 **als_rids)
|
||||
NTSTATUS rpccli_samr_query_useraliases(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *dom_pol, uint32 num_sids,
|
||||
DOM_SID2 *sid,
|
||||
uint32 *num_aliases, uint32 **als_rids)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_USERALIASES q;
|
||||
@@ -723,7 +788,7 @@ NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_query_useraliases(&q, dom_pol, num_sids, sid_ptrs, sid);
|
||||
|
||||
if (!samr_io_q_query_useraliases("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_USERALIASES, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_USERALIASES, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -745,11 +810,24 @@ NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_useraliases(struct cli_state *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *dom_pol, uint32 num_sids,
|
||||
DOM_SID2 *sid,
|
||||
uint32 *num_aliases, uint32 **als_rids)
|
||||
{
|
||||
return rpccli_samr_query_useraliases(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
dom_pol, num_sids, sid,
|
||||
num_aliases, als_rids);
|
||||
}
|
||||
|
||||
|
||||
/* Query user groups */
|
||||
|
||||
NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *group_pol, uint32 *num_mem,
|
||||
uint32 **rid, uint32 **attr)
|
||||
NTSTATUS rpccli_samr_query_groupmem(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *group_pol, uint32 *num_mem,
|
||||
uint32 **rid, uint32 **attr)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_GROUPMEM q;
|
||||
@@ -771,7 +849,7 @@ NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_query_groupmem(&q, group_pol);
|
||||
|
||||
if (!samr_io_q_query_groupmem("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -794,6 +872,15 @@ NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *group_pol, uint32 *num_mem,
|
||||
uint32 **rid, uint32 **attr)
|
||||
{
|
||||
return rpccli_samr_query_groupmem(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
group_pol, num_mem, rid, attr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enumerate domain users
|
||||
*
|
||||
@@ -892,10 +979,11 @@ done:
|
||||
|
||||
/* Enumerate domain groups */
|
||||
|
||||
NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_groups,
|
||||
uint32 *num_dom_groups)
|
||||
NTSTATUS rpccli_samr_enum_dom_groups(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_groups,
|
||||
uint32 *num_dom_groups)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_ENUM_DOM_GROUPS q;
|
||||
@@ -918,7 +1006,7 @@ NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_enum_dom_groups(&q, pol, *start_idx, size);
|
||||
|
||||
if (!samr_io_q_enum_dom_groups("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf))
|
||||
!rpc_api_pipe_req_int(cli, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
@@ -969,12 +1057,23 @@ NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_groups,
|
||||
uint32 *num_dom_groups)
|
||||
{
|
||||
return rpccli_samr_enum_dom_groups(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
pol, start_idx, size, dom_groups,
|
||||
num_dom_groups);
|
||||
}
|
||||
|
||||
/* Enumerate domain groups */
|
||||
|
||||
NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_aliases,
|
||||
uint32 *num_dom_aliases)
|
||||
NTSTATUS rpccli_samr_enum_als_groups(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_aliases,
|
||||
uint32 *num_dom_aliases)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_ENUM_DOM_ALIASES q;
|
||||
@@ -997,7 +1096,7 @@ NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_enum_dom_aliases(&q, pol, *start_idx, size);
|
||||
|
||||
if (!samr_io_q_enum_dom_aliases("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1051,6 +1150,16 @@ NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *pol, uint32 *start_idx,
|
||||
uint32 size, struct acct_info **dom_aliases,
|
||||
uint32 *num_dom_aliases)
|
||||
{
|
||||
return rpccli_samr_enum_als_groups(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
pol, start_idx, size, dom_aliases,
|
||||
num_dom_aliases);
|
||||
}
|
||||
|
||||
/* Query alias members */
|
||||
|
||||
NTSTATUS cli_samr_query_aliasmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
@@ -1326,7 +1435,7 @@ NTSTATUS cli_samr_query_alias_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
SAMR_R_QUERY_ALIASINFO r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG(10,("cli_samr_query_dom_info\n"));
|
||||
DEBUG(10,("cli_samr_query_alias_info\n"));
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
@@ -1368,9 +1477,11 @@ NTSTATUS cli_samr_query_alias_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Query domain info */
|
||||
|
||||
NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint16 switch_value,
|
||||
SAM_UNK_CTR *ctr)
|
||||
NTSTATUS rpccli_samr_query_dom_info(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol,
|
||||
uint16 switch_value,
|
||||
SAM_UNK_CTR *ctr)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_DOMAIN_INFO q;
|
||||
@@ -1392,7 +1503,7 @@ NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_query_dom_info(&q, domain_pol, switch_value);
|
||||
|
||||
if (!samr_io_q_query_dom_info("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1417,12 +1528,21 @@ NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint16 switch_value,
|
||||
SAM_UNK_CTR *ctr)
|
||||
{
|
||||
return rpccli_samr_query_dom_info(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
domain_pol, switch_value, ctr);
|
||||
}
|
||||
|
||||
/* User change password */
|
||||
|
||||
NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *username,
|
||||
const char *newpassword,
|
||||
const char *oldpassword )
|
||||
NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *username,
|
||||
const char *newpassword,
|
||||
const char *oldpassword )
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_CHGPASSWD_USER q;
|
||||
@@ -1477,14 +1597,14 @@ NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
init_samr_q_chgpasswd_user(&q, cli->srv_name_slash, username,
|
||||
init_samr_q_chgpasswd_user(&q, cli->cli->srv_name_slash, username,
|
||||
new_nt_password,
|
||||
old_nt_hash_enc,
|
||||
new_lm_password,
|
||||
old_lanman_hash_enc);
|
||||
|
||||
if (!samr_io_q_chgpasswd_user("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_CHGPASSWD_USER, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, SAMR_CHGPASSWD_USER, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1507,6 +1627,15 @@ NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_chgpasswd_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *username,
|
||||
const char *newpassword,
|
||||
const char *oldpassword )
|
||||
{
|
||||
return rpccli_samr_chgpasswd_user(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
username, newpassword, oldpassword);
|
||||
}
|
||||
|
||||
/* This function returns the bizzare set of (max_entries, max_size) required
|
||||
for the QueryDisplayInfo RPC to actually work against a domain controller
|
||||
with large (10k and higher) numbers of users. These values were
|
||||
@@ -1541,11 +1670,12 @@ void get_query_dispinfo_params(int loop_count, uint32 *max_entries,
|
||||
|
||||
/* Query display info */
|
||||
|
||||
NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 *start_idx,
|
||||
uint16 switch_value, uint32 *num_entries,
|
||||
uint32 max_entries, uint32 max_size,
|
||||
SAM_DISPINFO_CTR *ctr)
|
||||
NTSTATUS rpccli_samr_query_dispinfo(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 *start_idx,
|
||||
uint16 switch_value, uint32 *num_entries,
|
||||
uint32 max_entries, uint32 max_size,
|
||||
SAM_DISPINFO_CTR *ctr)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_QUERY_DISPINFO q;
|
||||
@@ -1570,7 +1700,7 @@ NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
*start_idx, max_entries, max_size);
|
||||
|
||||
if (!samr_io_q_query_dispinfo("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1601,14 +1731,26 @@ NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol, uint32 *start_idx,
|
||||
uint16 switch_value, uint32 *num_entries,
|
||||
uint32 max_entries, uint32 max_size,
|
||||
SAM_DISPINFO_CTR *ctr)
|
||||
{
|
||||
return rpccli_samr_query_dispinfo(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
domain_pol, start_idx, switch_value,
|
||||
num_entries, max_entries, max_size, ctr);
|
||||
}
|
||||
|
||||
/* Lookup rids. Note that NT4 seems to crash if more than ~1000 rids are
|
||||
looked up in one packet. */
|
||||
|
||||
NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol,
|
||||
uint32 num_rids, uint32 *rids,
|
||||
uint32 *num_names, char ***names,
|
||||
uint32 **name_types)
|
||||
NTSTATUS rpccli_samr_lookup_rids(struct rpc_pipe_client *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol,
|
||||
uint32 num_rids, uint32 *rids,
|
||||
uint32 *num_names, char ***names,
|
||||
uint32 **name_types)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SAMR_Q_LOOKUP_RIDS q;
|
||||
@@ -1636,7 +1778,7 @@ NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
init_samr_q_lookup_rids(mem_ctx, &q, domain_pol, 1000, num_rids, rids);
|
||||
|
||||
if (!samr_io_q_lookup_rids("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, PI_SAMR, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
|
||||
!rpc_api_pipe_req_int(cli, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1679,6 +1821,17 @@ NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *domain_pol,
|
||||
uint32 num_rids, uint32 *rids,
|
||||
uint32 *num_names, char ***names,
|
||||
uint32 **name_types)
|
||||
{
|
||||
return rpccli_samr_lookup_rids(&cli->pipes[PI_SAMR], mem_ctx,
|
||||
domain_pol, num_rids, rids,
|
||||
num_names, names, name_types);
|
||||
}
|
||||
|
||||
/* Lookup names */
|
||||
|
||||
NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
|
||||
@@ -1240,6 +1240,32 @@ BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth,
|
||||
const char **str)
|
||||
{
|
||||
size_t len;
|
||||
char *tmp_str;
|
||||
|
||||
if (UNMARSHALLING(ps))
|
||||
len = strlen(&ps->data_p[ps->data_offset]);
|
||||
else
|
||||
len = strlen(*str);
|
||||
|
||||
tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
|
||||
|
||||
if (tmp_str == NULL)
|
||||
return False;
|
||||
|
||||
if (MARSHALLING(ps))
|
||||
strncpy(tmp_str, *str, len);
|
||||
|
||||
if (!prs_string(name, ps, depth, tmp_str, len+1))
|
||||
return False;
|
||||
|
||||
*str = tmp_str;
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
prs_uint16 wrapper. Call this and it sets up a pointer to where the
|
||||
uint16 should be stored, or gets the size if reading.
|
||||
|
||||
@@ -315,7 +315,7 @@ static NTSTATUS cmd_sign(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
/* still have session, just need to use it again */
|
||||
cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
|
||||
cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
if (cli->pipes[cli->pipe_idx].fnum != 0)
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ static NTSTATUS cmd_seal(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
|
||||
cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
|
||||
cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
if (cli->pipes[cli->pipe_idx].fnum != 0)
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
@@ -346,7 +346,7 @@ static NTSTATUS cmd_none(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
} else {
|
||||
/* still have session, just need to use it again */
|
||||
cli->pipe_auth_flags = 0;
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
if (cli->pipes[cli->pipe_idx].fnum != 0)
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
cli->pipe_auth_flags = 0;
|
||||
@@ -362,34 +362,19 @@ static NTSTATUS setup_schannel(struct cli_state *cli, int pipe_auth_flags,
|
||||
uchar trust_password[16];
|
||||
uint32 sec_channel_type;
|
||||
if (argc == 2) {
|
||||
strhex_to_str((char *)cli->auth_info.sess_key,
|
||||
strlen(argv[1]),
|
||||
argv[1]);
|
||||
memcpy(cli->sess_key, cli->auth_info.sess_key, sizeof(cli->sess_key));
|
||||
|
||||
strhex_to_str(cli->sess_key, strlen(argv[1]), argv[1]);
|
||||
cli->pipe_auth_flags = pipe_auth_flags;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
|
||||
if ((memcmp(cli->auth_info.sess_key, zeros, sizeof(cli->auth_info.sess_key)) != 0)) {
|
||||
if (cli->pipe_auth_flags == pipe_auth_flags) {
|
||||
if ((memcmp(cli->sess_key, zeros, sizeof(cli->sess_key)) != 0) &&
|
||||
(cli->pipe_auth_flags == pipe_auth_flags)) {
|
||||
/* already in this mode nothing to do */
|
||||
return NT_STATUS_OK;
|
||||
} else {
|
||||
/* schannel is setup, just need to use it again with new flags */
|
||||
cli->pipe_auth_flags = pipe_auth_flags;
|
||||
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
cli_nt_session_close(cli);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
if (!secrets_fetch_trust_account_password(lp_workgroup(),
|
||||
trust_password,
|
||||
NULL, &sec_channel_type)) {
|
||||
@@ -399,8 +384,8 @@ static NTSTATUS setup_schannel(struct cli_state *cli, int pipe_auth_flags,
|
||||
ret = cli_nt_setup_netsec(cli, sec_channel_type, pipe_auth_flags, trust_password);
|
||||
if (NT_STATUS_IS_OK(ret)) {
|
||||
char *hex_session_key;
|
||||
hex_encode(cli->auth_info.sess_key,
|
||||
sizeof(cli->auth_info.sess_key),
|
||||
hex_encode(cli->pipes[cli->pipe_idx].auth_info.sess_key,
|
||||
sizeof(cli->pipes[cli->pipe_idx].auth_info.sess_key),
|
||||
&hex_session_key);
|
||||
printf("Got Session key: %s\n", hex_session_key);
|
||||
SAFE_FREE(hex_session_key);
|
||||
@@ -523,7 +508,7 @@ static NTSTATUS do_cmd(struct cli_state *cli,
|
||||
|
||||
if (cmd_entry->pipe_idx != -1
|
||||
&& cmd_entry->pipe_idx != cli->pipe_idx) {
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx] != 0)
|
||||
if (cli->pipes[cli->pipe_idx].fnum != 0)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
|
||||
@@ -549,7 +534,7 @@ static NTSTATUS do_cmd(struct cli_state *cli,
|
||||
trust_password,
|
||||
&neg_flags, 2);
|
||||
if (!NT_STATUS_IS_OK(ntresult)) {
|
||||
ZERO_STRUCT(cli->auth_info.sess_key);
|
||||
ZERO_STRUCT(cli->pipes[cli->pipe_idx].auth_info.sess_key);
|
||||
printf("nt_setup_creds failed with %s\n", nt_errstr(ntresult));
|
||||
return ntresult;
|
||||
}
|
||||
|
||||
@@ -153,11 +153,16 @@ BOOL idmap_init(const char **remote_backend)
|
||||
Don't do id mapping. This is used to make winbind a netlogon proxy only.
|
||||
**************************************************************************/
|
||||
|
||||
void idmap_proxyonly(void)
|
||||
void idmap_set_proxyonly(void)
|
||||
{
|
||||
proxyonly = True;
|
||||
}
|
||||
|
||||
BOOL idmap_proxyonly(void)
|
||||
{
|
||||
return proxyonly;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
This is a rare operation, designed to allow an explicit mapping to be
|
||||
set up for a sid to a POSIX id.
|
||||
@@ -223,7 +228,7 @@ NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (remote_map == NULL) {
|
||||
if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -288,7 +293,7 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
|
||||
if (NT_STATUS_IS_OK(ret))
|
||||
return ret;
|
||||
|
||||
if (remote_map == NULL)
|
||||
if ((remote_map == NULL) || (loc_type & ID_CACHE_ONLY))
|
||||
return ret;
|
||||
|
||||
/* We have a second chance, ask our authoritative backend */
|
||||
|
||||
@@ -71,7 +71,8 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
|
||||
else
|
||||
fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
|
||||
|
||||
pstr_sprintf(id_str, "%d", ((id_type & ID_USERID) ? id.uid : id.gid));
|
||||
pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
|
||||
(unsigned long)id.gid));
|
||||
|
||||
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
|
||||
|
||||
@@ -500,9 +501,9 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
|
||||
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
|
||||
|
||||
pstrcpy( suffix, lp_ldap_idmap_suffix() );
|
||||
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))",
|
||||
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
|
||||
LDAP_OBJ_IDMAP_ENTRY, type,
|
||||
((id_type & ID_USERID) ? id.uid : id.gid));
|
||||
((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
|
||||
|
||||
attr_list = get_attr_list( sidmap_attr_list );
|
||||
rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
|
||||
@@ -700,8 +701,8 @@ static NTSTATUS verify_idpool( void )
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
fstr_sprintf( uid_str, "%d", luid );
|
||||
fstr_sprintf( gid_str, "%d", lgid );
|
||||
fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
|
||||
fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
|
||||
|
||||
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
|
||||
smbldap_set_mod( &mods, LDAP_MOD_ADD,
|
||||
|
||||
@@ -100,14 +100,13 @@ BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
|
||||
Returns SID pointer.
|
||||
*****************************************************************/
|
||||
|
||||
NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
|
||||
NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid, int flags)
|
||||
{
|
||||
unid_t id;
|
||||
int flags;
|
||||
|
||||
DEBUG(10,("idmap_uid_to_sid: uid = [%lu]\n", (unsigned long)uid));
|
||||
|
||||
flags = ID_USERID;
|
||||
flags |= ID_USERID;
|
||||
id.uid = uid;
|
||||
|
||||
return idmap_get_sid_from_id(sid, id, flags);
|
||||
@@ -118,20 +117,15 @@ NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
|
||||
Returns SID pointer.
|
||||
*****************************************************************/
|
||||
|
||||
NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid)
|
||||
NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid, int flags)
|
||||
{
|
||||
unid_t id;
|
||||
int flags;
|
||||
|
||||
DEBUG(10,("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid));
|
||||
|
||||
flags = ID_GROUPID;
|
||||
#if 0 /* JERRY */
|
||||
if (!idmap_check_ugid_is_in_free_range(gid)) {
|
||||
flags |= ID_QUERY_ONLY;
|
||||
}
|
||||
#endif
|
||||
flags |= ID_GROUPID;
|
||||
id.gid = gid;
|
||||
|
||||
return idmap_get_sid_from_id(sid, id, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ enum client_action
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<PI_MAX_PIPES; i++)
|
||||
smb_cli->nt_pipe_fnum[i] = 0xffff;
|
||||
smb_cli->pipes[i].fnum = 0xffff;
|
||||
}
|
||||
|
||||
setup_logging(pname, True);
|
||||
|
||||
@@ -141,7 +141,7 @@ int run_rpc_command(struct cli_state *cli_arg, const int pipe_idx, int conn_flag
|
||||
}
|
||||
|
||||
if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx])
|
||||
if (cli->pipes[cli->pipe_idx].fnum)
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
|
||||
@@ -663,11 +663,11 @@ static NTSTATUS rpc_user_del_internals(const DOM_SID *domain_sid,
|
||||
}
|
||||
|
||||
/* Display results */
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
d_printf("Failed to delete user account - %s\n", nt_errstr(result));
|
||||
} else {
|
||||
d_printf("Deleted user account\n");
|
||||
}
|
||||
} else {
|
||||
d_printf("Deleted user account\n");
|
||||
}
|
||||
|
||||
done:
|
||||
return result;
|
||||
@@ -4452,6 +4452,7 @@ static int rpc_trustdom_add(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove interdomain trust account from the RPC server.
|
||||
* All parameters (except for argc and argv) are passed by run_rpc_command
|
||||
@@ -4583,6 +4584,7 @@ static int rpc_trustdom_del(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establish trust relationship to a trusting domain.
|
||||
* Interdomain account must already be created on remote PDC.
|
||||
@@ -4739,7 +4741,7 @@ static int rpc_trustdom_establish(int argc, const char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx])
|
||||
if (cli->pipes[cli->pipe_idx].fnum)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
cli_shutdown(cli);
|
||||
|
||||
@@ -77,7 +77,7 @@ static int net_rpc_join_ok(const char *domain)
|
||||
|
||||
done:
|
||||
/* Close down pipe - this will clean up open policy handles */
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx])
|
||||
if (cli->pipes[cli->pipe_idx].fnum)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
cli_shutdown(cli);
|
||||
@@ -346,7 +346,7 @@ int net_rpc_join_newstyle(int argc, const char **argv)
|
||||
done:
|
||||
/* Close down pipe - this will clean up open policy handles */
|
||||
|
||||
if (cli->nt_pipe_fnum[cli->pipe_idx])
|
||||
if (cli->pipes[cli->pipe_idx].fnum)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
/* Display success or failure */
|
||||
|
||||
@@ -428,8 +428,7 @@ static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
|
||||
return False;
|
||||
}
|
||||
|
||||
notify_printer_byname(argv[2], attribute,
|
||||
CONST_DISCARD(char *, argv[4]));
|
||||
notify_printer_byname(argv[2], attribute, argv[4]);
|
||||
|
||||
goto send;
|
||||
}
|
||||
@@ -573,6 +572,53 @@ static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
|
||||
return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
|
||||
}
|
||||
|
||||
static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
|
||||
{
|
||||
fstring unix_name;
|
||||
memset( (char *)n, '\0', sizeof(struct nmb_name) );
|
||||
fstrcpy(unix_name, name);
|
||||
strupper_m(unix_name);
|
||||
push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
|
||||
n->name_type = (unsigned int)type & 0xFF;
|
||||
push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
|
||||
}
|
||||
|
||||
static BOOL do_nodestatus(const pid_t pid, const int argc,
|
||||
const char **argv)
|
||||
{
|
||||
struct packet_struct p;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(p);
|
||||
|
||||
p.ip = *interpret_addr2(argv[1]);
|
||||
p.port = 137;
|
||||
p.packet_type = NMB_PACKET;
|
||||
|
||||
p.packet.nmb.header.name_trn_id = 10;
|
||||
p.packet.nmb.header.opcode = 0;
|
||||
p.packet.nmb.header.response = False;
|
||||
p.packet.nmb.header.nm_flags.bcast = False;
|
||||
p.packet.nmb.header.nm_flags.recursion_available = False;
|
||||
p.packet.nmb.header.nm_flags.recursion_desired = False;
|
||||
p.packet.nmb.header.nm_flags.trunc = False;
|
||||
p.packet.nmb.header.nm_flags.authoritative = False;
|
||||
p.packet.nmb.header.rcode = 0;
|
||||
p.packet.nmb.header.qdcount = 1;
|
||||
p.packet.nmb.header.ancount = 0;
|
||||
p.packet.nmb.header.nscount = 0;
|
||||
p.packet.nmb.header.arcount = 0;
|
||||
my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
|
||||
p.packet.nmb.question.question_type = 0x21;
|
||||
p.packet.nmb.question.question_class = 0x1;
|
||||
|
||||
return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
|
||||
}
|
||||
|
||||
/* A list of message type supported */
|
||||
|
||||
static const struct {
|
||||
@@ -597,6 +643,7 @@ static const struct {
|
||||
{ "shutdown", do_shutdown, "Shut down daemon" },
|
||||
{ "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
|
||||
{ "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
|
||||
{ "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
|
||||
{ "noop", do_noop, "Do nothing" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user