1
0
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:
Gerald Carter
2005-06-08 22:10:34 +00:00
committed by Gerald (Jerry) Carter
parent 0d303ab2f3
commit a0ac9a8ffd
51 changed files with 7628 additions and 3246 deletions

View File

@@ -328,7 +328,6 @@ GROUPDB_OBJ = groupdb/mapping.o
PROFILE_OBJ = profile/profile.o
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

View File

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

View File

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

View File

@@ -804,7 +804,12 @@ extern int errno;
#include "tdb/tdb.h"
#include "tdb/spinlock.h"
#include "tdb/tdbutil.h"
#include "talloc.h"
/* And a little extension. Abort on type mismatch */
#define talloc_get_type_abort(ptr, type) \
(type *)talloc_check_name_abort(ptr, #type)
#include "nt_status.h"
#include "ads.h"
#include "interfaces.h"

View File

@@ -46,6 +46,7 @@
/* nmbd messages */
#define MSG_FORCE_ELECTION 1001
#define MSG_WINS_NEW_ENTRY 1002
#define MSG_SEND_PACKET 1003
/* printing messages */
/* #define MSG_PRINTER_NOTIFY 2001*/ /* Obsolete */
@@ -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. */

View File

@@ -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 */

View File

@@ -2668,6 +2668,29 @@ void name_to_fqdn(fstring fqdn, const char *name)
}
}
/**********************************************************************
Extension to talloc_get_type: Abort on type mismatch
***********************************************************************/
void *talloc_check_name_abort(const void *ptr, const char *name)
{
void *result;
if (ptr == NULL)
return NULL;
result = talloc_check_name(ptr, name);
if (result != NULL)
return result;
DEBUG(0, ("Talloc type mismatch, expected %s, got %s\n",
name, talloc_get_name(ptr)));
smb_panic("aborting");
/* Keep the compiler happy */
return NULL;
}
#ifdef __INSURE__
/*******************************************************************

View File

@@ -342,6 +342,12 @@ BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
return False;
}
BOOL sid_compose(DOM_SID *dst, const DOM_SID *domain_sid, uint32 rid)
{
sid_copy(dst, domain_sid);
return sid_append_rid(dst, rid);
}
/*****************************************************************
Removes the last rid from the end of a sid
*****************************************************************/

View File

@@ -2128,3 +2128,69 @@ BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
*num += 1;
return True;
}
/* Append an sprintf'ed string. Double buffer size on demand. Usable without
* error checking in between. The indiation that something weird happened is
* string==NULL */
void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
size_t *bufsize, const char *fmt, ...)
{
va_list ap;
char *newstr;
int ret;
BOOL increased;
/* len<0 is an internal marker that something failed */
if (*len < 0)
goto error;
if (*string == NULL) {
if (*bufsize == 0)
*bufsize = 128;
if (mem_ctx != NULL)
*string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
else
*string = SMB_MALLOC_ARRAY(char, *bufsize);
if (*string == NULL)
goto error;
}
va_start(ap, fmt);
ret = vasprintf(&newstr, fmt, ap);
va_end(ap);
if (ret < 0)
goto error;
increased = False;
while ((*len)+ret >= *bufsize) {
increased = True;
*bufsize *= 2;
if (*bufsize >= (1024*1024*256))
goto error;
}
if (increased) {
if (mem_ctx != NULL)
*string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
*bufsize);
else
*string = SMB_REALLOC_ARRAY(*string, char, *bufsize);
if (*string == NULL)
goto error;
}
StrnCpy((*string)+(*len), newstr, ret);
(*len) += ret;
free(newstr);
return;
error:
*len = -1;
*string = NULL;
}

View File

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

View File

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

View File

@@ -22,8 +22,6 @@
#include "includes.h"
extern int smb_read_error;
/****************************************************************************
Change the timeout (in milliseconds).
****************************************************************************/
@@ -83,6 +81,7 @@ static BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
BOOL cli_receive_smb(struct cli_state *cli)
{
extern int smb_read_error;
BOOL ret;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
@@ -321,9 +320,9 @@ struct cli_state *cli_initialise(struct cli_state *cli)
cli_null_set_signing(cli);
for (i=0; i<PI_MAX_PIPES; i++)
cli->nt_pipe_fnum[i] = 0;
cli->pipes[i].fnum = 0;
cli->saved_netlogon_pipe_fnum = 0;
cli->netlogon_pipe.fnum = 0;
cli->initialised = 1;
cli->allocated = alloced_cli;
@@ -353,14 +352,14 @@ void cli_nt_session_close(struct cli_state *cli)
{
int i;
if (cli->ntlmssp_pipe_state) {
ntlmssp_end(&cli->ntlmssp_pipe_state);
}
for (i=0; i<PI_MAX_PIPES; i++) {
if (cli->nt_pipe_fnum[i] != 0)
cli_close(cli, cli->nt_pipe_fnum[i]);
cli->nt_pipe_fnum[i] = 0;
if (cli->pipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state);
}
if (cli->pipes[i].fnum != 0)
cli_close(cli, cli->pipes[i].fnum);
cli->pipes[i].fnum = 0;
}
cli->pipe_idx = -1;
}
@@ -371,9 +370,9 @@ close the NETLOGON session holding the session key for NETSEC
void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
{
if (cli->saved_netlogon_pipe_fnum != 0) {
cli_close(cli, cli->saved_netlogon_pipe_fnum);
cli->saved_netlogon_pipe_fnum = 0;
if (cli->netlogon_pipe.fnum != 0) {
cli_close(cli, cli->netlogon_pipe.fnum);
cli->netlogon_pipe.fnum = 0;
}
}
@@ -408,8 +407,8 @@ void cli_close_connection(struct cli_state *cli)
data_blob_free(&cli->secblob);
data_blob_free(&cli->user_session_key);
if (cli->ntlmssp_pipe_state)
ntlmssp_end(&cli->ntlmssp_pipe_state);
if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP)
ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state);
if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx);

View File

@@ -505,7 +505,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*/
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
if (cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
if (cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
cli_signing_trans_stop(cli);
return(False);
}
@@ -639,7 +639,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
}
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
if(cli->nt_pipe_fnum[cli->pipe_idx] == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
if(cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
cli_signing_trans_stop(cli);
return(False);
}

View File

@@ -323,6 +323,56 @@ static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t
}
}
static void msg_nmbd_send_packet(int msg_type, pid_t src,
void *buf, size_t len)
{
struct packet_struct *p = (struct packet_struct *)buf;
struct subnet_record *subrec;
struct in_addr *local_ip;
DEBUG(10, ("Received send_packet from %d\n", src));
if (len != sizeof(struct packet_struct)) {
DEBUG(2, ("Discarding invalid packet length from %d\n", src));
return;
}
if ((p->packet_type != NMB_PACKET) &&
(p->packet_type != DGRAM_PACKET)) {
DEBUG(2, ("Discarding invalid packet type from %d: %d\n",
src, p->packet_type));
return;
}
local_ip = iface_ip(p->ip);
if (local_ip == NULL) {
DEBUG(2, ("Could not find ip for packet from %d\n", src));
return;
}
subrec = FIRST_SUBNET;
p->fd = (p->packet_type == NMB_PACKET) ?
subrec->nmb_sock : subrec->dgram_sock;
for (subrec = FIRST_SUBNET; subrec != NULL;
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
if (ip_equal(*local_ip, subrec->myip)) {
p->fd = (p->packet_type == NMB_PACKET) ?
subrec->nmb_sock : subrec->dgram_sock;
break;
}
}
if (p->packet_type == DGRAM_PACKET) {
p->port = 138;
p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
p->packet.dgram.header.source_port = 138;
}
send_packet(p);
}
/**************************************************************************** **
The main select loop.
@@ -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 ) );

View File

@@ -257,6 +257,32 @@ BOOL winbind_allocate_rid(uint32 *rid)
return True;
}
BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
/* Initialise request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
/* Make request */
result = winbindd_request(WINBINDD_ALLOCATE_RID_AND_GID, &request,
&response);
if (result != NSS_STATUS_SUCCESS)
return False;
/* Copy out result */
*rid = response.data.rid_and_gid.rid;
*gid = response.data.rid_and_gid.gid;
return True;
}
/* Fetch the list of groups a user is a member of from winbindd. This is
used by winbind_getgroups. */

View File

@@ -167,6 +167,32 @@ static BOOL wbinfo_get_usersids(char *user_sid)
return True;
}
static BOOL wbinfo_get_userdomgroups(const char *user_sid)
{
struct winbindd_request request;
struct winbindd_response response;
NSS_STATUS result;
ZERO_STRUCT(response);
/* Send request */
fstrcpy(request.data.sid, user_sid);
result = winbindd_request(WINBINDD_GETUSERDOMGROUPS, &request,
&response);
if (result != NSS_STATUS_SUCCESS)
return False;
if (response.data.num_entries != 0)
printf("%s", (char *)response.extra_data);
SAFE_FREE(response.extra_data);
return True;
}
/* Convert NetBIOS name to IP */
static BOOL wbinfo_wins_byname(char *name)
@@ -224,7 +250,6 @@ static BOOL wbinfo_wins_byip(char *ip)
static BOOL wbinfo_list_domains(void)
{
struct winbindd_response response;
fstring name;
ZERO_STRUCT(response);
@@ -238,9 +263,19 @@ static BOOL wbinfo_list_domains(void)
if (response.extra_data) {
const char *extra_data = (char *)response.extra_data;
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;

View File

@@ -6,6 +6,7 @@
Copyright (C) by Tim Potter 2000-2002
Copyright (C) Andrew Tridgell 2002
Copyright (C) Jelmer Vernooij 2003
Copyright (C) Volker Lendecke 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
BOOL opt_nocache = False;
BOOL opt_dual_daemon = True;
static BOOL interactive = False;
extern BOOL override_logfile;
@@ -131,7 +133,6 @@ static void winbindd_status(void)
static void print_winbindd_status(void)
{
winbindd_status();
winbindd_cm_status();
}
/* Flush client cache */
@@ -163,6 +164,17 @@ static void terminate(void)
pstr_sprintf(path, "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path);
#if 0
if (interactive) {
TALLOC_CTX *mem_ctx = talloc_init("end_description");
char *description = talloc_describe_all(mem_ctx);
DEBUG(3, ("tallocs left:\n%s\n", description));
talloc_destroy(mem_ctx);
}
#endif
exit(0);
}
@@ -190,14 +202,11 @@ static void sighup_handler(int signum)
sys_select_signal();
}
static BOOL do_sigchld;
static void sigchld_handler(int signum)
{
pid_t pid;
int status;
while ((pid = wait(&status)) != -1 || errno == EINTR) {
continue; /* Reap children */
}
do_sigchld = True;
sys_select_signal();
}
@@ -215,13 +224,7 @@ static void msg_shutdown(int msg_type, pid_t src, void *buf, size_t len)
terminate();
}
struct dispatch_table {
enum winbindd_cmd cmd;
enum winbindd_result (*fn)(struct winbindd_cli_state *state);
const char *winbindd_cmd_name;
};
static struct dispatch_table dispatch_table[] = {
static struct winbindd_dispatch_table dispatch_table[] = {
/* User functions */
@@ -234,6 +237,8 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
{ WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
{ WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
"GETUSERDOMGROUPS" },
/* Group functions */
@@ -247,14 +252,15 @@ static struct dispatch_table dispatch_table[] = {
/* PAM auth functions */
{ WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
{ WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
{ WINBINDD_PAM_AUTH_CRAP, winbindd_crap_auth, "AUTH_CRAP" },
{ WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
/* Enumeration functions */
{ WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
{ WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
{ WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
{ WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
"LIST_TRUSTDOM" },
{ WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
/* SID related functions */
@@ -266,20 +272,25 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
{ WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid,
"ALLOCATE_RID_AND_GID" },
/* Miscellaneous */
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
{ WINBINDD_PING, winbindd_ping, "PING" },
{ WINBINDD_INFO, winbindd_info, "INFO" },
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
"INTERFACE_VERSION" },
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" },
{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
"WINBINDD_PRIV_PIPE_DIR" },
{ WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
/* WINS functions */
@@ -293,7 +304,7 @@ static struct dispatch_table dispatch_table[] = {
static void process_request(struct winbindd_cli_state *state)
{
struct dispatch_table *table = dispatch_table;
struct winbindd_dispatch_table *table = dispatch_table;
/* Free response data - we may be interrupted and receive another
command before being able to send this data off. */
@@ -302,26 +313,255 @@ static void process_request(struct winbindd_cli_state *state)
ZERO_STRUCT(state->response);
state->response.result = WINBINDD_ERROR;
state->response.result = WINBINDD_PENDING;
state->response.length = sizeof(struct winbindd_response);
state->mem_ctx = talloc_init("winbind request");
if (state->mem_ctx == NULL)
return;
/* Process command */
for (table = dispatch_table; table->fn; table++) {
if (state->request.cmd == table->cmd) {
DEBUG(10,("process_request: request fn %s\n", table->winbindd_cmd_name ));
DEBUG(10,("process_request: request fn %s\n",
table->winbindd_cmd_name ));
state->response.result = table->fn(state);
break;
}
}
if (!table->fn)
DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd ));
if (!table->fn) {
DEBUG(10,("process_request: unknown request fn number %d\n",
(int)state->request.cmd ));
state->response.result = WINBINDD_ERROR;
}
}
/* 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();

View File

@@ -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 */

View File

@@ -27,8 +27,6 @@
#ifdef HAVE_ADS
extern struct winbindd_methods msrpc_methods, cache_methods;
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -78,6 +76,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
status = ads_connect(ads);
if (!ADS_ERR_OK(status) || !ads->config.realm) {
extern struct winbindd_methods msrpc_methods, cache_methods;
DEBUG(1,("ads_connect for domain %s failed: %s\n",
domain->name, ads_errstr(status)));
ads_destroy(&ads);
@@ -157,9 +156,6 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
char *name, *gecos;
DOM_SID sid;
DOM_SID *sid2;
DOM_SID *group_sid;
uint32 group;
uint32 atype;
@@ -171,7 +167,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
name = ads_pull_username(ads, mem_ctx, msg);
gecos = ads_pull_string(ads, mem_ctx, msg, "name");
if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
if (!ads_pull_sid(ads, msg, "objectSid",
&(*info)[i].user_sid)) {
DEBUG(1,("No sid for %s !?\n", name));
continue;
}
@@ -180,20 +177,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
continue;
}
sid2 = TALLOC_P(mem_ctx, DOM_SID);
if (!sid2) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
sid_copy(sid2, &sid);
group_sid = rid_to_talloced_sid(domain, mem_ctx, group);
(*info)[i].acct_name = name;
(*info)[i].full_name = gecos;
(*info)[i].user_sid = sid2;
(*info)[i].group_sid = group_sid;
sid_compose(&(*info)[i].group_sid, &domain->sid, group);
i++;
}
@@ -386,8 +372,6 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
char *sidstr;
uint32 group_rid;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
DOM_SID *sid2;
fstring sid_string;
DEBUG(3,("ads: query_user\n"));
@@ -404,13 +388,15 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
free(ldap_exp);
free(sidstr);
if (!ADS_ERR_OK(rc) || !msg) {
DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc)));
DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
sid_string_static(sid), ads_errstr(rc)));
goto done;
}
count = ads_count_replies(ads, msg);
if (count != 1) {
DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid)));
DEBUG(1,("query_user(sid=%s): Not found\n",
sid_string_static(sid)));
goto done;
}
@@ -418,20 +404,13 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid)));
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;
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -4,6 +4,7 @@
Winbind background daemon
Copyright (C) Andrew Tridgell 2002
Copyright (C) Volker Lendecke 2004,2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -51,6 +52,39 @@ struct dual_list {
static struct dual_list *dual_list;
static struct dual_list *dual_list_end;
/* Read some data from a client connection */
static void dual_client_read(struct winbindd_cli_state *state)
{
int n;
/* Read data */
n = sys_read(state->sock, state->read_buf_len +
(char *)&state->request,
sizeof(state->request) - state->read_buf_len);
DEBUG(10,("client_read: read %d bytes. Need %ld more for a full "
"request.\n", n, (unsigned long)(sizeof(state->request) - n -
state->read_buf_len) ));
/* Read failed, kill client */
if (n == -1 || n == 0) {
DEBUG(5,("read failed on sock %d, pid %lu: %s\n",
state->sock, (unsigned long)state->pid,
(n == -1) ? strerror(errno) : "EOF"));
state->finished = True;
return;
}
/* Update client state */
state->read_buf_len += n;
state->last_access = time(NULL);
}
/*
setup a select() including the dual daemon pipe
*/
@@ -176,7 +210,7 @@ void do_dual_daemon(void)
main_loop_talloc_free();
/* fetch a request from the main daemon */
winbind_client_read(&state);
dual_client_read(&state);
if (state.finished) {
/* we lost contact with our parent */
@@ -212,3 +246,412 @@ void do_dual_daemon(void)
}
}
/*
* Machinery for async requests sent to children. You set up a
* winbindd_request, select a child to query, and issue a async_request
* call. When the request is completed, the callback function you specified is
* called back with the private pointer you gave to async_request.
*/
struct winbindd_async_request {
struct winbindd_async_request *next, *prev;
TALLOC_CTX *mem_ctx;
struct winbindd_child *child;
struct winbindd_request *request;
struct winbindd_response *response;
void (*continuation)(void *private, BOOL success);
void *private;
};
static void async_request_sent(void *private, BOOL success);
static void async_reply_recv(void *private, BOOL success);
static void schedule_async_request(struct winbindd_child *child);
void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
struct winbindd_request *request,
struct winbindd_response *response,
void (*continuation)(void *private, BOOL success),
void *private)
{
struct winbindd_async_request *state, *tmp;
SMB_ASSERT(continuation != NULL);
state = TALLOC_P(mem_ctx, struct winbindd_async_request);
if (state == NULL) {
DEBUG(0, ("talloc failed\n"));
continuation(private, False);
return;
}
state->mem_ctx = mem_ctx;
state->child = child;
state->request = request;
state->response = response;
state->continuation = continuation;
state->private = private;
DLIST_ADD_END(child->requests, state, tmp);
schedule_async_request(child);
return;
}
static void async_request_sent(void *private, BOOL success)
{
struct winbindd_async_request *state =
talloc_get_type_abort(private, struct winbindd_async_request);
if (!success) {
DEBUG(5, ("Could not send async request\n"));
state->response->length = sizeof(struct winbindd_response);
state->response->result = WINBINDD_ERROR;
state->continuation(state->private, False);
return;
}
/* Request successfully sent to the child, setup the wait for reply */
setup_async_read(&state->child->event,
&state->response->result,
sizeof(state->response->result),
async_reply_recv, state);
}
static void async_reply_recv(void *private, BOOL success)
{
struct winbindd_async_request *state =
talloc_get_type_abort(private, struct winbindd_async_request);
struct winbindd_child *child = state->child;
state->response->length = sizeof(struct winbindd_response);
if (!success) {
DEBUG(5, ("Could not receive async reply\n"));
state->response->result = WINBINDD_ERROR;
}
if (state->response->result == WINBINDD_OK)
SMB_ASSERT(cache_retrieve_response(child->pid,
state->response));
DLIST_REMOVE(child->requests, state);
schedule_async_request(child);
state->continuation(state->private, True);
}
static BOOL fork_domain_child(struct winbindd_child *child);
static void schedule_async_request(struct winbindd_child *child)
{
struct winbindd_async_request *request = child->requests;
if (request == NULL) {
return;
}
if (child->event.flags != 0) {
return; /* Busy */
}
if ((child->pid == 0) && (!fork_domain_child(child))) {
/* Cancel all outstanding requests */
while (request != NULL) {
/* request might be free'd in the continuation */
struct winbindd_async_request *next = request->next;
request->continuation(request->private, False);
request = next;
}
return;
}
setup_async_write(&child->event, request->request,
sizeof(*request->request),
async_request_sent, request);
return;
}
struct domain_request_state {
TALLOC_CTX *mem_ctx;
struct winbindd_domain *domain;
struct winbindd_request *request;
struct winbindd_response *response;
void (*continuation)(void *private, BOOL success);
void *private;
};
static void domain_init_recv(void *private, BOOL success);
void async_domain_request(TALLOC_CTX *mem_ctx,
struct winbindd_domain *domain,
struct winbindd_request *request,
struct winbindd_response *response,
void (*continuation)(void *private, BOOL success),
void *private)
{
struct domain_request_state *state;
if (domain->initialized) {
async_request(mem_ctx, &domain->child, request, response,
continuation, private);
return;
}
state = TALLOC_P(mem_ctx, struct domain_request_state);
if (state == NULL) {
DEBUG(0, ("talloc failed\n"));
continuation(private, False);
return;
}
state->mem_ctx = mem_ctx;
state->domain = domain;
state->request = request;
state->response = response;
state->continuation = continuation;
state->private = private;
init_child_connection(domain, domain_init_recv, state);
}
static void domain_init_recv(void *private, BOOL success)
{
struct domain_request_state *state =
talloc_get_type_abort(private, struct domain_request_state);
if (!success) {
DEBUG(5, ("Domain init returned an error\n"));
state->continuation(state->private, False);
return;
}
async_request(state->mem_ctx, &state->domain->child,
state->request, state->response,
state->continuation, state->private);
}
struct winbindd_child_dispatch_table {
enum winbindd_cmd cmd;
enum winbindd_result (*fn)(struct winbindd_domain *domain,
struct winbindd_cli_state *state);
const char *winbindd_cmd_name;
};
static struct winbindd_child_dispatch_table child_dispatch_table[] = {
{ WINBINDD_LOOKUPSID, winbindd_dual_lookupsid, "LOOKUPSID" },
{ WINBINDD_LOOKUPNAME, winbindd_dual_lookupname, "LOOKUPNAME" },
{ WINBINDD_LIST_TRUSTDOM, winbindd_dual_list_trusted_domains,
"LIST_TRUSTDOM" },
{ WINBINDD_INIT_CONNECTION, winbindd_dual_init_connection,
"INIT_CONNECTION" },
{ WINBINDD_GETDCNAME, winbindd_dual_getdcname, "GETDCNAME" },
{ WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence,
"SHOW_SEQUENCE" },
{ WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" },
{ WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" },
{ WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct,
"CHECK_MACHACC" },
{ WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" },
{ WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" },
{ WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" },
{ WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" },
{ WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" },
{ WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" },
{ WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" },
{ WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
{ WINBINDD_ALLOCATE_RID, winbindd_dual_allocate_rid, "ALLOCATE_RID" },
{ WINBINDD_ALLOCATE_RID_AND_GID, winbindd_dual_allocate_rid_and_gid,
"ALLOCATE_RID_AND_GID" },
{ WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups,
"GETUSERDOMGROUPS" },
{ WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases,
"GETSIDALIASES" },
/* End of list */
{ WINBINDD_NUM_CMDS, NULL, "NONE" }
};
static void child_process_request(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
struct winbindd_child_dispatch_table *table;
/* Free response data - we may be interrupted and receive another
command before being able to send this data off. */
state->response.result = WINBINDD_ERROR;
state->response.length = sizeof(struct winbindd_response);
state->mem_ctx = talloc_init("winbind request");
if (state->mem_ctx == NULL)
return;
/* Process command */
for (table = child_dispatch_table; table->fn; table++) {
if (state->request.cmd == table->cmd) {
DEBUG(10,("process_request: request fn %s\n",
table->winbindd_cmd_name ));
state->response.result = table->fn(domain, state);
break;
}
}
if (!table->fn) {
DEBUG(10,("process_request: unknown request fn number %d\n",
(int)state->request.cmd ));
state->response.result = WINBINDD_ERROR;
}
talloc_destroy(state->mem_ctx);
}
void setup_domain_child(struct winbindd_domain *domain,
struct winbindd_child *child,
const char *explicit_logfile)
{
if (explicit_logfile != NULL) {
pstr_sprintf(child->logfilename, "%s/log.winbindd-%s",
dyn_LOGFILEBASE, explicit_logfile);
} else if (domain != NULL) {
pstr_sprintf(child->logfilename, "%s/log.wb-%s",
dyn_LOGFILEBASE, domain->name);
} else {
smb_panic("Internal error: domain == NULL && "
"explicit_logfile == NULL");
}
child->domain = domain;
}
struct winbindd_child *children = NULL;
void winbind_child_died(pid_t pid)
{
struct winbindd_child *child;
for (child = children; child != NULL; child = child->next) {
if (child->pid == pid) {
break;
}
}
if (child == NULL) {
DEBUG(0, ("Unknown child %d died!\n", pid));
return;
}
remove_fd_event(&child->event);
close(child->event.fd);
child->event.fd = 0;
child->event.flags = 0;
child->pid = 0;
schedule_async_request(child);
}
static BOOL fork_domain_child(struct winbindd_child *child)
{
int fdpair[2];
struct winbindd_cli_state state;
extern BOOL override_logfile;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fdpair) != 0) {
DEBUG(0, ("Could not open child pipe: %s\n",
strerror(errno)));
return False;
}
ZERO_STRUCT(state);
state.pid = getpid();
child->pid = sys_fork();
if (child->pid == -1) {
DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
return False;
}
if (child->pid != 0) {
/* Parent */
close(fdpair[0]);
child->next = child->prev = NULL;
DLIST_ADD(children, child);
child->event.fd = fdpair[1];
child->event.flags = 0;
child->requests = NULL;
add_fd_event(&child->event);
return True;
}
/* Child */
state.sock = fdpair[0];
close(fdpair[1]);
/* tdb needs special fork handling */
if (tdb_reopen_all() == -1) {
DEBUG(0,("tdb_reopen_all failed.\n"));
_exit(0);
}
close_conns_after_fork();
if (!override_logfile) {
lp_set_logfile(child->logfilename);
reopen_logs();
}
dual_daemon_pipe = -1;
opt_dual_daemon = False;
while (1) {
/* free up any talloc memory */
lp_talloc_free();
main_loop_talloc_free();
/* fetch a request from the main daemon */
dual_client_read(&state);
if (state.finished) {
/* we lost contact with our parent */
exit(0);
}
/* process full rquests */
if (state.read_buf_len == sizeof(state.request)) {
DEBUG(4,("child daemon request %d\n",
(int)state.request.cmd));
state.request.null_term = '\0';
child_process_request(child->domain, &state);
if (state.response.result == WINBINDD_OK)
cache_store_response(sys_getpid(),
&state.response);
SAFE_FREE(state.response.extra_data);
/* We just send the result code back, the result
* structure needs to be fetched via the
* winbindd_cache. Hmm. That needs fixing... */
if (write_data(state.sock,
(void *)&state.response.result,
sizeof(state.response.result)) !=
sizeof(state.response.result)) {
DEBUG(0, ("Could not write result\n"));
exit(1);
}
state.read_buf_len = 0;
}
}
}

View File

@@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
enum SID_NAME_USE group_name_type,
int *num_gr_mem, char **gr_mem, int *gr_mem_len)
{
DOM_SID **sid_mem = NULL;
DOM_SID *sid_mem = NULL;
uint32 num_names = 0;
uint32 *name_types = NULL;
unsigned int buf_len, buf_ndx, i;
@@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
if (DEBUGLEVEL >= 10) {
for (i = 0; i < num_names; i++)
DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]),
DEBUG(10, ("\t%20s %s %d\n", names[i],
sid_string_static(&sid_mem[i]),
name_types[i]));
}
@@ -222,7 +223,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
parse_domain_user(tmp, name_domain, name_group);
/* if no domain or our local domain, default to our local domain for aliases */
/* if no domain or our local domain and no local tdb group, default to
* our local domain for aliases */
if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
fstrcpy(name_domain, get_global_sam_name());
@@ -245,8 +247,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
/* Get rid and name type from name */
if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid,
&name_type)) {
if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name,
name_group, &group_sid, &name_type)) {
DEBUG(1, ("group %s in domain %s does not exist\n",
name_group, name_domain));
return WINBINDD_ERROR;
@@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
/* Get rid from gid */
if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) {
DEBUG(1, ("could not convert gid %lu to rid\n",
(unsigned long)state->request.data.gid));
return WINBINDD_ERROR;
@@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
/* Get name from sid */
if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) {
if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
group_name, &name_type)) {
DEBUG(1, ("could not lookup sid\n"));
return WINBINDD_ERROR;
}
/* Fill in group structure */
domain = find_domain_from_sid(&group_sid);
domain = find_domain_from_sid_noinit(&group_sid);
if (!domain) {
DEBUG(1,("Can't find domain from sid\n"));
@@ -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;
}

View File

@@ -0,0 +1,646 @@
/*
Unix SMB/CIFS implementation.
winbind ldap proxy code
Copyright (C) Volker Lendecke
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "winbindd.h"
/* This rw-buf api is made to avoid memcpy. For now do that like mad... The
idea is to write into a circular list of buffers where the ideal case is
that a read(2) holds a complete request that is then thrown away
completely. */
struct ldap_message_queue {
struct ldap_message_queue *prev, *next;
struct ldap_message *msg;
};
struct rw_buffer {
uint8_t *data;
size_t ofs, length;
};
struct winbind_ldap_client {
struct winbind_ldap_client *next, *prev;
int sock;
BOOL finished;
struct rw_buffer in_buffer, out_buffer;
};
static struct winbind_ldap_client *ldap_clients;
struct winbind_ldap_server {
struct winbind_ldap_server *next, *prev;
int sock;
BOOL ready; /* Bind successful? */
BOOL finished;
struct rw_buffer in_buffer, out_buffer;
int messageid;
};
static struct winbind_ldap_server *ldap_servers;
struct pending_ldap_message {
struct pending_ldap_message *next, *prev;
struct ldap_message *msg; /* The message the client sent us */
int our_msgid; /* The messageid we used */
struct winbind_ldap_client *client;
};
struct pending_ldap_message *pending_messages;
static BOOL append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
{
buf->data = SMB_REALLOC(buf->data, buf->length+length);
if (buf->data == NULL)
return False;
memcpy(buf->data+buf->length, data, length);
buf->length += length;
return True;
}
static BOOL read_into_buf(int fd, struct rw_buffer *buf)
{
char tmp_buf[1024];
int len;
len = read(fd, tmp_buf, sizeof(tmp_buf));
if (len == 0)
return False;
return append_to_buf(buf, tmp_buf, len);
}
static void peek_into_buf(struct rw_buffer *buf, uint8_t **out,
size_t *out_length)
{
*out = buf->data;
*out_length = buf->length;
}
static void consumed_from_buf(struct rw_buffer *buf, size_t length)
{
uint8_t *new = memdup(buf->data+length, buf->length-length);
free(buf->data);
buf->data = new;
buf->length -= length;
}
static BOOL write_out_of_buf(int fd, struct rw_buffer *buf)
{
uint8_t *tmp;
size_t tmp_length, written;
peek_into_buf(buf, &tmp, &tmp_length);
if (tmp_length == 0)
return True;
written = write(fd, tmp, tmp_length);
if (written < 0)
return False;
consumed_from_buf(buf, written);
return True;
}
static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
{
DATA_BLOB blob;
BOOL res;
if (!ldap_encode(msg, &blob))
return False;
res = append_to_buf(buf, blob.data, blob.length);
data_blob_free(&blob);
return res;
}
static void new_ldap_client(int listen_sock)
{
struct sockaddr_un sunaddr;
struct winbind_ldap_client *client;
socklen_t len;
int sock;
/* Accept connection */
len = sizeof(sunaddr);
do {
sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
} while (sock == -1 && errno == EINTR);
if (sock == -1)
return;
DEBUG(6,("accepted socket %d\n", sock));
/* Create new connection structure */
client = SMB_MALLOC_P(struct winbind_ldap_client);
if (client == NULL)
return;
ZERO_STRUCTP(client);
client->sock = sock;
client->finished = False;
DLIST_ADD(ldap_clients, client);
}
static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,
BOOL *error)
{
uint8_t *buf;
int buf_length, msg_length;
DATA_BLOB blob;
ASN1_DATA data;
struct ldap_message *msg;
DEBUG(10,("ldapsrv_recv\n"));
*error = False;
peek_into_buf(buffer, &buf, &buf_length);
if (buf_length < 8) {
/* Arbitrary heuristics: ldap messages are longer than eight
* bytes, and their tag length fits into the eight bytes */
return NULL;
}
/* LDAP Messages are always SEQUENCES */
if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
&msg_length))
goto disconnect;
if (buf_length < msg_length) {
/* Not enough yet */
return NULL;
}
/* We've got a complete LDAP request in the in-buffer */
blob.data = buf;
blob.length = msg_length;
if (!asn1_load(&data, blob))
goto disconnect;
msg = new_ldap_message();
if ((msg == NULL) || !ldap_decode(&data, msg)) {
asn1_free(&data);
goto disconnect;
}
asn1_free(&data);
consumed_from_buf(buffer, msg_length);
return msg;
disconnect:
*error = True;
return NULL;
}
static int send_msg_to_server(struct ldap_message *msg,
struct winbind_ldap_server *server)
{
int cli_messageid;
cli_messageid = msg->messageid;
msg->messageid = ldap_servers->messageid;
if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))
return -1;
msg->messageid = cli_messageid;
return ldap_servers->messageid++;
}
static int send_msg(struct ldap_message *msg)
{
/* This is the scheduling routine that should decide where to send
* stuff. The first attempt is easy: We only have one server. This
* will change once we handle referrals etc. */
SMB_ASSERT(ldap_servers != NULL);
if (!ldap_servers->ready)
return -1;
return send_msg_to_server(msg, ldap_servers);
}
static void fake_bind_response(struct winbind_ldap_client *client,
int messageid)
{
struct ldap_message *msg = new_ldap_message();
if (msg == NULL) {
client->finished = True;
return;
}
msg->messageid = messageid;
msg->type = LDAP_TAG_BindResponse;
msg->r.BindResponse.response.resultcode = 0;
msg->r.BindResponse.response.dn = "";
msg->r.BindResponse.response.dn = "";
msg->r.BindResponse.response.errormessage = "";
msg->r.BindResponse.response.referral = "";
ldap_append_to_buf(msg, &client->out_buffer);
destroy_ldap_message(msg);
}
static int open_ldap_socket(void)
{
static int fd = -1;
if (fd >= 0)
return fd;
fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
return fd;
}
static BOOL do_sigterm = False;
static void ldap_termination_handler(int signum)
{
do_sigterm = True;
sys_select_signal();
}
static BOOL handled_locally(struct ldap_message *msg,
struct winbind_ldap_server *server)
{
struct ldap_Result *r = &msg->r.BindResponse.response;
if (msg->type != LDAP_TAG_BindResponse)
return False;
if (r->resultcode != 0) {
destroy_ldap_message(msg);
server->finished = True;
}
destroy_ldap_message(msg);
server->ready = True;
return True;
}
static void client_has_data(struct winbind_ldap_client *client)
{
struct ldap_message *msg;
if (!read_into_buf(client->sock, &client->in_buffer)) {
client->finished = True;
return;
}
while ((msg = get_msg_from_buf(&client->in_buffer,
&client->finished))) {
struct pending_ldap_message *pending;
if (msg->type == LDAP_TAG_BindRequest) {
fake_bind_response(client, msg->messageid);
destroy_ldap_message(msg);
continue;
}
if (msg->type == LDAP_TAG_UnbindRequest) {
destroy_ldap_message(msg);
client->finished = True;
break;
}
pending = SMB_MALLOC_P(struct pending_ldap_message);
if (pending == NULL)
continue;
pending->msg = msg;
pending->client = client;
pending->our_msgid = send_msg(msg);
if (pending->our_msgid < 0) {
/* could not send */
client->finished = True;
free(pending);
}
DLIST_ADD(pending_messages, pending);
}
}
static struct ldap_Result *ldap_msg2result(struct ldap_message *msg)
{
switch(msg->type) {
case LDAP_TAG_BindResponse:
return &msg->r.BindResponse.response;
case LDAP_TAG_SearchResultDone:
return &msg->r.SearchResultDone;
case LDAP_TAG_ModifyResponse:
return &msg->r.ModifyResponse;
case LDAP_TAG_AddResponse:
return &msg->r.AddResponse;
case LDAP_TAG_DelResponse:
return &msg->r.DelResponse;
case LDAP_TAG_ModifyDNResponse:
return &msg->r.ModifyDNResponse;
case LDAP_TAG_CompareResponse:
return &msg->r.CompareResponse;
case LDAP_TAG_ExtendedResponse:
return &msg->r.ExtendedResponse.response;
}
return NULL;
}
static void server_has_data(struct winbind_ldap_server *server)
{
struct ldap_message *msg;
if (!read_into_buf(server->sock, &server->in_buffer)) {
server->finished = True;
return;
}
while ((msg = get_msg_from_buf(&server->in_buffer,
&server->finished))) {
struct pending_ldap_message *pending;
struct rw_buffer *buf;
struct ldap_Result *res;
if (handled_locally(msg, server))
continue;
res = ldap_msg2result(msg);
if ( (res != NULL) && (res->resultcode == 10) )
DEBUG(5, ("Got Referral %s\n", res->referral));
for (pending = pending_messages;
pending != NULL;
pending = pending->next) {
if (pending->our_msgid == msg->messageid)
break;
}
if (pending == NULL) {
talloc_destroy(msg->mem_ctx);
continue;
}
msg->messageid = pending->msg->messageid;
buf = &pending->client->out_buffer;
ldap_append_to_buf(msg, buf);
if ( (msg->type != LDAP_TAG_SearchResultEntry) &&
(msg->type != LDAP_TAG_SearchResultReference) ) {
destroy_ldap_message(pending->msg);
DLIST_REMOVE(pending_messages,
pending);
SAFE_FREE(pending);
}
destroy_ldap_message(msg);
}
}
static void process_ldap_loop(void)
{
struct winbind_ldap_client *client;
struct winbind_ldap_server *server;
fd_set r_fds, w_fds;
int maxfd, listen_sock, selret;
struct timeval timeout;
/* Free up temporary memory */
lp_talloc_free();
main_loop_talloc_free();
if (do_sigterm) {
#if 0
TALLOC_CTX *mem_ctx = talloc_init("describe");
DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx)));
talloc_destroy(mem_ctx);
#endif
exit(0);
}
/* Initialise fd lists for select() */
listen_sock = open_ldap_socket();
if (listen_sock == -1) {
perror("open_ldap_socket");
exit(1);
}
maxfd = listen_sock;
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
FD_SET(listen_sock, &r_fds);
timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
timeout.tv_usec = 0;
/* Set up client readers and writers */
client = ldap_clients;
while (client != NULL) {
if (client->finished) {
struct winbind_ldap_client *next = client->next;
DLIST_REMOVE(ldap_clients, client);
close(client->sock);
SAFE_FREE(client->in_buffer.data);
SAFE_FREE(client->out_buffer.data);
SAFE_FREE(client);
client = next;
continue;
}
if (client->sock > maxfd)
maxfd = client->sock;
FD_SET(client->sock, &r_fds);
if (client->out_buffer.length > 0)
FD_SET(client->sock, &w_fds);
client = client->next;
}
/* And now the servers */
server = ldap_servers;
while (server != NULL) {
if (server->finished) {
struct winbind_ldap_server *next = server->next;
DLIST_REMOVE(ldap_servers, server);
close(server->sock);
SAFE_FREE(server);
server = next;
continue;
}
if (server->sock > maxfd)
maxfd = server->sock;
FD_SET(server->sock, &r_fds);
if (server->out_buffer.length > 0)
FD_SET(server->sock, &w_fds);
server = server->next;
}
selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
if (selret == 0)
return;
if (selret == -1 && errno != EINTR) {
perror("select");
exit(1);
}
if (FD_ISSET(listen_sock, &r_fds))
new_ldap_client(listen_sock);
for (client = ldap_clients; client != NULL; client = client->next) {
if (FD_ISSET(client->sock, &r_fds))
client_has_data(client);
if ((!client->finished) && FD_ISSET(client->sock, &w_fds))
write_out_of_buf(client->sock, &client->out_buffer);
}
for (server = ldap_servers; server != NULL; server = server->next) {
if (FD_ISSET(server->sock, &r_fds))
server_has_data(server);
if (!server->finished && FD_ISSET(server->sock, &w_fds))
write_out_of_buf(server->sock, &server->out_buffer);
}
}
static BOOL setup_ldap_serverconn(void)
{
char *host;
uint16 port;
BOOL ldaps;
struct hostent *hp;
struct in_addr ip;
TALLOC_CTX *mem_ctx = talloc_init("server");
struct ldap_message *msg;
char *dn, *pw;
ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);
if ((ldap_servers == NULL) || (mem_ctx == NULL))
return False;
if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",
&host, &port, &ldaps))
return False;
hp = sys_gethostbyname(host);
if ((hp == NULL) || (hp->h_addr == NULL))
return False;
putip((char *)&ip, (char *)hp->h_addr);
ZERO_STRUCTP(ldap_servers);
ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);
ldap_servers->messageid = 1;
if (!fetch_ldap_pw(&dn, &pw))
return False;
msg = new_ldap_simple_bind_msg(dn, pw);
SAFE_FREE(dn);
SAFE_FREE(pw);
if (msg == NULL)
return False;
msg->messageid = ldap_servers->messageid++;
ldap_append_to_buf(msg, &ldap_servers->out_buffer);
destroy_ldap_message(msg);
return (ldap_servers->sock >= 0);
}
void do_ldap_proxy(void)
{
int ldap_child;
ldap_child = sys_fork();
if (ldap_child != 0)
return;
/* tdb needs special fork handling */
if (tdb_reopen_all() == -1) {
DEBUG(0,("tdb_reopen_all failed.\n"));
_exit(0);
}
if (!message_init()) {
DEBUG(0, ("message_init failed\n"));
_exit(0);
}
CatchSignal(SIGINT, ldap_termination_handler);
CatchSignal(SIGQUIT, ldap_termination_handler);
CatchSignal(SIGTERM, ldap_termination_handler);
if (!setup_ldap_serverconn())
return;
while (1)
process_ldap_loop();
return;
}

View File

@@ -30,12 +30,21 @@
/* Check the machine account password is valid */
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)
{

View File

@@ -34,7 +34,7 @@
/* Update this when you change the interface. */
#define WINBIND_INTERFACE_VERSION 10
#define WINBIND_INTERFACE_VERSION 11
/* Socket commands */
@@ -83,6 +83,7 @@ enum winbindd_cmd {
WINBINDD_UID_TO_SID,
WINBINDD_GID_TO_SID,
WINBINDD_ALLOCATE_RID,
WINBINDD_ALLOCATE_RID_AND_GID,
/* Miscellaneous other stuff */
@@ -93,6 +94,7 @@ enum winbindd_cmd {
WINBINDD_DOMAIN_INFO, /* Most of what we know from
struct winbindd_domain */
WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
@@ -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 */

View File

@@ -145,24 +145,99 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
return NT_STATUS_LOGON_FAILURE;
}
static struct winbindd_domain *find_auth_domain(const char *domain_name)
{
struct winbindd_domain *domain;
if (IS_DC) {
domain = find_domain_from_name_noinit(domain_name);
if (domain == NULL) {
DEBUG(3, ("Authentication for domain [%s] "
"as it is not a trusted domain\n",
domain_name));
}
return domain;
}
if (is_myname(domain_name)) {
DEBUG(3, ("Authentication for domain %s (local domain "
"to this server) not supported at this "
"stage\n", domain_name));
return NULL;
}
return find_our_domain();
}
static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
{
resp->data.auth.nt_status = NT_STATUS_V(result);
fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
/* we might have given a more useful error above */
if (*resp->data.auth.error_string == '\0')
fstrcpy(resp->data.auth.error_string,
get_friendly_nt_error_msg(result));
resp->data.auth.pam_error = nt_status_to_pam(result);
}
/**********************************************************************
Authenticate a user with a clear text password
**********************************************************************/
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
{
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;
}

View File

@@ -57,7 +57,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
enum SID_NAME_USE type;
uint32 num_names;
DOM_SID **sid_mem;
DOM_SID *sid_mem;
char **names;
uint32 *types;
@@ -126,7 +126,7 @@ add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
for (i=0; i<num_names; i++) {
DEBUG(10, ("Adding group member SID %s\n",
sid_string_static(sid_mem[i])));
sid_string_static(&sid_mem[i])));
if (types[i] != SID_NAME_USER) {
DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
@@ -297,24 +297,29 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
uint32 *num_groups, DOM_SID ***user_gids)
uint32 *num_groups, DOM_SID **user_gids)
{
return NT_STATUS_NO_SUCH_USER;
}
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 num_sids, DOM_SID **sids,
uint32 *num_aliases, uint32 **aliases)
uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **rids)
{
return NT_STATUS_NO_SUCH_USER;
BOOL result;
result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
sids, num_sids, rids, num_aliases);
return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
/* Lookup group membership given a rid. */
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
DOM_SID ***sid_mem, char ***names,
DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
return NT_STATUS_OK;

View File

@@ -0,0 +1,273 @@
/*
Unix SMB/CIFS implementation.
Wrapper around winbindd_rpc.c to centralize retry logic.
Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "winbindd.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
extern struct winbindd_methods msrpc_methods;
/* List all users */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
WINBIND_USERINFO **info)
{
NTSTATUS result;
result = msrpc_methods.query_user_list(domain, mem_ctx,
num_entries, info);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.query_user_list(domain, mem_ctx,
num_entries, info);
return result;
}
/* list all domain groups */
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
struct acct_info **info)
{
NTSTATUS result;
result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
num_entries, info);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.enum_dom_groups(domain, mem_ctx,
num_entries, info);
return result;
}
/* List all domain groups */
static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
struct acct_info **info)
{
NTSTATUS result;
result = msrpc_methods.enum_local_groups(domain, mem_ctx,
num_entries, info);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.enum_local_groups(domain, mem_ctx,
num_entries, info);
return result;
}
/* convert a single name to a sid in a domain */
static NTSTATUS name_to_sid(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const char *domain_name,
const char *name,
DOM_SID *sid,
enum SID_NAME_USE *type)
{
NTSTATUS result;
result = msrpc_methods.name_to_sid(domain, mem_ctx,
domain_name, name,
sid, type);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.name_to_sid(domain, mem_ctx,
domain_name, name,
sid, type);
return result;
}
/*
convert a domain SID to a user or group name
*/
static NTSTATUS sid_to_name(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *sid,
char **domain_name,
char **name,
enum SID_NAME_USE *type)
{
NTSTATUS result;
result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
domain_name, name, type);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.sid_to_name(domain, mem_ctx, sid,
domain_name, name, type);
return result;
}
/* Lookup user information from a rid or username. */
static NTSTATUS query_user(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
WINBIND_USERINFO *user_info)
{
NTSTATUS result;
result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
user_info);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.query_user(domain, mem_ctx, user_sid,
user_info);
return result;
}
/* Lookup groups a user is a member of. I wish Unix had a call like this! */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,
uint32 *num_groups, DOM_SID **user_gids)
{
NTSTATUS result;
result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
user_sid, num_groups,
user_gids);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.lookup_usergroups(domain, mem_ctx,
user_sid, num_groups,
user_gids);
return result;
}
static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 num_sids, const DOM_SID *sids,
uint32 *num_aliases, uint32 **alias_rids)
{
NTSTATUS result;
result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
num_sids, sids,
num_aliases,
alias_rids);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.lookup_useraliases(domain, mem_ctx,
num_sids, sids,
num_aliases,
alias_rids);
return result;
}
/* Lookup group membership given a rid. */
static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *group_sid, uint32 *num_names,
DOM_SID **sid_mem, char ***names,
uint32 **name_types)
{
NTSTATUS result;
result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
group_sid, num_names,
sid_mem, names,
name_types);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.lookup_groupmem(domain, mem_ctx,
group_sid, num_names,
sid_mem, names,
name_types);
return result;
}
/* find the sequence number for a domain */
static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
{
NTSTATUS result;
result = msrpc_methods.sequence_number(domain, seq);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.sequence_number(domain, seq);
return result;
}
/* get a list of trusted domains */
static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_domains,
char ***names,
char ***alt_names,
DOM_SID **dom_sids)
{
NTSTATUS result;
result = msrpc_methods.trusted_domains(domain, mem_ctx,
num_domains, names,
alt_names, dom_sids);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.trusted_domains(domain, mem_ctx,
num_domains, names,
alt_names, dom_sids);
return result;
}
static NTSTATUS alternate_name(struct winbindd_domain *domain)
{
NTSTATUS result;
result = msrpc_methods.alternate_name(domain);
if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
result = msrpc_methods.alternate_name(domain);
return result;
}
/* the rpc backend methods are exposed via this structure */
struct winbindd_methods reconnect_methods = {
False,
query_user_list,
enum_dom_groups,
enum_local_groups,
name_to_sid,
sid_to_name,
query_user,
lookup_usergroups,
lookup_useraliases,
lookup_groupmem,
sequence_number,
trusted_domains,
alternate_name
};

File diff suppressed because it is too large Load Diff

View File

@@ -28,12 +28,13 @@
/* Convert a string */
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;
}

View File

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

View File

@@ -24,9 +24,6 @@
#include "includes.h"
#include "winbindd.h"
extern struct winbindd_methods cache_methods;
extern struct winbindd_methods passdb_methods;
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -65,8 +62,7 @@ struct winbindd_domain *domain_list(void)
/* Initialise list */
if (!_domain_list)
if (!init_domain_list())
return NULL;
init_domain_list();
return _domain_list;
}
@@ -91,12 +87,7 @@ static BOOL is_internal_domain(const DOM_SID *sid)
if (sid == NULL)
return False;
if ( sid_compare_domain( sid, get_global_sam_sid() ) == 0 )
return True;
if ( sid_compare_domain( sid, &global_sid_Builtin ) == 0 )
return True;
return False;
return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
}
@@ -181,80 +172,115 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
rescan our domains looking for new trusted domains
********************************************************************/
struct trustdom_state {
TALLOC_CTX *mem_ctx;
struct winbindd_response *response;
};
static void trustdom_recv(void *private, BOOL success);
static void add_trusted_domains( struct winbindd_domain *domain )
{
TALLOC_CTX *mem_ctx;
NTSTATUS result;
time_t t;
char **names;
char **alt_names;
int num_domains = 0;
DOM_SID *dom_sids, null_sid;
int i;
struct winbindd_domain *new_domain;
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 */
}

View File

@@ -225,6 +225,7 @@ typedef struct
int min_passwd_length;
int oplock_break_wait_time;
int winbind_cache_time;
int winbind_max_idle_children;
int iLockSpinCount;
int iLockSpinTime;
char *szLdapMachineSuffix;
@@ -1223,6 +1224,7 @@ static struct parm_struct parm_table[] = {
{"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED},
{"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED},
{"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED},
{"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED},
{NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
};
@@ -1567,6 +1569,7 @@ static void init_globals(void)
Globals.bWinbindUseDefaultDomain = False;
Globals.bWinbindTrustedDomainsOnly = False;
Globals.bWinbindNestedGroups = False;
Globals.winbind_max_idle_children = 3;
Globals.bEnableRidAlgorithm = True;
@@ -1986,6 +1989,7 @@ FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size);
FN_LOCAL_CHAR(lp_magicchar, magic_char)
FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
FN_GLOBAL_INTEGER(lp_winbind_max_idle_children, &Globals.winbind_max_idle_children)
FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)

View File

@@ -112,6 +112,44 @@ BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAM
return True;
}
BOOL sid_to_local_user_name(const DOM_SID *sid, fstring username)
{
fstring dom_name;
fstring name;
enum SID_NAME_USE type;
if (!sid_check_is_in_our_domain(sid))
return False;
if (!lookup_sid(sid, dom_name, name, &type))
return False;
if (type != SID_NAME_USER)
return False;
fstrcpy(username, name);
return True;
}
BOOL sid_to_local_dom_grp_name(const DOM_SID *sid, fstring groupname)
{
fstring dom_name;
fstring name;
enum SID_NAME_USE type;
if (!sid_check_is_in_our_domain(sid))
return False;
if (!lookup_sid(sid, dom_name, name, &type))
return False;
if (type != SID_NAME_DOM_GRP)
return False;
fstrcpy(groupname, name);
return True;
}
/*****************************************************************
Id mapping cache. This is to avoid Winbind mappings already
@@ -250,8 +288,8 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
if (sid_compare(&pc->sid, psid) == 0) {
fstring sid;
*pgid = pc->gid;
DEBUG(3,("fetch uid from cache %u -> %s\n",
(unsigned int)*pgid, sid_to_string(sid, psid)));
DEBUG(3,("fetch gid from cache %u -> %s\n",
(unsigned int)*pgid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc);
return True;
}

View File

@@ -906,7 +906,7 @@ static int printing_value_info( char *key, REGVAL_CTR *val )
static BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
{
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;
}
/*

View File

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

View File

@@ -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*/

View File

@@ -75,6 +75,55 @@ NTSTATUS cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
return result;
}
NTSTATUS rpccli_net_req_chal(struct rpc_pipe_client *cli,
const char *server_name,
const char *computer_name,
DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
{
prs_struct qbuf, rbuf;
NET_Q_REQ_CHAL q;
NET_R_REQ_CHAL r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->cli->mem_ctx, MARSHALL);
prs_init(&rbuf, 0, cli->cli->mem_ctx, UNMARSHALL);
/* create and send a MSRPC command with api NET_REQCHAL */
DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s\n",
computer_name, server_name));
/* store the parameters */
init_q_req_chal(&q, server_name, computer_name, clnt_chal);
/* Marshall data and send request */
if (!net_io_q_req_chal("", &q, &qbuf, 0) ||
!rpc_api_pipe_req_int(cli, NET_REQCHAL, &qbuf, &rbuf)) {
goto done;
}
/* Unmarhall response */
if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
goto done;
}
result = r.status;
/* Return result */
if (NT_STATUS_IS_OK(result)) {
memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
}
done:
prs_mem_free(&qbuf);
prs_mem_free(&rbuf);
return result;
}
/****************************************************************************
LSA Authenticate 2
@@ -158,6 +207,61 @@ password ?).\n", cli->desthost ));
return result;
}
NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
const char *server_name,
const char *account_name,
uint16 sec_chan_type,
const char *computer_name,
const DOM_CHAL *credentials,
uint32 *neg_flags,
DOM_CHAL *srv_chal)
{
prs_struct qbuf, rbuf;
NET_Q_AUTH_2 q;
NET_R_AUTH_2 r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
/* create and send a MSRPC command with api NET_AUTH2 */
DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s neg: %x\n",
server_name, account_name, sec_chan_type, computer_name,
*neg_flags));
/* store the parameters */
init_q_auth_2(&q, server_name, account_name, sec_chan_type,
computer_name, credentials, *neg_flags);
/* turn parameters into data stream */
if (!net_io_q_auth_2("", &q, &qbuf, 0) ||
!rpc_api_pipe_req_int(cli, NET_AUTH2, &qbuf, &rbuf)) {
goto done;
}
/* Unmarshall response */
if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
goto done;
}
result = r.status;
if (NT_STATUS_IS_OK(result)) {
*srv_chal = r.srv_chal;
*neg_flags = r.srv_flgs.neg_flags;
}
done:
prs_mem_free(&qbuf);
prs_mem_free(&rbuf);
return result;
}
/****************************************************************************
LSA Authenticate 3
@@ -340,8 +444,9 @@ NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* GetDCName */
NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
const char *domainname, fstring dcname)
NTSTATUS rpccli_netlogon_getdcname(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx, const char *mydcname,
const char *domainname, fstring newdcname)
{
prs_struct qbuf, rbuf;
NET_Q_GETDCNAME q;
@@ -358,12 +463,12 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Initialise input parameters */
init_net_q_getdcname(&q, cli->srv_name_slash, domainname);
init_net_q_getdcname(&q, mydcname, domainname);
/* Marshall data and send request */
if (!net_io_q_getdcname("", &q, &qbuf, 0) ||
!rpc_api_pipe_req(cli, PI_NETLOGON, NET_GETDCNAME, &qbuf, &rbuf)) {
!rpc_api_pipe_req_int(cli, NET_GETDCNAME, &qbuf, &rbuf)) {
result = NT_STATUS_UNSUCCESSFUL;
goto done;
}
@@ -378,7 +483,7 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
result = r.status;
if (NT_STATUS_IS_OK(result))
rpcstr_pull_unistr2_fstring(dcname, &r.uni_dcname);
rpcstr_pull_unistr2_fstring(newdcname, &r.uni_dcname);
done:
prs_mem_free(&qbuf);
@@ -387,6 +492,14 @@ NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return result;
}
NTSTATUS cli_netlogon_getdcname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
const char *domainname, fstring dcname)
{
return rpccli_netlogon_getdcname(&cli->pipes[PI_NETLOGON], mem_ctx,
cli->srv_name_slash, domainname,
dcname);
}
/****************************************************************************
Generate the next creds to use.
****************************************************************************/
@@ -636,19 +749,25 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
* @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
**/
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
DOM_CRED *ret_creds,
const char *username, const char *domain, const char *workstation,
const uint8 chal[8],
DATA_BLOB lm_response, DATA_BLOB nt_response,
NET_USER_INFO_3 *info3)
NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx,
const char *server_name_slash,
DOM_CRED *clnt_creds,
DOM_CRED *ret_creds,
const char *username,
const char *domain,
const char *workstation,
const uint8 chal[8],
DATA_BLOB lm_response,
DATA_BLOB nt_response,
NET_USER_INFO_3 *info3,
const uint8 *session_key)
{
prs_struct qbuf, rbuf;
NET_Q_SAM_LOGON q;
NET_R_SAM_LOGON r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
DOM_CRED clnt_creds, dummy_rtn_creds;
DOM_CRED dummy_rtn_creds;
NET_ID_INFO_CTR ctr;
int validation_level = 3;
char *workstation_name_slash;
@@ -661,7 +780,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
ZERO_STRUCT(dummy_rtn_creds);
workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
if (!workstation_name_slash) {
DEBUG(0, ("talloc_asprintf failed!\n"));
return NT_STATUS_NO_MEMORY;
@@ -674,8 +792,6 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
/* Initialise input parameters */
gen_next_creds(cli, &clnt_creds);
q.validation_level = validation_level;
if (ret_creds == NULL)
@@ -689,14 +805,14 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
username, workstation_name_slash, (const uchar*)chal,
lm_response.data, lm_response.length, nt_response.data, nt_response.length);
init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(),
&clnt_creds, ret_creds, NET_LOGON_TYPE,
init_sam_info(&q.sam_id, server_name_slash, global_myname(),
clnt_creds, ret_creds, NET_LOGON_TYPE,
&ctr);
/* Marshall data and send request */
if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
!rpc_api_pipe_req(cli, PI_NETLOGON, NET_SAMLOGON, &qbuf, &rbuf)) {
!rpc_api_pipe_req_int(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
goto done;
}
@@ -709,7 +825,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
}
ZERO_STRUCT(netlogon_sess_key);
memcpy(netlogon_sess_key, cli->sess_key, 8);
memcpy(netlogon_sess_key, session_key, 8);
if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16);
@@ -740,6 +856,30 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
return result;
}
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli,
TALLOC_CTX *mem_ctx,
DOM_CRED *ret_creds,
const char *username,
const char *domain,
const char *workstation,
const uint8 chal[8],
DATA_BLOB lm_response,
DATA_BLOB nt_response,
NET_USER_INFO_3 *info3)
{
DOM_CRED clnt_creds;
gen_next_creds(cli, &clnt_creds);
return rpccli_netlogon_sam_network_logon(&cli->pipes[PI_NETLOGON],
mem_ctx, cli->srv_name_slash,
&clnt_creds,
ret_creds, username,
domain, workstation, chal,
lm_response, nt_response,
info3, cli->sess_key);
}
/***************************************************************************
LSA Server Password Set.
****************************************************************************/

View File

@@ -62,7 +62,8 @@ static uint32 get_rpc_call_id(void)
Use SMBreadX to get rest of one fragment's worth of rpc data.
********************************************************************/
static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
static BOOL rpc_read(struct rpc_pipe_client *cli, prs_struct *rdata,
uint32 data_to_read, uint32 *rdata_offset)
{
size_t size = (size_t)cli->max_recv_frag;
int stream_offset = 0;
@@ -95,13 +96,14 @@ static BOOL rpc_read(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uin
if (size > (size_t)data_to_read)
size = (size_t)data_to_read;
num_read = (int)cli_read(cli, cli->nt_pipe_fnum[pipe_idx], pdata, (off_t)stream_offset, size);
num_read = (int)cli_read(cli->cli, cli->fnum, pdata,
(off_t)stream_offset, size);
DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
num_read, stream_offset, data_to_read));
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
if (cli_is_dos_error(cli->cli)) {
cli_dos_error(cli->cli, &eclass, &ecode);
if (eclass != ERRDOS && ecode != ERRmoredata) {
DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
eclass, (unsigned int)ecode));
@@ -168,7 +170,7 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
Never on bind requests/responses.
****************************************************************************/
static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
static BOOL rpc_auth_pipe(struct rpc_pipe_client *cli, prs_struct *rdata,
uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
int *pauth_padding_len)
{
@@ -219,7 +221,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
DEBUG(10,("rpc_auth_pipe: packet:\n"));
dump_data(100, dp, auth_len);
prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
prs_init(&auth_verf, 0, cli->cli->mem_ctx, UNMARSHALL);
/* The endinness must be preserved. JRA. */
prs_set_endian_data( &auth_verf, rdata->bigendian_data);
@@ -394,7 +396,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
****************************************************************************/
static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data, prs_struct *rdata,
static BOOL rpc_api_pipe(struct rpc_pipe_client *cli, prs_struct *data, prs_struct *rdata,
uint8 expected_pkt_type)
{
uint32 len;
@@ -416,23 +418,24 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
/* Create setup parameters - must be in native byte order. */
setup[0] = TRANSACT_DCERPCCMD;
setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* Pipe file handle. */
setup[1] = cli->fnum; /* Pipe file handle. */
DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum[pipe_idx]));
DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->fnum));
/* Send the RPC request and receive a response. For short RPC
calls (about 1024 bytes or so) the RPC request and response
appears in a SMBtrans request and response. Larger RPC
responses are received further on. */
if (!cli_api_pipe(cli, "\\PIPE\\",
if (!cli_api_pipe(cli->cli, "\\PIPE\\",
setup, 2, 0, /* Setup, length, max */
NULL, 0, 0, /* Params, length, max */
pdata, data_len, max_data, /* data, length, max */
&rparam, &rparam_len, /* return params, len */
&prdata, &rdata_len)) /* return data, len */
{
DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
DEBUG(0, ("cli_pipe: return critical error. Error was %s\n",
cli_errstr(cli->cli)));
return False;
}
@@ -442,7 +445,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
if (prdata == NULL) {
DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
(int)cli->nt_pipe_fnum[pipe_idx]));
(int)cli->fnum));
return False;
}
@@ -470,7 +473,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
}
if (rhdr.pkt_type == RPC_BINDNACK) {
DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum[pipe_idx]));
DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->fnum));
prs_mem_free(rdata);
return False;
}
@@ -485,7 +488,9 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
}
if (rhdr.pkt_type != expected_pkt_type) {
DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum[pipe_idx], rhdr.pkt_type, expected_pkt_type));
DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet "
"type - %d, not %d\n", (int)cli->fnum,
rhdr.pkt_type, expected_pkt_type));
prs_mem_free(rdata);
return False;
}
@@ -502,7 +507,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
/* Read the remaining part of the first response fragment */
if (!rpc_read(cli, pipe_idx, rdata, len, &current_offset)) {
if (!rpc_read(cli, rdata, len, &current_offset)) {
prs_mem_free(rdata);
return False;
}
@@ -554,12 +559,13 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
* First read the header of the next PDU.
*/
prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
prs_init(&hps, 0, cli->cli->mem_ctx, UNMARSHALL);
prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
num_read = cli_read(cli, cli->nt_pipe_fnum[pipe_idx], hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
num_read = cli_read(cli->cli, cli->fnum, hdr_data, 0,
RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
if (cli_is_dos_error(cli->cli)) {
cli_dos_error(cli->cli, &eclass, &ecode);
if (eclass != ERRDOS && ecode != ERRmoredata) {
DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
return False;
@@ -602,7 +608,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
* Now read the rest of the PDU.
*/
if (!rpc_read(cli, pipe_idx, rdata, len, &current_offset)) {
if (!rpc_read(cli, rdata, len, &current_offset)) {
prs_mem_free(rdata);
return False;
}
@@ -644,7 +650,8 @@ static BOOL rpc_api_pipe(struct cli_state *cli, int pipe_idx, prs_struct *data,
********************************************************************/
static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
prs_struct *rpc_out,
uint32 rpc_call_id,
RPC_IFACE *abstract, RPC_IFACE *transfer,
const char *my_name, const char *domain)
@@ -783,7 +790,7 @@ static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
the authentication handshake.
********************************************************************/
static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
static NTSTATUS create_rpc_bind_resp(struct rpc_pipe_client *cli,
uint32 rpc_call_id,
prs_struct *rpc_out)
{
@@ -916,8 +923,8 @@ static BOOL create_auth_hdr(prs_struct *outgoing_packet,
* @param rdata Unparsed NDR response data.
**/
BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
prs_struct *data, prs_struct *rdata)
BOOL rpc_api_pipe_req_int(struct rpc_pipe_client *cli, uint8 op_num,
prs_struct *data, prs_struct *rdata)
{
uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
NTSTATUS nt_status;
@@ -959,7 +966,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
send_size = MIN(data_left, max_data);
if (!prs_init(&sec_blob, send_size, /* will need at least this much */
cli->mem_ctx, MARSHALL)) {
cli->cli->mem_ctx, MARSHALL)) {
DEBUG(0,("Could not malloc %u bytes",
send_size+auth_padding));
return False;
@@ -1066,7 +1073,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
* Malloc parse struct to hold it (and enough for alignments).
*/
if(!prs_init(&outgoing_packet, data_len + 8,
cli->mem_ctx, MARSHALL)) {
cli->cli->mem_ctx, MARSHALL)) {
DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
return False;
}
@@ -1095,10 +1102,10 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
prs_offset(&outgoing_packet)));
if (flags & RPC_FLG_LAST)
ret = rpc_api_pipe(cli, pipe_idx, &outgoing_packet,
ret = rpc_api_pipe(cli, &outgoing_packet,
rdata, RPC_RESPONSE);
else {
cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x0008,
cli_write(cli->cli, cli->fnum, 0x0008,
prs_data_p(&outgoing_packet),
data_sent, data_len);
}
@@ -1108,17 +1115,26 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
}
/* Also capture received data */
slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s",
cli_pipe_get_name(cli));
cli_pipe_get_name(cli->cli));
prs_dump(dump_name, op_num, rdata);
return ret;
}
BOOL rpc_api_pipe_req(struct cli_state *cli, int pipe_idx, uint8 op_num,
prs_struct *data, prs_struct *rdata)
{
return rpc_api_pipe_req_int(&cli->pipes[pipe_idx], op_num,
data, rdata);
}
/****************************************************************************
Set the handle state.
****************************************************************************/
static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const char *pipe_name, uint16 device_state)
static BOOL rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
const char *pipe_name, uint16 device_state)
{
BOOL state_set = False;
char param[2];
@@ -1131,17 +1147,17 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, int pipe_idx, const ch
return False;
DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
cli->nt_pipe_fnum[pipe_idx], pipe_name, device_state));
cli->fnum, pipe_name, device_state));
/* create parameters: device state */
SSVAL(param, 0, device_state);
/* create setup parameters. */
setup[0] = 0x0001;
setup[1] = cli->nt_pipe_fnum[pipe_idx]; /* pipe file handle. got this from an SMBOpenX. */
setup[1] = cli->fnum; /* pipe file handle. got this from an SMBOpenX. */
/* send the data on \PIPE\ */
if (cli_api_pipe(cli, "\\PIPE\\",
if (cli_api_pipe(cli->cli, "\\PIPE\\",
setup, 2, 0, /* setup, length, max */
param, 2, 0, /* param, length, max */
NULL, 0, 1024, /* data, length, max */
@@ -1281,20 +1297,21 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFAC
Create and send the third packet in an RPC auth.
****************************************************************************/
static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct *rdata, uint32 rpc_call_id)
static BOOL rpc_send_auth_reply(struct rpc_pipe_client *cli,
prs_struct *rdata, uint32 rpc_call_id)
{
prs_struct rpc_out;
ssize_t ret;
prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */
cli->mem_ctx, MARSHALL);
cli->cli->mem_ctx, MARSHALL);
if (!NT_STATUS_IS_OK(create_rpc_bind_resp(cli, rpc_call_id,
&rpc_out))) {
return False;
}
if ((ret = cli_write(cli, cli->nt_pipe_fnum[pipe_idx], 0x8, prs_data_p(&rpc_out),
if ((ret = cli_write(cli->cli, cli->fnum, 0x8, prs_data_p(&rpc_out),
0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
prs_mem_free(&rpc_out);
@@ -1309,7 +1326,7 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, int pipe_idx, prs_struct
Do an rpc bind.
****************************************************************************/
static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name)
static BOOL rpc_pipe_bind(struct rpc_pipe_client *cli)
{
RPC_IFACE abstract;
RPC_IFACE transfer;
@@ -1318,15 +1335,16 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
uint32 rpc_call_id;
char buffer[MAX_PDU_FRAG_LEN];
if ( (pipe_idx < 0) || (pipe_idx >= PI_MAX_PIPES) )
if ( (cli->pipe_idx < 0) || (cli->pipe_idx >= PI_MAX_PIPES) )
return False;
DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum[pipe_idx], pipe_names[pipe_idx].client_pipe));
DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->fnum,
pipe_names[cli->pipe_idx].client_pipe));
if (!valid_pipe_name(pipe_idx, &abstract, &transfer))
if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer))
return False;
prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
prs_init(&rpc_out, 0, cli->cli->mem_ctx, MARSHALL);
/*
* Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
@@ -1391,10 +1409,10 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
global_myname(), cli->domain);
/* Initialize the incoming data struct. */
prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
prs_init(&rdata, 0, cli->cli->mem_ctx, UNMARSHALL);
/* send data on \PIPE\. receive a response */
if (rpc_api_pipe(cli, pipe_idx, &rpc_out, &rdata, RPC_BINDACK)) {
if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) {
RPC_HDR_BA hdr_ba;
DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
@@ -1405,7 +1423,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
return False;
}
if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) {
if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) {
DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
prs_mem_free(&rdata);
return False;
@@ -1421,7 +1439,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
*/
if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP)
&& !rpc_send_auth_reply(cli, pipe_idx, &rdata, rpc_call_id)) {
&& !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
prs_mem_free(&rdata);
return False;
@@ -1440,11 +1458,9 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
{
int fnum;
struct rpc_pipe_client *cli_pipe;
/* At the moment we can't have more than one pipe open over
a cli connection. )-: */
SMB_ASSERT(cli->nt_pipe_fnum[pipe_idx] == 0);
SMB_ASSERT(cli->pipes[pipe_idx].fnum == 0);
/* The pipe index must fall within our array */
@@ -1457,7 +1473,7 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
return False;
}
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
cli->pipes[pipe_idx].fnum = (uint16)fnum;
} else {
if ((fnum = cli_open(cli, pipe_names[pipe_idx].client_pipe, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
DEBUG(1,("cli_nt_session_open: cli_open failed on pipe %s to machine %s. Error was %s\n",
@@ -1465,25 +1481,32 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
return False;
}
cli->nt_pipe_fnum[pipe_idx] = (uint16)fnum;
cli->pipes[pipe_idx].fnum = (uint16)fnum;
/**************** Set Named Pipe State ***************/
if (!rpc_pipe_set_hnd_state(cli, pipe_idx, pipe_names[pipe_idx].client_pipe, 0x4300)) {
if (!rpc_pipe_set_hnd_state(&cli->pipes[pipe_idx], pipe_names[pipe_idx].client_pipe, 0x4300)) {
DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
cli_errstr(cli)));
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
cli->nt_pipe_fnum[pipe_idx] = 0;
cli_close(cli, cli->pipes[pipe_idx].fnum);
cli->pipes[pipe_idx].fnum = 0;
return False;
}
}
cli_pipe = &cli->pipes[pipe_idx];
cli_pipe->pipe_idx = pipe_idx;
cli_pipe->cli = cli;
cli_pipe->pipe_auth_flags = cli->pipe_auth_flags;
memcpy(&cli_pipe->auth_info.sess_key,
cli->sess_key, sizeof(cli->sess_key));
/******************* bind request on pipe *****************/
if (!rpc_pipe_bind(cli, pipe_idx, global_myname())) {
if (!rpc_pipe_bind(&cli->pipes[pipe_idx])) {
DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
get_pipe_name_from_index(pipe_idx)));
cli_close(cli, cli->nt_pipe_fnum[pipe_idx]);
cli->nt_pipe_fnum[pipe_idx] = 0;
cli_close(cli, cli->pipes[pipe_idx].fnum);
cli->pipes[pipe_idx].fnum = 0;
return False;
}
@@ -1523,7 +1546,6 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
{
NTSTATUS result;
uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
int fnum;
cli_nt_netlogon_netsec_session_close(cli);
@@ -1554,60 +1576,20 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
}
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);
}

View File

@@ -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,

View File

@@ -1240,6 +1240,32 @@ BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_
return True;
}
BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth,
const char **str)
{
size_t len;
char *tmp_str;
if (UNMARSHALLING(ps))
len = strlen(&ps->data_p[ps->data_offset]);
else
len = strlen(*str);
tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
if (tmp_str == NULL)
return False;
if (MARSHALLING(ps))
strncpy(tmp_str, *str, len);
if (!prs_string(name, ps, depth, tmp_str, len+1))
return False;
*str = tmp_str;
return True;
}
/*******************************************************************
prs_uint16 wrapper. Call this and it sets up a pointer to where the
uint16 should be stored, or gets the size if reading.

View File

@@ -315,7 +315,7 @@ static NTSTATUS cmd_sign(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* still have session, just need to use it again */
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;
}

View File

@@ -153,11 +153,16 @@ BOOL idmap_init(const char **remote_backend)
Don't do id mapping. This is used to make winbind a netlogon proxy only.
**************************************************************************/
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 */

View File

@@ -71,7 +71,8 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
else
fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
pstr_sprintf(id_str, "%d", ((id_type & ID_USERID) ? id.uid : id.gid));
pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid));
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
@@ -500,9 +501,9 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
pstrcpy( suffix, lp_ldap_idmap_suffix() );
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))",
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
LDAP_OBJ_IDMAP_ENTRY, type,
((id_type & ID_USERID) ? id.uid : id.gid));
((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
attr_list = get_attr_list( sidmap_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
@@ -700,8 +701,8 @@ static NTSTATUS verify_idpool( void )
return NT_STATUS_UNSUCCESSFUL;
}
fstr_sprintf( uid_str, "%d", luid );
fstr_sprintf( gid_str, "%d", lgid );
fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
smbldap_set_mod( &mods, LDAP_MOD_ADD,

View File

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

View File

@@ -288,7 +288,7 @@ enum client_action
{
int i;
for (i=0; i<PI_MAX_PIPES; i++)
smb_cli->nt_pipe_fnum[i] = 0xffff;
smb_cli->pipes[i].fnum = 0xffff;
}
setup_logging(pname, True);

View File

@@ -141,7 +141,7 @@ int run_rpc_command(struct cli_state *cli_arg, const int pipe_idx, int conn_flag
}
if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
if (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);

View File

@@ -77,7 +77,7 @@ static int net_rpc_join_ok(const char *domain)
done:
/* Close down pipe - this will clean up open policy handles */
if (cli->nt_pipe_fnum[cli->pipe_idx])
if (cli->pipes[cli->pipe_idx].fnum)
cli_nt_session_close(cli);
cli_shutdown(cli);
@@ -346,7 +346,7 @@ int net_rpc_join_newstyle(int argc, const char **argv)
done:
/* Close down pipe - this will clean up open policy handles */
if (cli->nt_pipe_fnum[cli->pipe_idx])
if (cli->pipes[cli->pipe_idx].fnum)
cli_nt_session_close(cli);
/* Display success or failure */

View File

@@ -428,8 +428,7 @@ static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
return False;
}
notify_printer_byname(argv[2], attribute,
CONST_DISCARD(char *, argv[4]));
notify_printer_byname(argv[2], attribute, argv[4]);
goto send;
}
@@ -573,6 +572,53 @@ static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
}
static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
{
fstring unix_name;
memset( (char *)n, '\0', sizeof(struct nmb_name) );
fstrcpy(unix_name, name);
strupper_m(unix_name);
push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
n->name_type = (unsigned int)type & 0xFF;
push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
}
static BOOL do_nodestatus(const pid_t pid, const int argc,
const char **argv)
{
struct packet_struct p;
if (argc != 2) {
fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
return False;
}
ZERO_STRUCT(p);
p.ip = *interpret_addr2(argv[1]);
p.port = 137;
p.packet_type = NMB_PACKET;
p.packet.nmb.header.name_trn_id = 10;
p.packet.nmb.header.opcode = 0;
p.packet.nmb.header.response = False;
p.packet.nmb.header.nm_flags.bcast = False;
p.packet.nmb.header.nm_flags.recursion_available = False;
p.packet.nmb.header.nm_flags.recursion_desired = False;
p.packet.nmb.header.nm_flags.trunc = False;
p.packet.nmb.header.nm_flags.authoritative = False;
p.packet.nmb.header.rcode = 0;
p.packet.nmb.header.qdcount = 1;
p.packet.nmb.header.ancount = 0;
p.packet.nmb.header.nscount = 0;
p.packet.nmb.header.arcount = 0;
my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
p.packet.nmb.question.question_type = 0x21;
p.packet.nmb.question.question_class = 0x1;
return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
}
/* A list of message type supported */
static const struct {
@@ -597,6 +643,7 @@ static const struct {
{ "shutdown", do_shutdown, "Shut down daemon" },
{ "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
{ "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
{ "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
{ "noop", do_noop, "Do nothing" },
{ NULL }
};